mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-20 06:28:13 +00:00
fix(memory, connection): two data-race/counter defects
1) connection_pool.go: GetConnectionStats read lastRecoveryAttempt (a multi-word time.Time) without any lock while checkAndRecover wrote it under recoveryMutex -> data race on live admin API endpoints. Snapshot it under recoveryMutex (the writer's lock). Regression test TestGetConnectionStatsRace drives the read path concurrent with the locked write under -race. 2) cache/memory memory.go: Cache.Get expired path used an unconditional Delete + atomic decrement, so concurrent Gets on the same expired entry each decremented entryCount/memoryUsage -> permanent negative drift. Use LoadAndDelete-with-guard (as evictOldest/evictToFreeMemory already do) so only the goroutine that actually removes the entry decrements. Regression test TestMemoryCacheConcurrentGetOnExpiredEntry_CountersConsistent.
This commit is contained in:
@@ -262,6 +262,38 @@ func (suite *ConnectionPoolTestSuite) TestRaceConditions() {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (suite *ConnectionPoolTestSuite) TestGetConnectionStatsRace() {
|
||||
// GetConnectionStats must be safe to call concurrently with the recovery
|
||||
// task, which writes lastRecoveryAttempt under recoveryMutex. Regression
|
||||
// test for the data race between GetConnectionStats reading
|
||||
// lastRecoveryAttempt and checkAndRecover writing it.
|
||||
client := &fasthttp.Client{MaxConnsPerHost: 100}
|
||||
cpm := NewConnectionPoolManager(client)
|
||||
defer cpm.Shutdown()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for range 4 {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for range 200 {
|
||||
_ = cpm.GetConnectionStats()
|
||||
}
|
||||
}()
|
||||
}
|
||||
// Writer mirrors checkAndRecover's locked write of lastRecoveryAttempt.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for range 200 {
|
||||
cpm.recoveryMutex.Lock()
|
||||
cpm.lastRecoveryAttempt = time.Now()
|
||||
cpm.recoveryMutex.Unlock()
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (suite *ConnectionPoolTestSuite) TestCleanupWithNilLogger() {
|
||||
// Test cleanup when cfg or logger is nil
|
||||
origCfg := cfg
|
||||
|
||||
Reference in New Issue
Block a user