lib/storage: reduce memory allocations when syncing dateMetricIDCache

This commit is contained in:
Aliaksandr Valialkin 2021-06-03 16:19:58 +03:00
parent 8d2553e6a1
commit fc2565b4ee
2 changed files with 49 additions and 23 deletions

View File

@ -2031,24 +2031,28 @@ type dateMetricIDCache struct {
byDate atomic.Value byDate atomic.Value
// Contains mutable map protected by mu // Contains mutable map protected by mu
byDateMutable *byDateMetricIDMap byDateMutable *byDateMetricIDMap
lastSyncTime uint64 nextSyncDeadline uint64
mu sync.Mutex mu sync.Mutex
} }
func newDateMetricIDCache() *dateMetricIDCache { func newDateMetricIDCache() *dateMetricIDCache {
var dmc dateMetricIDCache var dmc dateMetricIDCache
dmc.Reset() dmc.resetLocked()
return &dmc return &dmc
} }
func (dmc *dateMetricIDCache) Reset() { func (dmc *dateMetricIDCache) Reset() {
dmc.mu.Lock() dmc.mu.Lock()
dmc.resetLocked()
dmc.mu.Unlock()
}
func (dmc *dateMetricIDCache) resetLocked() {
// Do not reset syncsCount and resetsCount // Do not reset syncsCount and resetsCount
dmc.byDate.Store(newByDateMetricIDMap()) dmc.byDate.Store(newByDateMetricIDMap())
dmc.byDateMutable = newByDateMetricIDMap() dmc.byDateMutable = newByDateMetricIDMap()
dmc.lastSyncTime = fasttime.UnixTimestamp() dmc.nextSyncDeadline = 10 + fasttime.UnixTimestamp()
dmc.mu.Unlock()
atomic.AddUint64(&dmc.resetsCount, 1) atomic.AddUint64(&dmc.resetsCount, 1)
} }
@ -2081,20 +2085,12 @@ func (dmc *dateMetricIDCache) Has(date, metricID uint64) bool {
} }
// Slow path. Check mutable map. // Slow path. Check mutable map.
currentTime := fasttime.UnixTimestamp()
dmc.mu.Lock() dmc.mu.Lock()
v = dmc.byDateMutable.get(date) v = dmc.byDateMutable.get(date)
ok := v.Has(metricID) ok := v.Has(metricID)
mustSync := false dmc.syncLockedIfNeeded()
if currentTime-dmc.lastSyncTime > 10 {
mustSync = true
dmc.lastSyncTime = currentTime
}
dmc.mu.Unlock() dmc.mu.Unlock()
if mustSync {
dmc.sync()
}
return ok return ok
} }
@ -2133,21 +2129,47 @@ func (dmc *dateMetricIDCache) Set(date, metricID uint64) {
dmc.mu.Unlock() dmc.mu.Unlock()
} }
func (dmc *dateMetricIDCache) sync() { func (dmc *dateMetricIDCache) syncLockedIfNeeded() {
dmc.mu.Lock() currentTime := fasttime.UnixTimestamp()
if currentTime >= dmc.nextSyncDeadline {
dmc.nextSyncDeadline = currentTime + 10
dmc.syncLocked()
}
}
func (dmc *dateMetricIDCache) syncLocked() {
if len(dmc.byDateMutable.m) == 0 {
// Nothing to sync.
return
}
byDate := dmc.byDate.Load().(*byDateMetricIDMap) byDate := dmc.byDate.Load().(*byDateMetricIDMap)
for date, e := range dmc.byDateMutable.m { byDateMutable := dmc.byDateMutable
for date, e := range byDateMutable.m {
v := byDate.get(date) v := byDate.get(date)
e.v.Union(v) if v == nil {
continue
}
v = v.Clone()
v.Union(&e.v)
byDateMutable.m[date] = &byDateMetricIDEntry{
date: date,
v: *v,
}
}
for date, e := range byDate.m {
v := byDateMutable.get(date)
if v != nil {
continue
}
byDateMutable.m[date] = e
} }
dmc.byDate.Store(dmc.byDateMutable) dmc.byDate.Store(dmc.byDateMutable)
dmc.byDateMutable = newByDateMetricIDMap() dmc.byDateMutable = newByDateMetricIDMap()
dmc.mu.Unlock()
atomic.AddUint64(&dmc.syncsCount, 1) atomic.AddUint64(&dmc.syncsCount, 1)
if dmc.EntriesCount() > memory.Allowed()/128 { if dmc.EntriesCount() > memory.Allowed()/128 {
dmc.Reset() dmc.resetLocked()
} }
} }

View File

@ -89,7 +89,9 @@ func testDateMetricIDCache(c *dateMetricIDCache, concurrent bool) error {
return fmt.Errorf("c.Has(%d, %d) must return true, but returned false", date, metricID) return fmt.Errorf("c.Has(%d, %d) must return true, but returned false", date, metricID)
} }
if i%11234 == 0 { if i%11234 == 0 {
c.sync() c.mu.Lock()
c.syncLocked()
c.mu.Unlock()
} }
if i%34323 == 0 { if i%34323 == 0 {
c.Reset() c.Reset()
@ -103,7 +105,9 @@ func testDateMetricIDCache(c *dateMetricIDCache, concurrent bool) error {
metricID := uint64(i) % 123 metricID := uint64(i) % 123
c.Set(date, metricID) c.Set(date, metricID)
} }
c.sync() c.mu.Lock()
c.syncLocked()
c.mu.Unlock()
for i := 0; i < 1e5; i++ { for i := 0; i < 1e5; i++ {
date := uint64(i) % 3 date := uint64(i) % 3
metricID := uint64(i) % 123 metricID := uint64(i) % 123