or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-caching.mddisk-serialization.mddjango-integration.mdfanout-cache.mdindex.mdpersistent-data-structures.mdrecipe-functions.mdsynchronization-primitives.md

fanout-cache.mddocs/

0

# Sharded Caching

1

2

FanoutCache provides high-throughput caching by automatically distributing keys across multiple Cache instances (shards). This sharding approach improves performance for applications with high concurrency by reducing lock contention and enabling parallel operations across different shards.

3

4

## Capabilities

5

6

### FanoutCache Initialization

7

8

Create a FanoutCache instance with configurable shard count and settings.

9

10

```python { .api }

11

class FanoutCache:

12

def __init__(self, directory=None, shards=8, timeout=0.010, disk=Disk, **settings):

13

"""

14

Initialize sharded cache instance.

15

16

Args:

17

directory (str, optional): Cache directory path. If None, creates temp directory.

18

shards (int): Number of shards to distribute writes across. Default 8.

19

timeout (float): SQLite connection timeout in seconds. Default 0.010.

20

disk (Disk): Disk instance for serialization. Default Disk.

21

**settings: Cache configuration options from DEFAULT_SETTINGS.

22

size_limit is automatically divided by shard count.

23

"""

24

25

@property

26

def directory(self):

27

"""Cache directory path."""

28

```

29

30

### Cache Operations

31

32

All standard cache operations with automatic key distribution across shards.

33

34

```python { .api }

35

def set(self, key, value, expire=None, read=False, tag=None, retry=False):

36

"""

37

Store key-value pair in appropriate shard.

38

39

Args:

40

key: Cache key (must be hashable)

41

value: Value to store

42

expire (float, optional): Expiration time in seconds from now

43

read (bool): Store value as file for reading. Default False.

44

tag (str, optional): Tag for grouping related items

45

retry (bool): Retry operation on timeout. Default False.

46

47

Returns:

48

bool: True if set succeeded

49

"""

50

51

def get(self, key, default=None, read=False, expire_time=False, tag=False, retry=False):

52

"""

53

Retrieve value by key from appropriate shard.

54

55

Args:

56

key: Cache key

57

default: Default value if key not found

58

read (bool): Return file handle instead of value. Default False.

59

expire_time (bool): Include expiration time in result. Default False.

60

tag (bool): Include tag in result. Default False.

61

retry (bool): Retry operation on timeout. Default False.

62

63

Returns:

64

Value, or tuple with additional info if expire_time/tag requested

65

"""

66

67

def delete(self, key, retry=False):

68

"""

69

Delete key from appropriate shard.

70

71

Args:

72

key: Cache key to delete

73

retry (bool): Retry operation on timeout. Default False.

74

75

Returns:

76

bool: True if key existed and was deleted

77

"""

78

79

def add(self, key, value, expire=None, read=False, tag=None, retry=False):

80

"""

81

Add key-value pair only if key doesn't exist in any shard.

82

83

Args:

84

key: Cache key

85

value: Value to store

86

expire (float, optional): Expiration time in seconds from now

87

read (bool): Store value as file for reading. Default False.

88

tag (str, optional): Tag for grouping related items

89

retry (bool): Retry operation on timeout. Default False.

90

91

Returns:

92

bool: True if key was added (didn't exist)

93

"""

94

95

def touch(self, key, expire=None, retry=False):

96

"""

97

Update expiration time for existing key in appropriate shard.

98

99

Args:

100

key: Cache key

101

expire (float, optional): New expiration time in seconds from now

102

retry (bool): Retry operation on timeout. Default False.

103

104

Returns:

105

bool: True if key existed and was touched

106

"""

107

108

def pop(self, key, default=None, expire_time=False, tag=False, retry=False):

109

"""

110

Remove and return value for key from appropriate shard.

111

112

Args:

113

key: Cache key

114

default: Default value if key not found

115

expire_time (bool): Include expiration time in result. Default False.

116

tag (bool): Include tag in result. Default False.

117

retry (bool): Retry operation on timeout. Default False.

118

119

Returns:

120

Value, or tuple with additional info if expire_time/tag requested

121

"""

122

123

def read(self, key):

124

"""

125

Get file handle for key stored in read mode from appropriate shard.

126

127

Args:

128

key: Cache key

129

130

Returns:

131

File handle or None if key not found

132

"""

133

134

def incr(self, key, delta=1, default=0, retry=False):

135

"""

136

Atomically increment numeric value in appropriate shard.

137

138

Args:

139

key: Cache key

140

delta (int): Amount to increment. Default 1.

141

default (int): Default value if key doesn't exist. Default 0.

142

retry (bool): Retry operation on timeout. Default False.

143

144

Returns:

145

New value after increment

146

"""

147

148

def decr(self, key, delta=1, default=0, retry=False):

149

"""

150

Atomically decrement numeric value in appropriate shard.

151

152

Args:

153

key: Cache key

154

delta (int): Amount to decrement. Default 1.

155

default (int): Default value if key doesn't exist. Default 0.

156

retry (bool): Retry operation on timeout. Default False.

157

158

Returns:

159

New value after decrement

160

"""

161

```

162

163

### Dict-like Interface

164

165

Familiar dictionary operations with sharding handled transparently.

166

167

```python { .api }

168

def __setitem__(self, key, value):

169

"""Store key-value pair using fanout_cache[key] = value syntax."""

170

171

def __getitem__(self, key):

172

"""Retrieve value using fanout_cache[key] syntax. Raises KeyError if not found."""

173

174

def __delitem__(self, key):

175

"""Delete key using del fanout_cache[key] syntax."""

176

177

def __contains__(self, key):

178

"""Check if key exists using 'key in fanout_cache' syntax."""

179

180

def __len__(self):

181

"""Get total count of items across all shards."""

182

183

def __iter__(self):

184

"""Iterate over all cache keys across all shards."""

185

186

def __reversed__(self):

187

"""Reverse iterate over all cache keys across all shards."""

188

```

189

190

### Cache Management

191

192

Management operations that work across all shards.

193

194

```python { .api }

195

def clear(self, retry=False):

196

"""

197

Remove all items from all shards.

198

199

Args:

200

retry (bool): Retry operation on timeout. Default False.

201

202

Returns:

203

int: Total number of items removed across all shards

204

"""

205

206

def cull(self, retry=False):

207

"""

208

Remove items according to eviction policy from all shards.

209

210

Args:

211

retry (bool): Retry operation on timeout. Default False.

212

213

Returns:

214

int: Total number of items removed across all shards

215

"""

216

217

def expire(self, retry=False):

218

"""

219

Remove expired items from all shards.

220

221

Args:

222

retry (bool): Retry operation on timeout. Default False.

223

224

Returns:

225

int: Total number of expired items removed across all shards

226

"""

227

228

def evict(self, tag, retry=False):

229

"""

230

Remove all items with specified tag from all shards.

231

232

Args:

233

tag (str): Tag to evict

234

retry (bool): Retry operation on timeout. Default False.

235

236

Returns:

237

int: Total number of items evicted across all shards

238

"""

239

240

def check(self, fix=False, retry=False):

241

"""

242

Check database consistency across all shards.

243

244

Args:

245

fix (bool): Attempt to fix issues if found. Default False.

246

retry (bool): Retry operation on timeout. Default False.

247

248

Returns:

249

List of issues found across all shards

250

"""

251

252

def create_tag_index(self):

253

"""Create database index on tag column for all shards."""

254

255

def drop_tag_index(self):

256

"""Drop database index on tag column for all shards."""

257

```

258

259

### Statistics and Monitoring

260

261

Access aggregated statistics and information across all shards.

262

263

```python { .api }

264

def stats(self, enable=True, reset=False):

265

"""

266

Get aggregated cache hit/miss statistics across all shards.

267

268

Args:

269

enable (bool): Enable statistics tracking on all shards. Default True.

270

reset (bool): Reset statistics counters on all shards. Default False.

271

272

Returns:

273

Tuple of (total_hits, total_misses) across all shards

274

"""

275

276

def volume(self):

277

"""

278

Get total cache size on disk across all shards.

279

280

Returns:

281

int: Total size in bytes across all shards

282

"""

283

```

284

285

### Transaction Management

286

287

Context management and connection handling across shards.

288

289

```python { .api }

290

def transact(self, retry=True):

291

"""

292

Context manager for atomic transactions across relevant shards.

293

294

Args:

295

retry (bool): Retry transaction on timeout. Default True.

296

297

Returns:

298

Context manager for transaction

299

"""

300

301

def __enter__(self):

302

"""Context manager entry - prepare for operations."""

303

304

def __exit__(self, *exception):

305

"""Context manager exit - cleanup resources."""

306

307

def close(self):

308

"""Close database connections and cleanup resources for all shards."""

309

```

310

311

### Sub-collection Access

312

313

Create sub-collections (Cache, Deque, Index) within the FanoutCache directory structure.

314

315

```python { .api }

316

def cache(self, name, timeout=60, disk=None, **settings):

317

"""

318

Return Cache instance in subdirectory.

319

320

Args:

321

name (str): Subdirectory name for Cache

322

timeout (float): SQLite connection timeout. Default 60.

323

disk (Disk, optional): Disk instance. Default uses FanoutCache's disk.

324

**settings: Cache configuration options

325

326

Returns:

327

Cache: Cache instance in subdirectory

328

"""

329

330

def deque(self, name, maxlen=None):

331

"""

332

Return Deque instance in subdirectory.

333

334

Args:

335

name (str): Subdirectory name for Deque

336

maxlen (int, optional): Maximum length of deque

337

338

Returns:

339

Deque: Deque instance in subdirectory

340

"""

341

342

def index(self, name):

343

"""

344

Return Index instance in subdirectory.

345

346

Args:

347

name (str): Subdirectory name for Index

348

349

Returns:

350

Index: Index instance in subdirectory

351

"""

352

```

353

354

### Advanced Operations

355

356

Settings management and serialization support for FanoutCache.

357

358

```python { .api }

359

def reset(self, key, value=ENOVAL):

360

"""

361

Reset cache setting value across all shards.

362

363

Args:

364

key (str): Setting key from DEFAULT_SETTINGS

365

value: New value for setting

366

367

Returns:

368

Previous value of setting from first shard

369

"""

370

371

def __getstate__(self):

372

"""Support for pickle serialization - returns FanoutCache state."""

373

374

def __setstate__(self, state):

375

"""Support for pickle deserialization - restores FanoutCache state."""

376

```

377

378

### Dynamic Settings Access

379

380

Access shard settings dynamically through attribute access.

381

382

```python { .api }

383

def __getattr__(self, name):

384

"""

385

Get setting value from first shard dynamically.

386

387

Args:

388

name (str): Setting name

389

390

Returns:

391

Setting value from first shard

392

393

Raises:

394

AttributeError: If setting name is not found

395

"""

396

```

397

398

## Usage Examples

399

400

### Basic Sharded Caching

401

402

```python

403

import diskcache

404

405

# Create FanoutCache with 16 shards for higher throughput

406

fanout = diskcache.FanoutCache('/tmp/fanout_cache', shards=16)

407

408

# Basic operations - sharding is transparent

409

fanout.set('user:123', {'name': 'Bob', 'role': 'admin'})

410

user = fanout.get('user:123')

411

412

# Dict-like interface

413

fanout['config'] = {'debug': False, 'max_connections': 100}

414

config = fanout['config']

415

416

# Keys are automatically distributed across shards

417

for i in range(1000):

418

fanout.set(f'item:{i}', f'value_{i}')

419

420

print(f"Total items: {len(fanout)}") # Aggregated across all shards

421

```

422

423

### High-Concurrency Usage

424

425

```python

426

import threading

427

import diskcache

428

429

fanout = diskcache.FanoutCache('/tmp/high_throughput', shards=32)

430

431

def worker(thread_id):

432

# Each thread can work with different keys simultaneously

433

# without blocking due to sharding

434

for i in range(1000):

435

key = f'thread_{thread_id}_item_{i}'

436

fanout.set(key, {'thread': thread_id, 'value': i})

437

438

# Create multiple threads for concurrent access

439

threads = []

440

for i in range(10):

441

t = threading.Thread(target=worker, args=(i,))

442

threads.append(t)

443

t.start()

444

445

for t in threads:

446

t.join()

447

448

print(f"Total items: {len(fanout)}")

449

```

450

451

### Using Sub-collections

452

453

```python

454

fanout = diskcache.FanoutCache('/tmp/collections')

455

456

# Create different data structures in subdirectories

457

user_cache = fanout.cache('users')

458

session_index = fanout.index('sessions')

459

task_queue = fanout.deque('tasks')

460

461

# Use each collection independently

462

user_cache.set('user:123', {'name': 'Alice'})

463

session_index['session_abc'] = {'user_id': 123, 'created': 1609459200}

464

task_queue.append({'task': 'send_email', 'user_id': 123})

465

466

# Collections share the same directory structure but operate independently

467

print(f"Users: {len(user_cache)}")

468

print(f"Sessions: {len(session_index)}")

469

print(f"Tasks: {len(task_queue)}")

470

```

471

472

### Performance Monitoring

473

474

```python

475

# Enable statistics across all shards

476

fanout.stats(enable=True)

477

478

# Perform operations

479

for i in range(10000):

480

fanout.set(f'key_{i}', f'value_{i}')

481

482

for i in range(5000):

483

value = fanout.get(f'key_{i}') # Cache hits

484

485

for i in range(5000, 10000):

486

value = fanout.get(f'missing_{i}') # Cache misses

487

488

# Get aggregated statistics

489

hits, misses = fanout.stats()

490

print(f"Total hits: {hits}, misses: {misses}")

491

print(f"Hit ratio: {hits/(hits+misses):.2%}")

492

print(f"Total size: {fanout.volume()} bytes")

493

```

494

495

### Cache Management

496

497

```python

498

# Expire old items across all shards

499

expired_count = fanout.expire()

500

print(f"Expired {expired_count} items")

501

502

# Evict items by tag across all shards

503

fanout.set('temp1', 'data1', tag='temporary')

504

fanout.set('temp2', 'data2', tag='temporary')

505

evicted = fanout.evict('temporary')

506

print(f"Evicted {evicted} temporary items")

507

508

# Clear everything

509

total_cleared = fanout.clear()

510

print(f"Cleared {total_cleared} total items")

511

```