or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asynchronous-caching.mdcache-construction.mdcache-policies.mdfunctional-interfaces.mdindex.mdstatistics.mdsynchronous-caching.md

cache-policies.mddocs/

0

# Cache Policies

1

2

The `Policy` interface provides runtime access to cache configuration and behavior, allowing inspection and modification of cache policies after creation. This enables dynamic tuning and monitoring of cache performance characteristics.

3

4

## Policy Interface

5

6

```java { .api }

7

public interface Policy<K, V> {

8

// Statistics inspection

9

boolean isRecordingStats();

10

11

// Entry inspection (no side effects)

12

V getIfPresentQuietly(K key);

13

CacheEntry<K, V> getEntryIfPresentQuietly(K key);

14

15

// Active refreshes

16

Map<K, CompletableFuture<V>> refreshes();

17

18

// Policy access

19

Optional<Eviction<K, V>> eviction();

20

Optional<FixedExpiration<K, V>> expireAfterAccess();

21

Optional<FixedExpiration<K, V>> expireAfterWrite();

22

Optional<VarExpiration<K, V>> expireVariably();

23

Optional<FixedRefresh<K, V>> refreshAfterWrite();

24

}

25

26

// Cache entry metadata interface

27

interface CacheEntry<K, V> extends Map.Entry<K, V> {

28

int weight();

29

long expiresAt();

30

Duration expiresAfter();

31

long refreshableAt();

32

Duration refreshableAfter();

33

long snapshotAt();

34

}

35

```

36

37

### Accessing Cache Policies

38

39

```java

40

Cache<String, String> cache = Caffeine.newBuilder()

41

.maximumSize(1000)

42

.expireAfterAccess(Duration.ofMinutes(30))

43

.expireAfterWrite(Duration.ofHours(1))

44

.refreshAfterWrite(Duration.ofMinutes(10))

45

.recordStats()

46

.build();

47

48

Policy<String, String> policy = cache.policy();

49

50

// Check if statistics are enabled

51

boolean recordingStats = policy.isRecordingStats(); // true

52

53

// Access available policies

54

Optional<Policy.Eviction<String, String>> eviction = policy.eviction();

55

Optional<Policy.Expiration<String, String>> accessExpiration = policy.expireAfterAccess();

56

Optional<Policy.Expiration<String, String>> writeExpiration = policy.expireAfterWrite();

57

Optional<Policy.Expiration<String, String>> refreshPolicy = policy.refreshAfterWrite();

58

```

59

60

## Eviction Policy

61

62

The eviction policy controls size-based and weight-based cache limits.

63

64

```java { .api }

65

interface Eviction<K, V> {

66

// Size inspection and modification

67

boolean isWeighted();

68

OptionalInt weightOf(K key);

69

OptionalLong weightedSize();

70

long getMaximum();

71

void setMaximum(long maximum);

72

73

// Entry inspection by count

74

Map<K, V> coldest(int limit);

75

Map<K, V> hottest(int limit);

76

77

// Entry inspection by weight (v3.0.4+)

78

Map<K, V> coldestWeighted(long weightLimit);

79

Map<K, V> hottestWeighted(long weightLimit);

80

81

// Stream-based entry inspection (v3.0.6+)

82

<T> T coldest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction);

83

<T> T hottest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction);

84

}

85

```

86

87

### Size-Based Eviction

88

89

```java

90

Cache<String, String> sizeCache = Caffeine.newBuilder()

91

.maximumSize(1000)

92

.build();

93

94

Policy.Eviction<String, String> evictionPolicy = sizeCache.policy().eviction().get();

95

96

// Inspect current configuration

97

boolean isWeighted = evictionPolicy.isWeighted(); // false for size-based

98

long maxSize = evictionPolicy.getMaximum().getAsLong(); // 1000

99

100

// Dynamically adjust maximum size

101

evictionPolicy.setMaximum(2000);

102

long newMaxSize = evictionPolicy.getMaximum().getAsLong(); // 2000

103

104

// Inspect hottest and coldest entries

105

sizeCache.put("hot1", "value1");

106

sizeCache.put("hot2", "value2");

107

sizeCache.put("cold1", "value1");

108

sizeCache.put("cold2", "value2");

109

110

// Access patterns affect hotness

111

sizeCache.getIfPresent("hot1");

112

sizeCache.getIfPresent("hot2");

113

114

Map<String, String> hottestEntries = evictionPolicy.hottest(2);

115

Map<String, String> coldestEntries = evictionPolicy.coldest(2);

116

```

117

118

### Weight-Based Eviction

119

120

```java

121

Cache<String, String> weightCache = Caffeine.newBuilder()

122

.maximumWeight(10000)

123

.weigher((key, value) -> key.length() + value.length())

124

.build();

125

126

Policy.Eviction<String, String> weightEvictionPolicy = weightCache.policy().eviction().get();

127

128

// Weight-specific operations

129

boolean isWeighted = weightEvictionPolicy.isWeighted(); // true

130

long maxWeight = weightEvictionPolicy.getMaximum().getAsLong(); // 10000

131

long currentWeight = weightEvictionPolicy.weightedSize().getAsLong();

132

133

// Adjust maximum weight dynamically

134

weightEvictionPolicy.setMaximum(20000);

135

136

System.out.println("Current weight: " + currentWeight + "/" + maxWeight);

137

```

138

139

## Expiration Policies

140

141

Expiration policies control time-based entry removal and provide runtime inspection.

142

143

```java { .api }

144

interface FixedExpiration<K, V> {

145

// Duration inspection and modification

146

OptionalLong ageOf(K key, TimeUnit unit);

147

Duration ageOf(K key);

148

long getExpiresAfter(TimeUnit unit);

149

Duration getExpiresAfter();

150

void setExpiresAfter(long duration, TimeUnit unit);

151

void setExpiresAfter(Duration duration);

152

153

// Entry inspection by count

154

Map<K, V> oldest(int limit);

155

Map<K, V> youngest(int limit);

156

157

// Stream-based entry inspection (v3.0.6+)

158

<T> T oldest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction);

159

<T> T youngest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction);

160

}

161

162

interface VarExpiration<K, V> {

163

// Variable expiration inspection and modification

164

OptionalLong getExpiresAfter(K key, TimeUnit unit);

165

Optional<Duration> getExpiresAfter(K key);

166

void setExpiresAfter(K key, long duration, TimeUnit unit);

167

void setExpiresAfter(K key, Duration duration);

168

169

// Entry modification with custom expiration

170

V putIfAbsent(K key, V value, long duration, TimeUnit unit);

171

V putIfAbsent(K key, V value, Duration duration);

172

V put(K key, V value, long duration, TimeUnit unit);

173

V put(K key, V value, Duration duration);

174

V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction, Duration duration);

175

176

// Age and entry inspection

177

OptionalLong ageOf(K key, TimeUnit unit);

178

Map<K, V> oldest(int limit);

179

Map<K, V> youngest(int limit);

180

181

// Stream-based entry inspection (v3.0.6+)

182

<T> T oldest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction);

183

<T> T youngest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction);

184

}

185

186

interface FixedRefresh<K, V> {

187

OptionalLong ageOf(K key, TimeUnit unit);

188

Duration ageOf(K key);

189

long getRefreshesAfter(TimeUnit unit);

190

Duration getRefreshesAfter();

191

void setRefreshesAfter(long duration, TimeUnit unit);

192

void setRefreshesAfter(Duration duration);

193

}

194

```

195

196

### Fixed Expiration Policies

197

198

```java

199

Cache<String, String> expiringCache = Caffeine.newBuilder()

200

.maximumSize(1000)

201

.expireAfterAccess(Duration.ofMinutes(30))

202

.expireAfterWrite(Duration.ofHours(2))

203

.build();

204

205

// Access expiration policy

206

Policy.Expiration<String, String> accessExpiration =

207

expiringCache.policy().expireAfterAccess().get();

208

209

// Inspect current expiration settings

210

Duration accessDuration = accessExpiration.getExpiresAfter().get(); // 30 minutes

211

212

// Modify expiration duration at runtime

213

accessExpiration.setExpiresAfter(Duration.ofMinutes(45));

214

215

// Write expiration policy

216

Policy.Expiration<String, String> writeExpiration =

217

expiringCache.policy().expireAfterWrite().get();

218

219

Duration writeDuration = writeExpiration.getExpiresAfter().get(); // 2 hours

220

writeExpiration.setExpiresAfter(Duration.ofHours(3));

221

222

// Inspect entry ages

223

expiringCache.put("test_key", "test_value");

224

Thread.sleep(1000);

225

226

OptionalLong ageInSeconds = accessExpiration.ageOf("test_key", TimeUnit.SECONDS);

227

if (ageInSeconds.isPresent()) {

228

System.out.println("Entry age: " + ageInSeconds.getAsLong() + " seconds");

229

}

230

231

// Get oldest and youngest entries

232

Map<String, String> oldestEntries = accessExpiration.oldest(5);

233

Map<String, String> youngestEntries = accessExpiration.youngest(5);

234

```

235

236

### Variable Expiration Policy

237

238

```java

239

Cache<String, String> varExpiringCache = Caffeine.newBuilder()

240

.maximumSize(1000)

241

.expireAfter(Expiry.creating((key, value) -> {

242

// Different expiration based on key prefix

243

if (key.startsWith("temp_")) {

244

return Duration.ofMinutes(5);

245

} else if (key.startsWith("cache_")) {

246

return Duration.ofHours(1);

247

} else {

248

return Duration.ofMinutes(30);

249

}

250

}))

251

.build();

252

253

Policy.VarExpiration<String, String> varExpiration =

254

varExpiringCache.policy().expireVariably().get();

255

256

// Add entries with different expiration times

257

varExpiringCache.put("temp_data", "temporary");

258

varExpiringCache.put("cache_data", "cached");

259

varExpiringCache.put("normal_data", "normal");

260

261

// Inspect individual entry expiration

262

OptionalLong tempExpiration = varExpiration.getExpiresAfter("temp_data", TimeUnit.MINUTES);

263

OptionalLong cacheExpiration = varExpiration.getExpiresAfter("cache_data", TimeUnit.MINUTES);

264

265

System.out.println("Temp expires in: " + tempExpiration.orElse(-1) + " minutes");

266

System.out.println("Cache expires in: " + cacheExpiration.orElse(-1) + " minutes");

267

268

// Modify expiration for specific entries

269

varExpiration.setExpiresAfter("temp_data", 10, TimeUnit.MINUTES);

270

271

// Inspect ages

272

OptionalLong tempAge = varExpiration.ageOf("temp_data", TimeUnit.SECONDS);

273

System.out.println("Temp entry age: " + tempAge.orElse(-1) + " seconds");

274

```

275

276

## Refresh Policy

277

278

The refresh policy controls automatic background refresh behavior for loading caches.

279

280

```java

281

LoadingCache<String, String> refreshingCache = Caffeine.newBuilder()

282

.maximumSize(1000)

283

.refreshAfterWrite(Duration.ofMinutes(5))

284

.build(key -> "loaded_" + System.currentTimeMillis());

285

286

Policy.Expiration<String, String> refreshPolicy =

287

refreshingCache.policy().refreshAfterWrite().get();

288

289

// Inspect refresh configuration

290

Duration refreshInterval = refreshPolicy.getExpiresAfter().get(); // 5 minutes

291

292

// Modify refresh interval

293

refreshPolicy.setExpiresAfter(Duration.ofMinutes(10));

294

295

// Check time since last refresh

296

refreshingCache.get("test_key");

297

Thread.sleep(1000);

298

299

OptionalLong timeSinceRefresh = refreshPolicy.ageOf("test_key", TimeUnit.SECONDS);

300

System.out.println("Time since last refresh: " + timeSinceRefresh.orElse(-1) + " seconds");

301

302

// Get entries that need refresh soon

303

Map<String, String> oldestEntries = refreshPolicy.oldest(10);

304

System.out.println("Entries needing refresh soon: " + oldestEntries.keySet());

305

```

306

307

## Policy Inspection Examples

308

309

### Complete Policy Inspection

310

311

```java

312

Cache<String, String> fullyConfiguredCache = Caffeine.newBuilder()

313

.maximumSize(10000)

314

.expireAfterAccess(Duration.ofMinutes(30))

315

.expireAfterWrite(Duration.ofHours(2))

316

.recordStats()

317

.build();

318

319

Policy<String, String> policy = fullyConfiguredCache.policy();

320

321

// Check all available policies

322

System.out.println("Recording stats: " + policy.isRecordingStats());

323

324

if (policy.eviction().isPresent()) {

325

Policy.Eviction<String, String> eviction = policy.eviction().get();

326

System.out.println("Max size: " + eviction.getMaximum().orElse(-1));

327

System.out.println("Is weighted: " + eviction.isWeighted());

328

}

329

330

if (policy.expireAfterAccess().isPresent()) {

331

Policy.Expiration<String, String> accessExp = policy.expireAfterAccess().get();

332

System.out.println("Expire after access: " + accessExp.getExpiresAfter().orElse(null));

333

}

334

335

if (policy.expireAfterWrite().isPresent()) {

336

Policy.Expiration<String, String> writeExp = policy.expireAfterWrite().get();

337

System.out.println("Expire after write: " + writeExp.getExpiresAfter().orElse(null));

338

}

339

340

// Variable expiration and refresh would be empty for this cache

341

System.out.println("Has variable expiration: " + policy.expireVariably().isPresent());

342

System.out.println("Has refresh policy: " + policy.refreshAfterWrite().isPresent());

343

```

344

345

### Dynamic Policy Adjustment

346

347

```java

348

Cache<String, String> adaptiveCache = Caffeine.newBuilder()

349

.maximumSize(1000)

350

.expireAfterAccess(Duration.ofMinutes(10))

351

.build();

352

353

Policy<String, String> policy = adaptiveCache.policy();

354

355

// Monitor cache performance and adjust policies

356

Timer timer = new Timer();

357

timer.scheduleAtFixedRate(new TimerTask() {

358

@Override

359

public void run() {

360

CacheStats stats = adaptiveCache.stats();

361

double hitRate = stats.hitRate();

362

363

// Adjust expiration based on hit rate

364

if (hitRate < 0.8 && policy.expireAfterAccess().isPresent()) {

365

// Low hit rate - increase expiration time

366

Duration current = policy.expireAfterAccess().get().getExpiresAfter().get();

367

Duration increased = current.multipliedBy(2);

368

policy.expireAfterAccess().get().setExpiresAfter(increased);

369

System.out.println("Increased expiration to: " + increased);

370

}

371

372

// Adjust size based on eviction rate

373

if (stats.evictionCount() > 100 && policy.eviction().isPresent()) {

374

// High eviction rate - increase cache size

375

long currentMax = policy.eviction().get().getMaximum().getAsLong();

376

policy.eviction().get().setMaximum(currentMax * 2);

377

System.out.println("Increased max size to: " + (currentMax * 2));

378

}

379

}

380

}, 60000, 60000); // Check every minute

381

```

382

383

## Policy Limitations

384

385

- **Async Cache Policies**: Async caches return policies that operate on the underlying synchronous cache

386

- **Configuration Constraints**: Some policy modifications may be rejected if they violate cache constraints

387

- **Thread Safety**: Policy operations are thread-safe but modifications should be done carefully in concurrent environments

388

- **Performance Impact**: Frequent policy modifications may impact cache performance