@@ -93,6 +93,10 @@ func (sc *ShardedLRURevisionCache) RemoveWithCV(ctx context.Context, docID strin
93
93
sc .getShard (docID ).RemoveWithCV (ctx , docID , cv , collectionID )
94
94
}
95
95
96
+ func (sc * ShardedLRURevisionCache ) RemoveRevOnly (ctx context.Context , docID , revID string , collectionID uint32 ) {
97
+ sc .getShard (docID ).RemoveRevOnly (ctx , docID , revID , collectionID )
98
+ }
99
+
96
100
// An LRU cache of document revision bodies, together with their channel access.
97
101
type LRURevisionCache struct {
98
102
backingStores map [uint32 ]RevisionCacheBackingStore
@@ -507,6 +511,12 @@ func (rc *LRURevisionCache) RemoveWithCV(ctx context.Context, docID string, cv *
507
511
rc .removeFromCacheByCV (ctx , docID , cv , collectionID )
508
512
}
509
513
514
+ // RemoveRevOnly removes a rev from revision cache lookup map, if present.
515
+ func (rc * LRURevisionCache ) RemoveRevOnly (ctx context.Context , docID , revID string , collectionID uint32 ) {
516
+ // This will only remove the entry from the rev lookup map, not the lru list
517
+ rc .removeFromRevLookup (ctx , docID , revID , collectionID )
518
+ }
519
+
510
520
// removeFromCacheByCV removes an entry from rev cache by CV
511
521
func (rc * LRURevisionCache ) removeFromCacheByCV (ctx context.Context , docID string , cv * Version , collectionID uint32 ) {
512
522
key := IDandCV {DocID : docID , Source : cv .SourceID , Version : cv .Value , CollectionID : collectionID }
@@ -518,6 +528,7 @@ func (rc *LRURevisionCache) removeFromCacheByCV(ctx context.Context, docID strin
518
528
}
519
529
// grab the revid key from the value to enable us to remove the reference from the rev lookup map too
520
530
elem := element .Value .(* revCacheValue )
531
+
521
532
legacyKey := IDAndRev {DocID : docID , RevID : elem .revID , CollectionID : collectionID }
522
533
rc .lruList .Remove (element )
523
534
delete (rc .hlvCache , key )
@@ -538,6 +549,7 @@ func (rc *LRURevisionCache) removeFromCacheByRev(ctx context.Context, docID, rev
538
549
}
539
550
// grab the cv key from the value to enable us to remove the reference from the rev lookup map too
540
551
elem := element .Value .(* revCacheValue )
552
+
541
553
hlvKey := IDandCV {DocID : docID , Source : elem .cv .SourceID , Version : elem .cv .Value , CollectionID : collectionID }
542
554
rc .lruList .Remove (element )
543
555
// decrement the overall memory bytes count
@@ -548,6 +560,16 @@ func (rc *LRURevisionCache) removeFromCacheByRev(ctx context.Context, docID, rev
548
560
rc .cacheNumItems .Add (- 1 )
549
561
}
550
562
563
+ // removeFromRevLookup will only remove the entry from the rev lookup map, if present. Underlying element must stay in list for eviction to work.
564
+ func (rc * LRURevisionCache ) removeFromRevLookup (ctx context.Context , docID , revID string , collectionID uint32 ) {
565
+ key := IDAndRev {DocID : docID , RevID : revID , CollectionID : collectionID }
566
+ rc .lock .Lock ()
567
+ defer rc .lock .Unlock ()
568
+ // only delete from rev lookup map, if we delete underlying element in list, the now elem in the HLV lookup map
569
+ // will never be evicted leading to potential unbounded growth of HLV lookup map
570
+ delete (rc .cache , key )
571
+ }
572
+
551
573
// removeValue removes a value from the revision cache, if present and the value matches the the value. If there's an item in the revision cache with a matching docID and revID but the document is different, this item will not be removed from the rev cache.
552
574
func (rc * LRURevisionCache ) removeValue (value * revCacheValue ) {
553
575
rc .lock .Lock ()
@@ -583,8 +605,17 @@ func (rc *LRURevisionCache) _numberCapacityEviction() (numItemsEvicted int64, nu
583
605
}
584
606
hlvKey := IDandCV {DocID : value .id , Source : value .cv .SourceID , Version : value .cv .Value , CollectionID : value .collectionID }
585
607
revKey := IDAndRev {DocID : value .id , RevID : value .revID , CollectionID : value .collectionID }
586
- delete (rc .cache , revKey )
587
608
delete (rc .hlvCache , hlvKey )
609
+ if elem := rc .cache [revKey ]; elem != nil {
610
+ revValue := elem .Value .(* revCacheValue )
611
+ // we need to check if the value pointed to by the rev lookup map is the same value we're evicting, this is
612
+ // because we can have can currently have two items with the same docID and revID, but different CVs due to
613
+ // a new HLV being generated for user xattr updates where we don't generate a new revID.
614
+ if revValue .cv .String () == value .cv .String () {
615
+ // this rev lookup item matches the value we're evicting, so remove it
616
+ delete (rc .cache , revKey )
617
+ }
618
+ }
588
619
numItemsEvicted ++
589
620
numBytesEvicted += value .getItemBytes ()
590
621
}
@@ -832,8 +863,17 @@ func (rc *LRURevisionCache) performEviction(ctx context.Context) {
832
863
}
833
864
revKey := IDAndRev {DocID : value .id , RevID : value .revID , CollectionID : value .collectionID }
834
865
hlvKey := IDandCV {DocID : value .id , Source : value .cv .SourceID , Version : value .cv .Value , CollectionID : value .collectionID }
835
- delete (rc .cache , revKey )
836
866
delete (rc .hlvCache , hlvKey )
867
+ if elem := rc .cache [revKey ]; elem != nil {
868
+ revValue := elem .Value .(* revCacheValue )
869
+ // we need to check if the value pointed to by the rev lookup map is the same value we're evicting, this is
870
+ // because we can have can currently have two items with the same docID and revID, but different CVs due to
871
+ // a new HLV being generated for user xattr updates where we don't generate a new revID.
872
+ if revValue .cv .String () == value .cv .String () {
873
+ // this rev lookup item matches the value we're evicting, so remove it
874
+ delete (rc .cache , revKey )
875
+ }
876
+ }
837
877
numItemsRemoved ++
838
878
valueBytes := value .getItemBytes ()
839
879
numBytesRemoved += valueBytes
0 commit comments