diff --git a/lib/storage/storage.go b/lib/storage/storage.go index 59156badc..ec3a7ce3a 100644 --- a/lib/storage/storage.go +++ b/lib/storage/storage.go @@ -2352,6 +2352,8 @@ func (dmc *dateMetricIDCache) syncLocked() { // Merge data from byDate into byDateMutable and then atomically replace byDate with the merged data. byDate := dmc.byDate.Load() byDateMutable := dmc.byDateMutable + byDateMutable.hotEntry.Store(&byDateMetricIDEntry{}) + for k, e := range byDateMutable.m { v := byDate.get(k.generation, k.date) if v == nil { @@ -2365,11 +2367,8 @@ func (dmc *dateMetricIDCache) syncLocked() { v: *v, } byDateMutable.m[k] = dme - he := byDateMutable.hotEntry.Load() - if he.k == k { - byDateMutable.hotEntry.Store(dme) - } } + // Copy entries from byDate, which are missing in byDateMutable for k, e := range byDate.m { v := byDateMutable.get(k.generation, k.date) @@ -2379,6 +2378,24 @@ func (dmc *dateMetricIDCache) syncLocked() { byDateMutable.m[k] = e } + if len(byDateMutable.m) > 2 { + // Keep only entries for the last two dates - these are usually + // the current date and the next date. + dates := make([]uint64, 0, len(byDateMutable.m)) + for k := range byDateMutable.m { + dates = append(dates, k.date) + } + sort.Slice(dates, func(i, j int) bool { + return dates[i] < dates[j] + }) + maxDate := dates[len(dates)-2] + for k := range byDateMutable.m { + if k.date < maxDate { + delete(byDateMutable.m, k) + } + } + } + // Atomically replace byDate with byDateMutable dmc.byDate.Store(dmc.byDateMutable) dmc.byDateMutable = newByDateMetricIDMap() diff --git a/lib/storage/storage_test.go b/lib/storage/storage_test.go index 80303cdac..09fe56486 100644 --- a/lib/storage/storage_test.go +++ b/lib/storage/storage_test.go @@ -98,7 +98,7 @@ func testDateMetricIDCache(c *dateMetricIDCache, concurrent bool) error { m := make(map[dmk]bool) for i := 0; i < 1e5; i++ { generation := uint64(i) % 2 - date := uint64(i) % 3 + date := uint64(i) % 2 metricID := uint64(i) % 1237 if !concurrent && c.Has(generation, date, metricID) { if !m[dmk{generation, date, metricID}] { @@ -127,7 +127,7 @@ func testDateMetricIDCache(c *dateMetricIDCache, concurrent bool) error { // Verify fast path after sync. for i := 0; i < 1e5; i++ { generation := uint64(i) % 2 - date := uint64(i) % 3 + date := uint64(i) % 2 metricID := uint64(i) % 123 c.Set(generation, date, metricID) } @@ -136,7 +136,7 @@ func testDateMetricIDCache(c *dateMetricIDCache, concurrent bool) error { c.mu.Unlock() for i := 0; i < 1e5; i++ { generation := uint64(i) % 2 - date := uint64(i) % 3 + date := uint64(i) % 2 metricID := uint64(i) % 123 if !concurrent && !c.Has(generation, date, metricID) { return fmt.Errorf("c.Has(%d, %d, %d) must return true after sync", generation, date, metricID)