(ctx context.Context)
| 894 | } |
| 895 | |
| 896 | func (rc *LRURevisionCache) evictBasedOffMemoryUsage(ctx context.Context) int64 { |
| 897 | var numItemsRemoved, numBytesRemoved int64 |
| 898 | rc.lock.Lock() |
| 899 | defer rc.lock.Unlock() |
| 900 | // check if we are over memory capacity after holding rev cache mutex (protect against another goroutine evicting whilst waiting for mutex above) |
| 901 | if currMemoryUsage := rc.currMemoryUsage.Value(); currMemoryUsage > rc.memoryCapacity { |
| 902 | // find amount of bytes needed to evict till below threshold |
| 903 | bytesNeededToRemove := currMemoryUsage - rc.memoryCapacity |
| 904 | for bytesNeededToRemove > numBytesRemoved { |
| 905 | value := rc._findEvictionValue() |
| 906 | if value == nil { |
| 907 | if rc.lruList.Len() > 0 { |
| 908 | // no more values ready for eviction |
| 909 | break |
| 910 | } else { |
| 911 | // list is empty, nothing more to evict but stats are wrong so zero stats and return |
| 912 | base.DebugfCtx(ctx, base.KeyCache, "Revision cache memory stats inconsistent for this shard, resetting to zero") |
| 913 | correctionVal := rc.currMemoryUsage.Value() |
| 914 | // Correct overall memory stat across shards to remove this shards memory usage, and set this shard to zero |
| 915 | rc.cacheMemoryBytesStat.Add(-correctionVal) |
| 916 | rc.currMemoryUsage.Set(0) |
| 917 | return numItemsRemoved |
| 918 | } |
| 919 | } |
| 920 | revKey := IDAndRev{DocID: value.id, RevID: value.revID, CollectionID: value.collectionID} |
| 921 | hlvKey := IDandCV{DocID: value.id, Source: value.cv.SourceID, Version: value.cv.Value, CollectionID: value.collectionID} |
| 922 | // same below but for hlv lookup map |
| 923 | if elem := rc.hlvCache[hlvKey]; elem != nil { |
| 924 | revValue := elem.Value.(*revCacheValue) |
| 925 | // we need to check if the value pointed to by the cv lookup map is the same value we're evicting, this is |
| 926 | // because we can currently have two items with the same docID and CV, but different revIDs due to |
| 927 | // local wins conflict resolution not generating a new CV but generating a new revID. |
| 928 | if revValue.revID == value.revID { |
| 929 | // this cv lookup item matches the value we're evicting, so remove it |
| 930 | delete(rc.hlvCache, hlvKey) |
| 931 | } |
| 932 | } |
| 933 | if elem := rc.cache[revKey]; elem != nil { |
| 934 | revValue := elem.Value.(*revCacheValue) |
| 935 | // we need to check if the value pointed to by the rev lookup map is the same value we're evicting, this is |
| 936 | // because we can have can currently have two items with the same docID and revID, but different CVs due to |
| 937 | // a new HLV being generated for user xattr updates where we don't generate a new revID. |
| 938 | if revValue.cv.String() == value.cv.String() { |
| 939 | // this rev lookup item matches the value we're evicting, so remove it |
| 940 | delete(rc.cache, revKey) |
| 941 | } |
| 942 | } |
| 943 | numItemsRemoved++ |
| 944 | valueBytes := value.getItemBytes() |
| 945 | numBytesRemoved += valueBytes |
| 946 | } |
| 947 | } |
| 948 | rc._decrRevCacheMemoryUsage(ctx, -numBytesRemoved) // need update rev cache memory stats before release lock to stop other goroutines evicting based on outdated stats |
| 949 | return numItemsRemoved |
| 950 | } |
| 951 | |
| 952 | // _decrRevCacheMemoryUsage atomically decreases overall memory usage for cache and the actual rev cache objects usage. |
| 953 | // You should be holding rev cache lock in using this function to avoid eviction processes over evicting items |
no test coverage detected