From 431aa16c8de4f36ece730edced4117243f141c80 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Mon, 29 Jan 2024 18:42:45 +0100 Subject: [PATCH] lib/storage: keep (date, metricID) entries only for the last two dates Entries for the previous dates is usually not used, so there is little sense in keeping them in memory. This should reduce the size of storage/date_metricID cache, which can be monitored via vm_cache_entries{type="storage/date_metricID"} metric. --- lib/storage/storage.go | 25 +++++++++++++++++++++---- lib/storage/storage_test.go | 6 +++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/storage/storage.go b/lib/storage/storage.go index 59156badc1..ec3a7ce3a6 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 80303cdace..09fe564860 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)