@@ -429,11 +429,10 @@ export class BoundedCache<K extends KeyType, V> extends AbstractCache<K, V> impl
429429 */
430430 while ( data . weightedSize > data . weightedMaxSize ) {
431431 const probation = data . probation . head . next ;
432- //const evicted = evictedToProbation == 0 ? null : data.probation.head.previous;
433- const evicted = evictedToProbation === 0 ? data . probation . head : data . probation . head . previous ;
432+ const evictedCandidate = evictedToProbation === 0 ? data . probation . head : data . probation . head . previous ;
434433
435434 const hasProbation = probation !== data . probation . head ;
436- const hasEvicted = evicted !== data . probation . head ;
435+ const hasEvicted = evictedCandidate !== data . probation . head ;
437436
438437 let toRemove : BoundedNode < K , V > ;
439438 if ( ! hasProbation && ! hasEvicted ) {
@@ -442,20 +441,46 @@ export class BoundedCache<K extends KeyType, V> extends AbstractCache<K, V> impl
442441 } else if ( ! hasEvicted ) {
443442 toRemove = probation ;
444443 } else if ( ! hasProbation ) {
445- toRemove = evicted ;
444+ toRemove = evictedCandidate ;
446445
447446 evictedToProbation -- ;
448447 } else {
449- // Estimate how often the two items have been accessed
450- const freqEvicted = data . sketch . estimate ( evicted . hashCode ) ;
448+ /*
449+ * Estimate how often the two items have been accessed to
450+ * determine which of the keys should actually be evicted.
451+ *
452+ * Also protect against hash collision attacks where the
453+ * frequency of an item in the cache is raised causing the
454+ * candidate to never be admitted into the cache.
455+ */
456+ let removeCandidate ;
457+
458+ const freqEvictedCandidate = data . sketch . estimate ( evictedCandidate . hashCode ) ;
451459 const freqProbation = data . sketch . estimate ( probation . hashCode ) ;
452460
453- if ( freqEvicted > freqProbation ) {
454- toRemove = probation ;
461+ if ( freqEvictedCandidate > freqProbation ) {
462+ removeCandidate = false ;
463+ } else if ( freqEvictedCandidate < data . sketch . slightlyLessThanHalfMaxSize ) {
464+ /*
465+ * If the frequency of the candidate is slightly less than
466+ * half it can be admitted without going through randomness
467+ * checks.
468+ *
469+ * The idea here is that will reduce the number of random
470+ * admittances.
471+ */
472+ removeCandidate = true ;
455473 } else {
456- toRemove = evicted ;
474+ /*
475+ * Make it a 1 in 1000 chance that the candidate is not
476+ * removed.
477+ *
478+ * TODO: Should this be lower or higher? Please open an issue if you have thoughts on this
479+ */
480+ removeCandidate = Math . floor ( Math . random ( ) * 1000 ) >= 1 ;
457481 }
458482
483+ toRemove = removeCandidate ? evictedCandidate : probation ;
459484 evictedToProbation -- ;
460485 }
461486
0 commit comments