frostfs-node/pkg/local_object_storage/writecache/state.go
Aleksey Savchuk b28e45f5a4
All checks were successful
DCO action / DCO (pull_request) Successful in 51s
Vulncheck / Vulncheck (pull_request) Successful in 1m1s
Build / Build Components (pull_request) Successful in 1m45s
Tests and linters / Lint (pull_request) Successful in 2m26s
Tests and linters / Run gofumpt (pull_request) Successful in 2m37s
Tests and linters / Tests (pull_request) Successful in 2m51s
Tests and linters / Staticcheck (pull_request) Successful in 3m13s
Tests and linters / Tests with -race (pull_request) Successful in 3m26s
Tests and linters / gopls check (pull_request) Successful in 4m13s
Pre-commit hooks / Pre-commit (pull_request) Successful in 1m13s
[#1648] writecache: Fix race condition when reporting cache size metrics
There is a race condition when multiple cache operation try to report
the cache size metrics simultaneously. Consider the following example:
- the initial total size of objects stored in the cache size is 2
- worker X deletes an object and reads the cache size, which is 1
- worker Y deletes an object and reads the cache size, which is 0
- worker Y reports the cache size it learnt, which is 0
- worker X reports the cache size it learnt, which is 1

As a result, the observed cache size is 1 (i. e. one object remains
in the cache), which is incorrect because the actual cache size is 0.

To fix this, a separate worker for reporting the cache size metric has
been created. All operations should use a queue (a buffered channel) to
request the reporter worker to report the metrics. Currently, all queue
writes are non-blocking.

Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
2025-02-18 13:39:39 +03:00

26 lines
565 B
Go

package writecache
func (c *cache) estimateCacheSize() (uint64, uint64) {
count, size := c.counter.CountSize()
select {
case c.sizeMetricsReporterQueue <- struct{}{}:
default:
}
return count, size
}
func (c *cache) hasEnoughSpaceFS() bool {
return c.hasEnoughSpace(c.maxObjectSize)
}
func (c *cache) hasEnoughSpace(objectSize uint64) bool {
count, size := c.estimateCacheSize()
if c.maxCacheCount > 0 && count+1 > c.maxCacheCount {
return false
}
return c.maxCacheSize >= size+objectSize
}
func (c *cache) initCounters() {
c.estimateCacheSize()
}