@@ -2447,31 +2447,77 @@ func TestEvictionWhenStaleCVRemoved(t *testing.T) {
24472447// TestUpdateDeltaRevCacheMemoryStatPanic:
24482448// - Test will interleave underlying rev cache operations for UpdateDelta process and Remove item process to reproduce a race between
24492449// threads updating a delta (and that thread updating the cache memory stats) and the underlying value being removed/evicted from the cache
2450- func TestUpdateDeltaRevCacheMemoryStatPanic (t * testing.T ) {
2450+ func TestUpdateDeltaRevCacheMemoryStatPanicSingleEntry (t * testing.T ) {
24512451 cacheHitCounter , cacheMissCounter , getDocumentCounter , getRevisionCounter , cacheNumItems , memoryBytesCounted := base.SgwIntStat {}, base.SgwIntStat {}, base.SgwIntStat {}, base.SgwIntStat {}, base.SgwIntStat {}, base.SgwIntStat {}
24522452 backingStoreMap := CreateTestSingleBackingStoreMap (& testBackingStore {nil , & getDocumentCounter , & getRevisionCounter }, testCollectionID )
24532453 cacheOptions := & RevisionCacheOptions {
24542454 MaxItemCount : 5000 ,
2455- MaxBytes : 125 ,
2455+ MaxBytes : 500 ,
24562456 }
24572457 cache := NewLRURevisionCache (cacheOptions , backingStoreMap , & cacheHitCounter , & cacheMissCounter , & cacheNumItems , & memoryBytesCounted )
24582458
24592459 firstDelta := bytes .Repeat ([]byte ("a" ), 1000 )
24602460 ctx := base .TestCtx (t )
24612461
2462- // Trigger load into cache
2462+ // Trigger load into cache.
24632463 docRev , err := cache .GetWithRev (ctx , "doc1" , "1-abc" , testCollectionID , RevCacheIncludeDelta )
24642464 require .NoError (t , err , "Error adding to cache" )
24652465
2466- revCacheDelta := newRevCacheDelta (firstDelta , "1-abc" , docRev , false , nil )
2466+ revCacheDelta2 := newRevCacheDelta (firstDelta , "1-abc" , docRev , false , nil )
24672467
24682468 // Thread 1: UpdateDelta - start
24692469 value := cache .getValue (ctx , "doc1" , "1-abc" , testCollectionID , false )
24702470 if value != nil {
24712471 // Thread 2: Remove - start - drop value underneath UpdateDelta thread
24722472 cache .RemoveWithRev (ctx , "doc1" , "1-abc" , testCollectionID )
24732473 // Thread 2: Remove - end
2474- outGoingBytes := value .updateDelta (revCacheDelta )
2474+ outGoingBytes := value .updateDelta (revCacheDelta2 )
2475+ if outGoingBytes != 0 {
2476+ cache .currMemoryUsage .Add (outGoingBytes )
2477+ cache .cacheMemoryBytesStat .Add (outGoingBytes )
2478+ }
2479+ // check for memory based eviction
2480+ cache .revCacheMemoryBasedEviction (ctx )
2481+ }
2482+ // Thread 1: UpdateDelta - end
2483+
2484+ assert .Equal (t , 0 , cache .lruList .Len ())
2485+ assert .Equal (t , int64 (0 ), memoryBytesCounted .Value ())
2486+ }
2487+
2488+ // TestUpdateDeltaRevCacheMemoryStatPanic:
2489+ // - Test will interleave underlying rev cache operations for UpdateDelta process and Remove item process to reproduce a race between
2490+ // threads updating a delta (and that thread updating the cache memory stats) and the underlying value being removed/evicted from the cache
2491+ func TestUpdateDeltaRevCacheMemoryStatPanicMultipleEntries (t * testing.T ) {
2492+ cacheHitCounter , cacheMissCounter , getDocumentCounter , getRevisionCounter , cacheNumItems , memoryBytesCounted := base.SgwIntStat {}, base.SgwIntStat {}, base.SgwIntStat {}, base.SgwIntStat {}, base.SgwIntStat {}, base.SgwIntStat {}
2493+ backingStoreMap := CreateTestSingleBackingStoreMap (& testBackingStore {nil , & getDocumentCounter , & getRevisionCounter }, testCollectionID )
2494+ cacheOptions := & RevisionCacheOptions {
2495+ MaxItemCount : 5000 ,
2496+ MaxBytes : 500 ,
2497+ }
2498+ cache := NewLRURevisionCache (cacheOptions , backingStoreMap , & cacheHitCounter , & cacheMissCounter , & cacheNumItems , & memoryBytesCounted )
2499+
2500+ firstDelta := bytes .Repeat ([]byte ("a" ), 1000 )
2501+ ctx := base .TestCtx (t )
2502+
2503+ // Trigger load into cache. Add one revision (doc1) without a delta that's less than 500 bytes, then a
2504+ // revision (doc2) with a delta update that will exceed memory limit
2505+ // when added. Both should be removed and cache memory stats should be zero.
2506+ _ , err := cache .GetWithRev (ctx , "doc1" , "1-abc" , testCollectionID , RevCacheIncludeDelta )
2507+ require .NoError (t , err , "Error adding to cache" )
2508+
2509+ docRev2 , err := cache .GetWithRev (ctx , "doc2" , "1-abc" , testCollectionID , RevCacheIncludeDelta )
2510+ require .NoError (t , err , "Error adding to cache" )
2511+
2512+ revCacheDelta2 := newRevCacheDelta (firstDelta , "1-abc" , docRev2 , false , nil )
2513+
2514+ // Thread 1: UpdateDelta - start
2515+ value := cache .getValue (ctx , "doc2" , "1-abc" , testCollectionID , false )
2516+ if value != nil {
2517+ // Thread 2: Remove - start - drop value underneath UpdateDelta thread
2518+ cache .RemoveWithRev (ctx , "doc2" , "1-abc" , testCollectionID )
2519+ // Thread 2: Remove - end
2520+ outGoingBytes := value .updateDelta (revCacheDelta2 )
24752521 if outGoingBytes != 0 {
24762522 cache .currMemoryUsage .Add (outGoingBytes )
24772523 cache .cacheMemoryBytesStat .Add (outGoingBytes )
0 commit comments