@@ -162,7 +162,7 @@ static class TieredSpilloverCacheSegment<K, V> implements ICache<K, V> {
162
162
* This map is used to handle concurrent requests for same key in computeIfAbsent() to ensure we load the value
163
163
* only once.
164
164
*/
165
- Map <ICacheKey <K >, CompletableFuture <Tuple <ICacheKey <K >, V >>> completableFutureMap = new ConcurrentHashMap <>();
165
+ Map <ICacheKey <K >, CompletableFuture <Tuple <Tuple < ICacheKey <K >, V >, Boolean >>> completableFutureMap = new ConcurrentHashMap <>();
166
166
167
167
TieredSpilloverCacheSegment (
168
168
Builder <K , V > builder ,
@@ -291,7 +291,7 @@ public V computeIfAbsent(ICacheKey<K> key, LoadAwareCacheLoader<ICacheKey<K>, V>
291
291
// getValueFromTieredCache(),
292
292
// we will see all misses. Instead, handle stats in computeIfAbsent().
293
293
Tuple <V , String > cacheValueTuple ;
294
- CompletableFuture <Tuple <ICacheKey <K >, V >> future = null ;
294
+ CompletableFuture <Tuple <Tuple < ICacheKey <K >, V >, Boolean >> future = null ;
295
295
try (ReleasableLock ignore = readLock .acquire ()) {
296
296
cacheValueTuple = getValueFromTieredCache (false ).apply (key );
297
297
if (cacheValueTuple == null ) {
@@ -343,14 +343,17 @@ public V computeIfAbsent(ICacheKey<K> key, LoadAwareCacheLoader<ICacheKey<K>, V>
343
343
private Tuple <V , Tuple <Boolean , Boolean >> compute (
344
344
ICacheKey <K > key ,
345
345
LoadAwareCacheLoader <ICacheKey <K >, V > loader ,
346
- CompletableFuture <Tuple <ICacheKey <K >, V >> future
346
+ CompletableFuture <Tuple <Tuple < ICacheKey <K >, V >, Boolean >> future
347
347
) throws Exception {
348
- // Handler to handle results post-processing. Takes a tuple<key, value> or exception as an input and returns
349
- // the value. Also before returning value, puts the value in cache.
348
+ // Handler to handle results post-processing. Takes a Tuple<Tuple<key, value>, boolean>, where the boolean represents whether
349
+ // this key/value pair was rejected by the policies,
350
+ // or exception as an input and returns the value. Also before returning value, puts the value in cache if accepted by policies.
350
351
boolean wasCacheMiss = false ;
351
352
boolean wasRejectedByPolicy = false ;
352
- BiFunction <Tuple <ICacheKey <K >, V >, Throwable , Void > handler = (pair , ex ) -> {
353
- if (pair != null ) {
353
+ BiFunction <Tuple <Tuple <ICacheKey <K >, V >, Boolean >, Throwable , Void > handler = (pairInfo , ex ) -> {
354
+ Tuple <ICacheKey <K >, V > pair = pairInfo .v1 ();
355
+ boolean rejectedByPolicy = pairInfo .v2 ();
356
+ if (pair != null && !rejectedByPolicy ) {
354
357
boolean didAddToCache = false ;
355
358
try (ReleasableLock ignore = writeLock .acquire ()) {
356
359
onHeapCache .put (pair .v1 (), pair .v2 ());
@@ -387,33 +390,24 @@ private Tuple<V, Tuple<Boolean, Boolean>> compute(
387
390
future .completeExceptionally (npe );
388
391
throw new ExecutionException (npe );
389
392
} else {
390
- if (evaluatePoliciesList (value , policies )) {
391
- future .complete (new Tuple <>(key , value ));
392
- wasCacheMiss = true ;
393
- } else {
394
- future .complete (null ); // Passing null would skip the logic to put this into onHeap cache.
395
- // Signal to the caller that the key didn't enter the cache by sending a removal notification.
396
- // This case does not count as a cache miss.
397
- removalListener .onRemoval (new RemovalNotification <>(key , value , RemovalReason .EXPLICIT ));
398
- wasRejectedByPolicy = true ;
399
- }
393
+ wasRejectedByPolicy = !evaluatePoliciesList (value , policies );
394
+ future .complete (new Tuple <>(new Tuple <>(key , value ), wasRejectedByPolicy ));
395
+ wasCacheMiss = !wasRejectedByPolicy ;
400
396
}
401
397
} else {
402
398
try {
403
- Tuple <ICacheKey <K >, V > futureTuple = future .get ();
404
- if (futureTuple == null ) {
405
- // This case can happen if we earlier completed the future with null to skip putting the value into the cache.
406
- // It does not count as a cache miss.
407
- value = loader .load (key );
408
- removalListener .onRemoval (new RemovalNotification <>(key , value , RemovalReason .EXPLICIT ));
409
- wasRejectedByPolicy = true ;
410
- } else {
411
- value = futureTuple .v2 ();
412
- }
399
+ Tuple <Tuple <ICacheKey <K >, V >, Boolean > futureTuple = future .get ();
400
+ wasRejectedByPolicy = futureTuple .v2 ();
401
+ value = futureTuple .v1 ().v2 ();
413
402
} catch (InterruptedException ex ) {
414
403
throw new IllegalStateException (ex );
415
404
}
416
405
}
406
+ if (wasRejectedByPolicy ) {
407
+ // Signal to the caller that the key didn't enter the cache by sending a removal notification.
408
+ // This case does not count as a cache miss.
409
+ removalListener .onRemoval (new RemovalNotification <>(key , value , RemovalReason .EXPLICIT ));
410
+ }
417
411
return new Tuple <>(value , new Tuple <>(wasCacheMiss , wasRejectedByPolicy ));
418
412
}
419
413
0 commit comments