mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-23 12:31:07 +01:00
lib/bytesutil: make sure that the cleanup code is performed only by a single goroutine out of many concurrently running goroutines
Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3466
This commit is contained in:
parent
0f8ffc7df9
commit
3300546eab
@ -62,10 +62,8 @@ func (fsm *FastStringMatcher) Match(s string) bool {
|
||||
s = strings.Clone(s)
|
||||
fsm.m.Store(s, e)
|
||||
|
||||
if atomic.LoadUint64(&fsm.lastCleanupTime)+61 < ct {
|
||||
// Perform a global cleanup for fsm.m by removing items, which weren't accessed
|
||||
// during the last 5 minutes.
|
||||
atomic.StoreUint64(&fsm.lastCleanupTime, ct)
|
||||
if needCleanup(&fsm.lastCleanupTime, ct) {
|
||||
// Perform a global cleanup for fsm.m by removing items, which weren't accessed during the last 5 minutes.
|
||||
m := &fsm.m
|
||||
m.Range(func(k, v interface{}) bool {
|
||||
e := v.(*fsmEntry)
|
||||
@ -78,3 +76,14 @@ func (fsm *FastStringMatcher) Match(s string) bool {
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func needCleanup(lastCleanupTime *uint64, currentTime uint64) bool {
|
||||
lct := atomic.LoadUint64(lastCleanupTime)
|
||||
if lct+61 >= currentTime {
|
||||
return false
|
||||
}
|
||||
// Atomically compare and swap the current time with the lastCleanupTime
|
||||
// in order to guarantee that only a single goroutine out of multiple
|
||||
// concurrently executing goroutines gets true from the call.
|
||||
return atomic.CompareAndSwapUint64(lastCleanupTime, lct, currentTime)
|
||||
}
|
||||
|
@ -23,3 +23,27 @@ func TestFastStringMatcher(t *testing.T) {
|
||||
f("a_b-C", false)
|
||||
f("foobar", true)
|
||||
}
|
||||
|
||||
func TestNeedCleanup(t *testing.T) {
|
||||
f := func(lastCleanupTime, currentTime uint64, resultExpected bool) {
|
||||
t.Helper()
|
||||
lct := lastCleanupTime
|
||||
result := needCleanup(&lct, currentTime)
|
||||
if result != resultExpected {
|
||||
t.Fatalf("unexpected result for needCleanup(%d, %d); got %v; want %v", lastCleanupTime, currentTime, result, resultExpected)
|
||||
}
|
||||
if result {
|
||||
if lct != currentTime {
|
||||
t.Fatalf("unexpected value for lct; got %d; want currentTime=%d", lct, currentTime)
|
||||
}
|
||||
} else {
|
||||
if lct != lastCleanupTime {
|
||||
t.Fatalf("unexpected value for lct; got %d; want lastCleanupTime=%d", lct, lastCleanupTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
f(0, 0, false)
|
||||
f(0, 61, false)
|
||||
f(0, 62, true)
|
||||
f(10, 100, true)
|
||||
}
|
||||
|
@ -67,10 +67,8 @@ func (fst *FastStringTransformer) Transform(s string) string {
|
||||
}
|
||||
fst.m.Store(s, e)
|
||||
|
||||
if atomic.LoadUint64(&fst.lastCleanupTime)+61 < ct {
|
||||
// Perform a global cleanup for fst.m by removing items, which weren't accessed
|
||||
// during the last 5 minutes.
|
||||
atomic.StoreUint64(&fst.lastCleanupTime, ct)
|
||||
if needCleanup(&fst.lastCleanupTime, ct) {
|
||||
// Perform a global cleanup for fst.m by removing items, which weren't accessed during the last 5 minutes.
|
||||
m := &fst.m
|
||||
m.Range(func(k, v interface{}) bool {
|
||||
e := v.(*fstEntry)
|
||||
|
@ -30,10 +30,8 @@ func InternString(s string) string {
|
||||
}
|
||||
internStringsMap.Store(sCopy, e)
|
||||
|
||||
if atomic.LoadUint64(&internStringsMapLastCleanupTime)+61 < ct {
|
||||
// Perform a global cleanup for internStringsMap by removing items, which weren't accessed
|
||||
// during the last 5 minutes.
|
||||
atomic.StoreUint64(&internStringsMapLastCleanupTime, ct)
|
||||
if needCleanup(&internStringsMapLastCleanupTime, ct) {
|
||||
// Perform a global cleanup for internStringsMap by removing items, which weren't accessed during the last 5 minutes.
|
||||
m := &internStringsMap
|
||||
m.Range(func(k, v interface{}) bool {
|
||||
e := v.(*ismEntry)
|
||||
|
Loading…
Reference in New Issue
Block a user