Skip to content

Commit

Permalink
CBG-4234: clean up rev cache work (#7113)
Browse files Browse the repository at this point in the history
* CBG-4234: clean up rev cache work

* new test
  • Loading branch information
gregns1 authored and bbrks committed Sep 26, 2024
1 parent 59c86bc commit 2583f2b
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 3 deletions.
6 changes: 6 additions & 0 deletions db/revision_cache_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ func NewRevisionCache(cacheOptions *RevisionCacheOptions, backingStores map[uint
cacheMissStat := cacheStats.RevisionCacheMisses
cacheNumItemsStat := cacheStats.RevisionCacheNumItems
cacheMemoryStat := cacheStats.RevisionCacheTotalMemory
if cacheNumItemsStat.Value() != 0 {
cacheNumItemsStat.Set(0)
}
if cacheMemoryStat.Value() != 0 {
cacheMemoryStat.Set(0)
}

if cacheOptions.ShardCount > 1 {
return NewShardedLRURevisionCache(cacheOptions, backingStores, cacheHitStat, cacheMissStat, cacheNumItemsStat, cacheMemoryStat)
Expand Down
11 changes: 8 additions & 3 deletions db/revision_cache_lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,9 @@ func (rc *LRURevisionCache) Put(ctx context.Context, docRev DocumentRevision, co
// increment incoming bytes
docRev.CalculateBytes()
rc.cacheMemoryBytes.Add(docRev.MemoryBytes)
value.store(docRev)
// check for rev cache memory based eviction
rc.revCacheMemoryBasedEviction()
value.store(docRev)
}

// Upsert a revision in the cache.
Expand Down Expand Up @@ -276,17 +276,19 @@ func (rc *LRURevisionCache) Upsert(ctx context.Context, docRev DocumentRevision,
docRev.CalculateBytes()
// add new item bytes to overall count
rc.cacheMemoryBytes.Add(docRev.MemoryBytes)
value.store(docRev)

// check we aren't over memory capacity, if so perform eviction
numItemsRemoved = 0
if rc.memoryCapacity > 0 {
for rc.cacheMemoryBytes.Value() > rc.memoryCapacity {
rc.purgeOldest_()
numItemsRemoved++
}
rc.cacheNumItems.Add(int64(-numItemsRemoved))
}

rc.lock.Unlock()

value.store(docRev)
}

func (rc *LRURevisionCache) getValue(docID, revID string, collectionID uint32, create bool) (value *revCacheValue) {
Expand Down Expand Up @@ -538,7 +540,10 @@ func (rc *LRURevisionCache) revCacheMemoryBasedEviction() {
func (rc *LRURevisionCache) performEviction() {
rc.lock.Lock()
defer rc.lock.Unlock()
var numItemsRemoved int64
for rc.cacheMemoryBytes.Value() > rc.memoryCapacity {
rc.purgeOldest_()
numItemsRemoved++
}
rc.cacheNumItems.Add(-numItemsRemoved)
}
108 changes: 108 additions & 0 deletions db/revision_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ func TestLRURevisionCacheEviction(t *testing.T) {
id := strconv.Itoa(docID)
cache.Put(ctx, DocumentRevision{BodyBytes: []byte(`{}`), DocID: id, RevID: "1-abc", History: Revisions{"start": 1}}, testCollectionID)
}
assert.Equal(t, int64(10), cacheNumItems.Value())
assert.Equal(t, int64(20), memoryBytesCounted.Value())

// Get them back out
for i := 0; i < 10; i++ {
Expand All @@ -115,12 +117,16 @@ func TestLRURevisionCacheEviction(t *testing.T) {
assert.Equal(t, int64(0), cacheMissCounter.Value())
assert.Equal(t, int64(i+1), cacheHitCounter.Value())
}
assert.Equal(t, int64(10), cacheNumItems.Value())
assert.Equal(t, int64(20), memoryBytesCounted.Value())

// Add 3 more docs to the now full revcache
for i := 10; i < 13; i++ {
docID := strconv.Itoa(i)
cache.Put(ctx, DocumentRevision{BodyBytes: []byte(`{}`), DocID: docID, RevID: "1-abc", History: Revisions{"start": 1}}, testCollectionID)
}
assert.Equal(t, int64(10), cacheNumItems.Value())
assert.Equal(t, int64(20), memoryBytesCounted.Value())

// Check that the first 3 docs were evicted
prevCacheHitCount := cacheHitCounter.Value()
Expand All @@ -132,6 +138,8 @@ func TestLRURevisionCacheEviction(t *testing.T) {
assert.Equal(t, int64(0), cacheMissCounter.Value()) // peek incurs no cache miss if not found
assert.Equal(t, prevCacheHitCount, cacheHitCounter.Value())
}
assert.Equal(t, int64(10), cacheNumItems.Value())
assert.Equal(t, int64(20), memoryBytesCounted.Value())

// and check we can Get up to and including the last 3 we put in
for i := 0; i < 10; i++ {
Expand All @@ -143,6 +151,8 @@ func TestLRURevisionCacheEviction(t *testing.T) {
assert.Equal(t, int64(0), cacheMissCounter.Value())
assert.Equal(t, prevCacheHitCount+int64(i)+1, cacheHitCounter.Value())
}
assert.Equal(t, int64(10), cacheNumItems.Value())
assert.Equal(t, int64(20), memoryBytesCounted.Value())
}

func TestLRURevisionCacheEvictionMemoryBased(t *testing.T) {
Expand Down Expand Up @@ -612,6 +622,104 @@ func TestUpdateDeltaRevCacheMemoryStat(t *testing.T) {
assert.Equal(t, 0, cache.lruList.Len())
}

func TestImmediateRevCacheMemoryBasedEviction(t *testing.T) {
cacheHitCounter, cacheMissCounter, getDocumentCounter, getRevisionCounter, cacheNumItems, memoryBytesCounted := base.SgwIntStat{}, base.SgwIntStat{}, base.SgwIntStat{}, base.SgwIntStat{}, base.SgwIntStat{}, base.SgwIntStat{}
backingStoreMap := CreateTestSingleBackingStoreMap(&testBackingStore{nil, &getDocumentCounter, &getRevisionCounter}, testCollectionID)
cacheOptions := &RevisionCacheOptions{
MaxItemCount: 10,
MaxBytes: 10,
}
ctx := base.TestCtx(t)
cache := NewLRURevisionCache(cacheOptions, backingStoreMap, &cacheHitCounter, &cacheMissCounter, &cacheNumItems, &memoryBytesCounted)

cache.Put(ctx, DocumentRevision{BodyBytes: []byte(`{"some":"test"}`), DocID: "doc1", RevID: "1-abc", History: Revisions{"start": 1}}, testCollectionID)

assert.Equal(t, int64(0), memoryBytesCounted.Value())
assert.Equal(t, int64(0), cacheNumItems.Value())

cache.Upsert(ctx, DocumentRevision{BodyBytes: []byte(`{"some":"test"}`), DocID: "doc2", RevID: "1-abc", History: Revisions{"start": 1}}, testCollectionID)

assert.Equal(t, int64(0), memoryBytesCounted.Value())
assert.Equal(t, int64(0), cacheNumItems.Value())

docRev, err := cache.Get(ctx, "doc1", "1-abc", testCollectionID, RevCacheOmitDelta)
require.NoError(t, err)
assert.NotNil(t, docRev.BodyBytes)

assert.Equal(t, int64(0), memoryBytesCounted.Value())
assert.Equal(t, int64(0), cacheNumItems.Value())

docRev, err = cache.GetActive(ctx, "doc1", testCollectionID)
require.NoError(t, err)
assert.NotNil(t, docRev.BodyBytes)

assert.Equal(t, int64(0), memoryBytesCounted.Value())
assert.Equal(t, int64(0), cacheNumItems.Value())
}

func TestImmediateRevCacheItemBasedEviction(t *testing.T) {
cacheHitCounter, cacheMissCounter, getDocumentCounter, getRevisionCounter, cacheNumItems, memoryBytesCounted := base.SgwIntStat{}, base.SgwIntStat{}, base.SgwIntStat{}, base.SgwIntStat{}, base.SgwIntStat{}, base.SgwIntStat{}
backingStoreMap := CreateTestSingleBackingStoreMap(&testBackingStore{nil, &getDocumentCounter, &getRevisionCounter}, testCollectionID)
cacheOptions := &RevisionCacheOptions{
MaxItemCount: 1,
MaxBytes: 0, // turn off memory based eviction
}
ctx := base.TestCtx(t)
cache := NewLRURevisionCache(cacheOptions, backingStoreMap, &cacheHitCounter, &cacheMissCounter, &cacheNumItems, &memoryBytesCounted)
// load up item to hit max capacity
cache.Put(ctx, DocumentRevision{BodyBytes: []byte(`{"some":"test"}`), DocID: "doc1", RevID: "1-abc", History: Revisions{"start": 1}}, testCollectionID)

// eviction starts from here in test
cache.Put(ctx, DocumentRevision{BodyBytes: []byte(`{"some":"test"}`), DocID: "newDoc", RevID: "1-abc", History: Revisions{"start": 1}}, testCollectionID)

assert.Equal(t, int64(15), memoryBytesCounted.Value())
assert.Equal(t, int64(1), cacheNumItems.Value())

cache.Upsert(ctx, DocumentRevision{BodyBytes: []byte(`{"some":"test"}`), DocID: "doc2", RevID: "1-abc", History: Revisions{"start": 1}}, testCollectionID)

assert.Equal(t, int64(15), memoryBytesCounted.Value())
assert.Equal(t, int64(1), cacheNumItems.Value())

docRev, err := cache.Get(ctx, "doc3", "1-abc", testCollectionID, RevCacheOmitDelta)
require.NoError(t, err)
assert.NotNil(t, docRev.BodyBytes)

assert.Equal(t, int64(102), memoryBytesCounted.Value())
assert.Equal(t, int64(1), cacheNumItems.Value())

docRev, err = cache.GetActive(ctx, "doc4", testCollectionID)
require.NoError(t, err)
assert.NotNil(t, docRev.BodyBytes)

assert.Equal(t, int64(102), memoryBytesCounted.Value())
assert.Equal(t, int64(1), cacheNumItems.Value())
}

func TestResetRevCache(t *testing.T) {
dbcOptions := DatabaseContextOptions{
RevisionCacheOptions: &RevisionCacheOptions{
MaxBytes: 100,
MaxItemCount: 10,
},
}
db, ctx := SetupTestDBWithOptions(t, dbcOptions)
defer db.Close(ctx)
collection, ctx := GetSingleDatabaseCollectionWithUser(ctx, t, db)
cacheStats := db.DbStats.Cache()

// add a doc
docSize, _ := createDocAndReturnSizeAndRev(t, ctx, "doc1", collection, Body{"test": "doc"})
assert.Equal(t, int64(docSize), cacheStats.RevisionCacheTotalMemory.Value())
assert.Equal(t, int64(1), cacheStats.RevisionCacheNumItems.Value())

// re create rev cache
db.FlushRevisionCacheForTest()

// assert rev cache is reset as expected
assert.Equal(t, int64(0), cacheStats.RevisionCacheTotalMemory.Value())
assert.Equal(t, int64(0), cacheStats.RevisionCacheNumItems.Value())
}

func TestBasicOperationsOnCacheWithMemoryStat(t *testing.T) {
dbcOptions := DatabaseContextOptions{
RevisionCacheOptions: &RevisionCacheOptions{
Expand Down

0 comments on commit 2583f2b

Please sign in to comment.