From 50b6d6890d0d39083645388c590327e67871039a Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Thu, 31 Aug 2023 12:23:34 -0300 Subject: [PATCH 1/9] pointed to flagSet redis storage support --- CHANGES.txt | 3 +++ go.mod | 4 ++-- go.sum | 8 ++++---- splitio/commitversion.go | 2 +- splitio/version.go | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index c6a00fa7..6a00f353 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +5.5.0 (Month XX, 2023) +- FlagSet + 5.4.0 (July 18, 2023) - Improved streaming architecture implementation to apply feature flag updates from the notification received which is now enhanced, improving efficiency and reliability of the whole update system. - Fixed possible edge case issue where deleting a feature flag doesn’t propagate immediately. diff --git a/go.mod b/go.mod index 908d8a86..cc89e00e 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 github.com/splitio/gincache v1.0.1 - github.com/splitio/go-split-commons/v5 v5.0.0 - github.com/splitio/go-toolkit/v5 v5.3.1 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20230830213316-5611920d2742 + github.com/splitio/go-toolkit/v5 v5.3.2-0.20230830210316-76db3ef04f28 go.etcd.io/bbolt v1.3.6 ) diff --git a/go.sum b/go.sum index bbe5b69d..cafcd079 100644 --- a/go.sum +++ b/go.sum @@ -87,10 +87,10 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/splitio/gincache v1.0.1 h1:dLYdANY/BqH4KcUMCe/LluLyV5WtuE/LEdQWRE06IXU= github.com/splitio/gincache v1.0.1/go.mod h1:CcgJDSM9Af75kyBH0724v55URVwMBuSj5x1eCWIOECY= -github.com/splitio/go-split-commons/v5 v5.0.0 h1:bGRi0cf1JP5VNSi0a4BPQEWv/DACkeSKliazhPMVDPk= -github.com/splitio/go-split-commons/v5 v5.0.0/go.mod h1:lzoVmYJaCqB8UPSxWva0BZe7fF+bRJD+eP0rNi/lL7c= -github.com/splitio/go-toolkit/v5 v5.3.1 h1:9J/byd0fRxWj5/Zg0QZOnUxKBDIAMCGr7rySYzJKdJg= -github.com/splitio/go-toolkit/v5 v5.3.1/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20230830213316-5611920d2742 h1:uIbbdmCX1oNdCYuWgXNxklncDC1afEE46slmbXR+vO0= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20230830213316-5611920d2742/go.mod h1:MZmhMhKXnHzf6gic0fyRaaDAh7h/lDx5wVVQ3I5FeIM= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20230830210316-76db3ef04f28 h1:Uj2rPOBbYvHt/NrMFpde1aFuBJOl+Unyc5SwLbPJ5aI= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20230830210316-76db3ef04f28/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/splitio/commitversion.go b/splitio/commitversion.go index 47b58123..c0c5b04e 100644 --- a/splitio/commitversion.go +++ b/splitio/commitversion.go @@ -5,4 +5,4 @@ This file is created automatically, please do not edit */ // CommitVersion is the version of the last commit previous to release -const CommitVersion = "da63b9f" +const CommitVersion = "18b8201" diff --git a/splitio/version.go b/splitio/version.go index 84a70c52..089f9cc9 100644 --- a/splitio/version.go +++ b/splitio/version.go @@ -2,4 +2,4 @@ package splitio // Version is the version of this Agent -const Version = "5.4.0" +const Version = "5.5.0-rc1" From 9ed4ca598a974f47b888ca26fdfdb9676bc4cf1b Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Wed, 4 Oct 2023 15:52:57 -0300 Subject: [PATCH 2/9] added flagSetsFilter for producer --- go.mod | 4 ++-- go.sum | 8 ++++---- splitio/commitversion.go | 2 +- splitio/producer/conf/sections.go | 1 + splitio/producer/initialization.go | 9 +++++++-- splitio/proxy/caching/workers.go | 4 +++- splitio/proxy/conf/sections.go | 1 + splitio/proxy/initialization.go | 10 ++++++++-- splitio/proxy/storage/splits.go | 5 +++-- splitio/proxy/storage/splits_test.go | 3 ++- 10 files changed, 32 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index cc89e00e..87a92710 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 github.com/splitio/gincache v1.0.1 - github.com/splitio/go-split-commons/v5 v5.0.1-0.20230830213316-5611920d2742 - github.com/splitio/go-toolkit/v5 v5.3.2-0.20230830210316-76db3ef04f28 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231004184048-81902536fc1f + github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a go.etcd.io/bbolt v1.3.6 ) diff --git a/go.sum b/go.sum index cafcd079..3b99efc6 100644 --- a/go.sum +++ b/go.sum @@ -87,10 +87,10 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/splitio/gincache v1.0.1 h1:dLYdANY/BqH4KcUMCe/LluLyV5WtuE/LEdQWRE06IXU= github.com/splitio/gincache v1.0.1/go.mod h1:CcgJDSM9Af75kyBH0724v55URVwMBuSj5x1eCWIOECY= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20230830213316-5611920d2742 h1:uIbbdmCX1oNdCYuWgXNxklncDC1afEE46slmbXR+vO0= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20230830213316-5611920d2742/go.mod h1:MZmhMhKXnHzf6gic0fyRaaDAh7h/lDx5wVVQ3I5FeIM= -github.com/splitio/go-toolkit/v5 v5.3.2-0.20230830210316-76db3ef04f28 h1:Uj2rPOBbYvHt/NrMFpde1aFuBJOl+Unyc5SwLbPJ5aI= -github.com/splitio/go-toolkit/v5 v5.3.2-0.20230830210316-76db3ef04f28/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231004184048-81902536fc1f h1:g3rsXA0cdMx2uz3MrTEz2tiittf+HDXpHooyYnuYg6w= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231004184048-81902536fc1f/go.mod h1:ksVZQYLs+3ZuzU81vEvf1aCjk24pdrVWjUXNq6Qcayo= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a h1:2wjh5hSGlFRuh6Lbmodr0VRqtry2m9pEBNmwiLsY+ss= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/splitio/commitversion.go b/splitio/commitversion.go index c0c5b04e..fe49404a 100644 --- a/splitio/commitversion.go +++ b/splitio/commitversion.go @@ -5,4 +5,4 @@ This file is created automatically, please do not edit */ // CommitVersion is the version of the last commit previous to release -const CommitVersion = "18b8201" +const CommitVersion = "50b6d68" diff --git a/splitio/producer/conf/sections.go b/splitio/producer/conf/sections.go index 32808ab6..ba26d57e 100644 --- a/splitio/producer/conf/sections.go +++ b/splitio/producer/conf/sections.go @@ -9,6 +9,7 @@ import ( type Main struct { Apikey string `json:"apikey" s-cli:"apikey" s-def:"" s-desc:"Split server side SDK key"` IPAddressEnabled bool `json:"ipAddressEnabled" s-cli:"ip-address-enabled" s-def:"true" s-desc:"Bundle host's ip address when sending data to Split"` + FlagSetsFilter []string `json:"flagSetsFilter" s-cli:"flag-sets-filter" s-def:"" s-desc:"Flag Sets Filter provided"` Initialization Initialization `json:"initialization" s-nested:"true"` Storage Storage `json:"storage" s-nested:"true"` Sync Sync `json:"sync" s-nested:"true"` diff --git a/splitio/producer/initialization.go b/splitio/producer/initialization.go index 532953b7..48fe4b9c 100644 --- a/splitio/producer/initialization.go +++ b/splitio/producer/initialization.go @@ -7,6 +7,7 @@ import ( cconf "github.com/splitio/go-split-commons/v5/conf" "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/provisional/strategy" "github.com/splitio/go-split-commons/v5/service/api" "github.com/splitio/go-split-commons/v5/storage/filter" @@ -46,6 +47,7 @@ const ( func Start(logger logging.LoggerInterface, cfg *conf.Main) error { // Getting initial config data advanced := cfg.BuildAdvancedConfig() + advanced.FlagSetsFilter = cfg.FlagSetsFilter metadata := util.GetMetadata(false, cfg.IPAddressEnabled) clientKey, err := util.GetClientKey(cfg.Apikey) @@ -84,8 +86,11 @@ func Start(logger logging.LoggerInterface, cfg *conf.Main) error { syncTelemetryStorage, _ := inmemory.NewTelemetryStorage() sdkTelemetryStorage := storage.NewRedisTelemetryCosumerclient(redisClient, logger) + // FlagSetsFilter + flagSetsFilter := flagsets.NewFlagSetFilter(cfg.FlagSetsFilter) + // These storages are forwarded to the dashboard, the sdk-telemetry is irrelevant there - splitStorage, err := observability.NewObservableSplitStorage(redis.NewSplitStorage(redisClient, logger), logger) + splitStorage, err := observability.NewObservableSplitStorage(redis.NewSplitStorage(redisClient, logger, flagSetsFilter), logger) if err != nil { return fmt.Errorf("error instantiating observable feature flag storage: %w", err) } @@ -118,7 +123,7 @@ func Start(logger logging.LoggerInterface, cfg *conf.Main) error { eventEvictionMonitor := evcalc.New(1) workers := synchronizer.Workers{ - SplitUpdater: split.NewSplitUpdater(storages.SplitStorage, splitAPI.SplitFetcher, logger, syncTelemetryStorage, appMonitor), + SplitUpdater: split.NewSplitUpdater(storages.SplitStorage, splitAPI.SplitFetcher, logger, syncTelemetryStorage, appMonitor, flagSetsFilter), SegmentUpdater: segment.NewSegmentUpdater(storages.SplitStorage, storages.SegmentStorage, splitAPI.SegmentFetcher, logger, syncTelemetryStorage, appMonitor), ImpressionsCountRecorder: impressionscount.NewRecorderSingle(impressionsCounter, splitAPI.ImpressionRecorder, diff --git a/splitio/proxy/caching/workers.go b/splitio/proxy/caching/workers.go index cc4bff18..ea002998 100644 --- a/splitio/proxy/caching/workers.go +++ b/splitio/proxy/caching/workers.go @@ -2,6 +2,7 @@ package caching import ( "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/healthcheck/application" "github.com/splitio/go-split-commons/v5/service" "github.com/splitio/go-split-commons/v5/storage" @@ -27,9 +28,10 @@ func NewCacheAwareSplitSync( runtimeTelemetry storage.TelemetryRuntimeProducer, cacheFlusher gincache.CacheFlusher, appMonitor application.MonitorProducerInterface, + flagSetsFilter flagsets.FlagSetFilter, ) *CacheAwareSplitSynchronizer { return &CacheAwareSplitSynchronizer{ - wrapped: split.NewSplitUpdater(splitStorage, splitFetcher, logger, runtimeTelemetry, appMonitor), + wrapped: split.NewSplitUpdater(splitStorage, splitFetcher, logger, runtimeTelemetry, appMonitor, flagSetsFilter), splitStorage: splitStorage, cacheFlusher: cacheFlusher, } diff --git a/splitio/proxy/conf/sections.go b/splitio/proxy/conf/sections.go index 204720f5..8deef0e8 100644 --- a/splitio/proxy/conf/sections.go +++ b/splitio/proxy/conf/sections.go @@ -9,6 +9,7 @@ import ( type Main struct { Apikey string `json:"apikey" s-cli:"apikey" s-def:"" s-desc:"Split server side SDK key"` IPAddressEnabled bool `json:"ipAddressEnabled" s-cli:"ip-address-enabled" s-def:"true" s-desc:"Bundle host's ip address when sending data to Split"` + FlagSetsFilter []string `json:"flagSetsFilter" s-cli:"flag-sets-filter" s-def:"" s-desc:"Flag Sets Filter provided"` Initialization Initialization `json:"initialization" s-nested:"true"` Server Server `json:"server" s-nested:"true"` Admin conf.Admin `json:"admin" s-nested:"true"` diff --git a/splitio/proxy/initialization.go b/splitio/proxy/initialization.go index 8b4ec7f5..267200ea 100644 --- a/splitio/proxy/initialization.go +++ b/splitio/proxy/initialization.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/splitio/go-split-commons/v5/conf" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/service/api" "github.com/splitio/go-split-commons/v5/synchronizer" "github.com/splitio/go-split-commons/v5/tasks" @@ -70,13 +71,18 @@ func Start(logger logging.LoggerInterface, cfg *pconf.Main) error { // Getting initial config data advanced := cfg.BuildAdvancedConfig() + // advanced.FlagSetsFilter = cfg.FlagSetsFilter + advanced.FlagSetsFilter = make([]string, 0) metadata := util.GetMetadata(cfg.IPAddressEnabled, true) + // FlagSetsFilter + flagSetsFilter := flagsets.NewFlagSetFilter(cfg.FlagSetsFilter) + // Setup fetchers & recorders splitAPI := api.NewSplitAPI(cfg.Apikey, *advanced, logger, metadata) // Proxy storages already implement the observable interface, so no need to wrap them - splitStorage := storage.NewProxySplitStorage(dbInstance, logger, cfg.Initialization.Snapshot != "") + splitStorage := storage.NewProxySplitStorage(dbInstance, logger, cfg.Initialization.Snapshot != "", flagsets.NewFlagSetFilter(nil)) segmentStorage := storage.NewProxySegmentStorage(dbInstance, logger, cfg.Initialization.Snapshot != "") // Local telemetry @@ -112,7 +118,7 @@ func Start(logger logging.LoggerInterface, cfg *pconf.Main) error { // setup feature flags, segments & local telemetry API interactions workers := synchronizer.Workers{ - SplitUpdater: caching.NewCacheAwareSplitSync(splitStorage, splitAPI.SplitFetcher, logger, localTelemetryStorage, httpCache, appMonitor), + SplitUpdater: caching.NewCacheAwareSplitSync(splitStorage, splitAPI.SplitFetcher, logger, localTelemetryStorage, httpCache, appMonitor, flagSetsFilter), SegmentUpdater: caching.NewCacheAwareSegmentSync(splitStorage, segmentStorage, splitAPI.SegmentFetcher, logger, localTelemetryStorage, httpCache, appMonitor), TelemetryRecorder: telemetry.NewTelemetrySynchronizer(localTelemetryStorage, telemetryRecorder, splitStorage, segmentStorage, logger, diff --git a/splitio/proxy/storage/splits.go b/splitio/proxy/storage/splits.go index bc4a99d3..5f516fd4 100644 --- a/splitio/proxy/storage/splits.go +++ b/splitio/proxy/storage/splits.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/storage" "github.com/splitio/go-split-commons/v5/storage/inmemory/mutexmap" "github.com/splitio/go-toolkit/v5/datastructures/set" @@ -41,9 +42,9 @@ type ProxySplitStorageImpl struct { // NewProxySplitStorage instantiates a new proxy storage that wraps an in-memory snapshot of the last known, // flag configuration, a changes summaries containing recipes to update SDKs with different CNs, and a persistent storage // for snapshot purposes -func NewProxySplitStorage(db persistent.DBWrapper, logger logging.LoggerInterface, restoreBackup bool) *ProxySplitStorageImpl { +func NewProxySplitStorage(db persistent.DBWrapper, logger logging.LoggerInterface, restoreBackup bool, flagSetsFilter flagsets.FlagSetFilter) *ProxySplitStorageImpl { disk := persistent.NewSplitChangesCollection(db, logger) - snapshot := mutexmap.NewMMSplitStorage() + snapshot := mutexmap.NewMMSplitStorage(flagSetsFilter) recipes := optimized.NewSplitChangesSummaries(maxRecipes) if restoreBackup { snapshotFromDisk(snapshot, recipes, disk, logger) diff --git a/splitio/proxy/storage/splits_test.go b/splitio/proxy/storage/splits_test.go index 7365564c..b3e03e7b 100644 --- a/splitio/proxy/storage/splits_test.go +++ b/splitio/proxy/storage/splits_test.go @@ -6,6 +6,7 @@ import ( "github.com/splitio/split-synchronizer/v5/splitio/proxy/storage/persistent" "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-toolkit/v5/logging" ) @@ -23,7 +24,7 @@ func TestSplitStorage(t *testing.T) { {Name: "s2", ChangeNumber: 2, Status: "ACTIVE"}, }, nil, 1) - pss := NewProxySplitStorage(dbw, logger, true) + pss := NewProxySplitStorage(dbw, logger, true, flagsets.NewFlagSetFilter(nil)) sinceMinus1, currentCN, err := pss.recipes.FetchSince(-1) if err != nil { From afcffa239eb8dc9f33f40f0f2766b1c4caded9a4 Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Tue, 17 Oct 2023 19:34:02 -0300 Subject: [PATCH 3/9] add historic storage for keeping track of flagsets --- go.mod | 9 +- go.sum | 14 +- splitio/commitversion.go | 2 +- splitio/proxy/storage/optimized/historic.go | 192 +++++++++++ .../proxy/storage/optimized/historic_test.go | 305 ++++++++++++++++++ 5 files changed, 513 insertions(+), 9 deletions(-) create mode 100644 splitio/proxy/storage/optimized/historic.go create mode 100644 splitio/proxy/storage/optimized/historic_test.go diff --git a/go.mod b/go.mod index 908d8a86..3485f219 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/splitio/split-synchronizer/v5 -go 1.18 +go 1.21 require ( github.com/gin-contrib/cors v1.4.0 @@ -8,8 +8,9 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 github.com/splitio/gincache v1.0.1 - github.com/splitio/go-split-commons/v5 v5.0.0 - github.com/splitio/go-toolkit/v5 v5.3.1 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0 + github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a + github.com/stretchr/testify v1.8.4 go.etcd.io/bbolt v1.3.6 ) @@ -19,6 +20,7 @@ require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -34,6 +36,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/redis/go-redis/v9 v9.0.4 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect diff --git a/go.sum b/go.sum index bbe5b69d..ff9301c7 100644 --- a/go.sum +++ b/go.sum @@ -3,7 +3,9 @@ github.com/bits-and-blooms/bitset v1.3.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edY github.com/bits-and-blooms/bloom/v3 v3.3.1 h1:K2+A19bXT8gJR5mU7y+1yW6hsKfNCjcP2uNfLFKncjQ= github.com/bits-and-blooms/bloom/v3 v3.3.1/go.mod h1:bhUUknWd5khVbTe4UgMCSiOOVJzr3tMoijSK3WwvW90= github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -31,6 +33,7 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -87,10 +90,10 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/splitio/gincache v1.0.1 h1:dLYdANY/BqH4KcUMCe/LluLyV5WtuE/LEdQWRE06IXU= github.com/splitio/gincache v1.0.1/go.mod h1:CcgJDSM9Af75kyBH0724v55URVwMBuSj5x1eCWIOECY= -github.com/splitio/go-split-commons/v5 v5.0.0 h1:bGRi0cf1JP5VNSi0a4BPQEWv/DACkeSKliazhPMVDPk= -github.com/splitio/go-split-commons/v5 v5.0.0/go.mod h1:lzoVmYJaCqB8UPSxWva0BZe7fF+bRJD+eP0rNi/lL7c= -github.com/splitio/go-toolkit/v5 v5.3.1 h1:9J/byd0fRxWj5/Zg0QZOnUxKBDIAMCGr7rySYzJKdJg= -github.com/splitio/go-toolkit/v5 v5.3.1/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0 h1:t7QuH0+4T2LeJOc2gdRP+PkFPkQEB017arfxBccsArg= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0/go.mod h1:ksVZQYLs+3ZuzU81vEvf1aCjk24pdrVWjUXNq6Qcayo= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a h1:2wjh5hSGlFRuh6Lbmodr0VRqtry2m9pEBNmwiLsY+ss= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -101,8 +104,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= diff --git a/splitio/commitversion.go b/splitio/commitversion.go index 47b58123..4ba6024b 100644 --- a/splitio/commitversion.go +++ b/splitio/commitversion.go @@ -5,4 +5,4 @@ This file is created automatically, please do not edit */ // CommitVersion is the version of the last commit previous to release -const CommitVersion = "da63b9f" +const CommitVersion = "fa204db" diff --git a/splitio/proxy/storage/optimized/historic.go b/splitio/proxy/storage/optimized/historic.go new file mode 100644 index 00000000..3805e8d9 --- /dev/null +++ b/splitio/proxy/storage/optimized/historic.go @@ -0,0 +1,192 @@ +package optimized + +import ( + "slices" + "sort" + "strings" + "sync" + + "github.com/splitio/go-split-commons/v5/dtos" +) + +type HistoricChanges struct { + data []FeatureView + mutex sync.RWMutex +} + +func (h *HistoricChanges) GetUpdatedSince(since int64, flagSets []string) []FeatureView { + h.mutex.RLock() + views := h.findNewerThan(since) + toRet := copyAndFilter(views, flagSets, since) + h.mutex.RUnlock() + return toRet +} + +func (h *HistoricChanges) Update(toAdd []dtos.SplitDTO, toRemove []dtos.SplitDTO, newCN int64) { + h.mutex.Lock() + h.updateFrom(toAdd) + h.updateFrom(toRemove) + sort.Slice(h.data, func(i, j int) bool { return h.data[i].LastUpdated < h.data[j].LastUpdated }) + h.mutex.Unlock() +} + +func (h *HistoricChanges) updateFrom(source []dtos.SplitDTO) { + for idx := range source { + if current := h.findByName(source[idx].Name); current != nil { + current.updateFrom(&source[idx]) + } else { + var toAdd FeatureView + toAdd.updateFrom(&source[idx]) + h.data = append(h.data, toAdd) + } + } + +} + +func (h *HistoricChanges) findByName(name string) *FeatureView { + for idx := range h.data { + if h.data[idx].Name == name { // TODO(mredolatti): optimize! + return &h.data[idx] + } + } + return nil +} + +func (h *HistoricChanges) findNewerThan(since int64) []FeatureView { + // precondition: h.data is sorted by CN + start := sort.Search(len(h.data), func(i int) bool { return h.data[i].LastUpdated > since }) + if start == len(h.data) { + return nil + } + return h.data[start:] +} + +type FeatureView struct { + Name string + Active bool + LastUpdated int64 + TrafficTypeName string + FlagSets []FlagSetView +} + +func (f *FeatureView) updateFrom(s *dtos.SplitDTO) { + f.Name = s.Name + f.Active = s.Status == "ACTIVE" + f.LastUpdated = s.ChangeNumber + f.TrafficTypeName = s.TrafficTypeName + f.updateFlagsets(s.Sets, s.ChangeNumber) +} + +func (f *FeatureView) updateFlagsets(incoming []string, lastUpdated int64) { + // TODO(mredolatti): need a copy of incoming? + for idx := range f.FlagSets { + if itemIdx := slices.Index(incoming, f.FlagSets[idx].Name); itemIdx != -1 { + if !f.FlagSets[idx].Active { // Association changed from ARCHIVED to ACTIVE + f.FlagSets[idx].Active = true + f.FlagSets[idx].LastUpdated = lastUpdated + + } + + // "soft delete" the item so that it's not traversed later on + // (replaces the item with the last one, clears the latter and shrinks the slice by 1) + incoming[itemIdx] = incoming[len(incoming)-1] + incoming[len(incoming)-1] = "" + incoming = incoming[:len(incoming)-1] + + } else { // Association changed from ARCHIVED to ACTIVE + f.FlagSets[idx].Active = false + f.FlagSets[idx].LastUpdated = lastUpdated + } + } + + for idx := range incoming { + // the only leftover in `incoming` should be the items that were not + // present in the feature's previously associated flagsets, so they're new & active + f.FlagSets = append(f.FlagSets, FlagSetView{ + Name: incoming[idx], + Active: true, + LastUpdated: lastUpdated, + }) + } + + sort.Slice(f.FlagSets, func(i, j int) bool { return f.FlagSets[i].Name < f.FlagSets[j].Name }) +} + +func (f *FeatureView) findFlagSetByName(name string) *FlagSetView { + // precondition: f.FlagSets is sorted by name + idx := sort.Search(len(f.FlagSets), func(i int) bool { return f.FlagSets[i].Name >= name }) + if idx != len(f.FlagSets) && name == f.FlagSets[idx].Name { + return &f.FlagSets[idx] + } + return nil +} + +func (f *FeatureView) clone() FeatureView { + toRet := FeatureView{ + Name: f.Name, + Active: f.Active, + LastUpdated: f.LastUpdated, + TrafficTypeName: f.TrafficTypeName, + FlagSets: make([]FlagSetView, len(f.FlagSets)), + } + copy(toRet.FlagSets, f.FlagSets) // we need to deep clone to avoid race conditions + return toRet + +} + +func copyAndFilter(views []FeatureView, sets []string, since int64) []FeatureView { + // precondition: f.Flagsets is sorted by name + // precondition: sets is sorted + toRet := make([]FeatureView, 0, len(views)) + if len(sets) == 0 { + for idx := range views { + toRet = append(toRet, views[idx].clone()) + } + return toRet + } + + // this code computes the intersection in o(views * (len(views.sets) + len(sets))) + for idx := range views { + viewFlagSetIndex, requestedSetIndex := 0, 0 + for viewFlagSetIndex < len(views[idx].FlagSets) { + switch strings.Compare(views[idx].FlagSets[viewFlagSetIndex].Name, sets[requestedSetIndex]) { + case 0: // we got a match + fsinfo := views[idx].FlagSets[viewFlagSetIndex] + // if an association is active, it's considered and the Feature is added to the result set. + // if an association is inactive and we're fetching from scratch (since=-1), it's not considered. + // if an association was already inactive at the time of the provided `since`, it's not considered. + // if an association was active on the provided `since` and now isn't, the feature IS added to the returned payload. + // - the consumer is responsible for filtering flagsets where active = false when mapping the outcome of + // this function to a []dtos.SplitChanges response. + if fsinfo.Active || (since > -1 && fsinfo.LastUpdated > since) { + toRet = append(toRet, views[idx].clone()) + } + viewFlagSetIndex++ + incrUpTo(&requestedSetIndex, len(sets)) + case -1: + viewFlagSetIndex++ + case 1: + if incrUpTo(&requestedSetIndex, len(sets)) { + viewFlagSetIndex++ + } + } + } + } + return toRet +} + +type FlagSetView struct { + Name string + Active bool + LastUpdated int64 +} + +// increment `toIncr` by 1 as long as the result is less than `limit`. +// return wether the limit was reached +func incrUpTo(toIncr *int, limit int) bool { + if *toIncr+1 >= limit { + return true + } + *toIncr++ + return false +} diff --git a/splitio/proxy/storage/optimized/historic_test.go b/splitio/proxy/storage/optimized/historic_test.go new file mode 100644 index 00000000..797e1881 --- /dev/null +++ b/splitio/proxy/storage/optimized/historic_test.go @@ -0,0 +1,305 @@ +package optimized + +import ( + "math/rand" + "sort" + "testing" + "time" + + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/stretchr/testify/assert" +) + +func TestHistoricSplitStorage(t *testing.T) { + + var historic HistoricChanges + historic.Update([]dtos.SplitDTO{ + {Name: "f1", Sets: []string{"s1", "s2"}, Status: "ACTIVE", ChangeNumber: 1, TrafficTypeName: "tt1"}, + }, []dtos.SplitDTO{}, 1) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 1}, + }, + historic.GetUpdatedSince(-1, nil)) + + // process an update with no change in flagsets / split status + // - fetching from -1 && 1 should return the same paylaod as before with only `lastUpdated` bumped to 2 + // - fetching from 2 should return empty + historic.Update([]dtos.SplitDTO{ + {Name: "f1", Sets: []string{"s1", "s2"}, Status: "ACTIVE", ChangeNumber: 2, TrafficTypeName: "tt1"}, + }, []dtos.SplitDTO{}, 1) + + // no filter + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + }, + historic.GetUpdatedSince(-1, nil)) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + }, + historic.GetUpdatedSince(1, nil)) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(2, nil)) + + // filter by s1 + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + }, + historic.GetUpdatedSince(-1, []string{"s1"})) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + }, + historic.GetUpdatedSince(1, []string{"s1"})) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(2, []string{"s1"})) + + // filter by s2 + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + }, + historic.GetUpdatedSince(-1, []string{"s2"})) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + }, + historic.GetUpdatedSince(1, []string{"s2"})) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(2, []string{"s2"})) + + // ------------------- + + // process an update with one extra split + // - fetching from -1, & 1 should return the same payload + // - fetching from 2 shuold only return f2 + // - fetching from 3 should return empty + historic.Update([]dtos.SplitDTO{ + {Name: "f2", Sets: []string{"s2", "s3"}, Status: "ACTIVE", ChangeNumber: 3, TrafficTypeName: "tt1"}, + }, []dtos.SplitDTO{}, 1) + + // assert correct behaviours for CN == 1..3 and no flag sets filter + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(-1, nil)) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(1, nil)) + assert.Equal(t, + []FeatureView{ + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(2, nil)) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(3, nil)) + + // filtering by s1: + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + }, + historic.GetUpdatedSince(-1, []string{"s1"})) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + }, + historic.GetUpdatedSince(1, []string{"s1"})) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(2, []string{"s1"})) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(3, []string{"s1"})) + + // filtering by s2: + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(-1, []string{"s2"})) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", true, 1}, {"s2", true, 1}}, Active: true, LastUpdated: 2}, + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(1, []string{"s2"})) + assert.Equal(t, + []FeatureView{ + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(2, []string{"s2"})) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(3, []string{"s2"})) + + //filtering by s3 + assert.Equal(t, + []FeatureView{ + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(-1, []string{"s3"})) + assert.Equal(t, + []FeatureView{ + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(1, []string{"s3"})) + assert.Equal(t, + []FeatureView{ + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + }, + historic.GetUpdatedSince(2, []string{"s3"})) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(3, []string{"s3"})) + + // ------------------- + + // process an update that removes f1 from flagset s1 + // - fetching without a filter should remain the same + // - fetching with filter = s1 should not return f1 in CN=-1, should return it without the flagset in greater CNs + historic.Update([]dtos.SplitDTO{ + {Name: "f1", Sets: []string{"s2"}, Status: "ACTIVE", ChangeNumber: 4, TrafficTypeName: "tt1"}, + }, []dtos.SplitDTO{}, 1) + + assert.Equal(t, + []FeatureView{ + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: true, LastUpdated: 3}, + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", false, 4}, {"s2", true, 1}}, Active: true, LastUpdated: 4}, + }, + historic.GetUpdatedSince(-1, nil)) + + // with filter = s1 (f2 never was associated with s1, f1 is no longer associated) + assert.Equal(t, + []FeatureView{}, + historic.GetUpdatedSince(-1, []string{"s1"})) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", false, 4}, {"s2", true, 1}}, Active: true, LastUpdated: 4}, + }, + historic.GetUpdatedSince(1, []string{"s1"})) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", false, 4}, {"s2", true, 1}}, Active: true, LastUpdated: 4}, + }, + historic.GetUpdatedSince(2, []string{"s1"})) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", false, 4}, {"s2", true, 1}}, Active: true, LastUpdated: 4}, + }, + historic.GetUpdatedSince(3, []string{"s1"})) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(4, []string{"s1"})) + +} + +// -- code below is for benchmarking random access using hashsets (map[string]struct{}) vs sorted slices + binary search + +func setupRandomData(flagsetLength int, flagsetCount int, splits int, flagSetsPerSplitMax int, userSets int) benchmarkDataSlices { + const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + rand.Seed(time.Now().UnixNano()) + makeStr := func(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) + } + + flagSets := make([]string, 0, flagsetCount) + for flagsetCount > 0 { + flagSets = append(flagSets, makeStr(flagsetLength)) + flagsetCount-- + } + + views := make([]FeatureView, 0, splits) + for len(views) < cap(views) { + fscount := rand.Intn(flagSetsPerSplitMax) + setsForSplit := make([]FlagSetView, 0, fscount) + for fscount > 0 { + setsForSplit = append(setsForSplit, FlagSetView{ + Name: flagSets[rand.Intn(len(flagSets))], + Active: rand.Intn(2) > 0, + LastUpdated: rand.Int63n(2), + }) + fscount-- + } + sort.Slice(setsForSplit, func(i, j int) bool { return setsForSplit[i].Name < setsForSplit[j].Name }) + views = append(views, FeatureView{ + Name: makeStr(20), + Active: rand.Intn(2) > 0, // rand bool + LastUpdated: rand.Int63n(2), // 1 or 2 (still an int but behaving like a bool if we filter by since=1) + TrafficTypeName: makeStr(10), + FlagSets: setsForSplit, + }) + + } + sort.Slice(views, func(i, j int) bool { return views[i].LastUpdated < views[j].LastUpdated }) + return benchmarkDataSlices{views, flagSets} +} + +type benchmarkDataSlices struct { + views []FeatureView + sets []string +} + +func (b *benchmarkDataSlices) toBenchmarkDataForMaps() benchmarkDataMaps { + setMap := make(map[string]struct{}, len(b.sets)) + for _, s := range b.sets { + setMap[s] = struct{}{} + } + + return benchmarkDataMaps{ + views: b.views, + sets: setMap, + } + +} + +type benchmarkDataMaps struct { + views []FeatureView + sets map[string]struct{} +} + +// reference implementation for benchmarking purposes only +func copyAndFilterUsingMaps(views []FeatureView, sets map[string]struct{}, since int64) []FeatureView { + toRet := make([]FeatureView, 0, len(views)) + for idx := range views { + for fsidx := range views[idx].FlagSets { + if _, ok := sets[views[idx].FlagSets[fsidx].Name]; ok { + fsinfo := views[idx].FlagSets[fsidx] + if fsinfo.Active || fsinfo.LastUpdated > since { + toRet = append(toRet, views[idx].clone()) + } + } + } + + } + return toRet +} + +func BenchmarkFlagSetProcessing(b *testing.B) { + + b.Run("sorted-slice", func(b *testing.B) { + data := make([]benchmarkDataSlices, 0, b.N) + for i := 0; i < b.N; i++ { + data = append(data, setupRandomData(20, 50, 500, 20, 10)) + } + + b.ResetTimer() // to ignore setup time & allocs + + for i := 0; i < b.N; i++ { + copyAndFilter(data[i].views, data[i].sets, 1) + } + }) + + b.Run("maps", func(b *testing.B) { + data := make([]benchmarkDataMaps, 0, b.N) + for i := 0; i < b.N; i++ { + d := setupRandomData(20, 50, 500, 20, 10) + data = append(data, d.toBenchmarkDataForMaps()) + } + + b.ResetTimer() // to ignore setup time & allocs + + for i := 0; i < b.N; i++ { + copyAndFilterUsingMaps(data[i].views, data[i].sets, 1) + } + }) +} From dee7ebcddc7338b827f622352c2c2c336c3c87eb Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Tue, 17 Oct 2023 19:46:36 -0300 Subject: [PATCH 4/9] update images --- docker/Dockerfile.proxy | 10 +++++----- docker/Dockerfile.synchronizer | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docker/Dockerfile.proxy b/docker/Dockerfile.proxy index e2ea204a..a0392fc6 100644 --- a/docker/Dockerfile.proxy +++ b/docker/Dockerfile.proxy @@ -1,13 +1,13 @@ # Build stage -FROM golang:1.20.6-alpine3.18 AS builder +FROM golang:1.21.3-alpine3.18 AS builder ARG EXTRA_BUILD_ARGS RUN apk add \ - bash \ - build-base \ - python3 \ - git + bash \ + build-base \ + python3 \ + git WORKDIR /code diff --git a/docker/Dockerfile.synchronizer b/docker/Dockerfile.synchronizer index 4d10cc1f..f852ed32 100644 --- a/docker/Dockerfile.synchronizer +++ b/docker/Dockerfile.synchronizer @@ -1,13 +1,13 @@ # Build stage -FROM golang:1.20.6-alpine3.18 AS builder +FROM golang:1.21.3-alpine3.18 AS builder ARG EXTRA_BUILD_ARGS RUN apk add \ - bash \ - build-base \ - python3 \ - git + bash \ + build-base \ + python3 \ + git WORKDIR /code From f2a7a497c285126db0d73b2d1a64397dd30a1263 Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Thu, 19 Oct 2023 10:36:44 -0300 Subject: [PATCH 5/9] fixes & more test --- splitio/commitversion.go | 2 +- splitio/proxy/storage/optimized/historic.go | 77 +++++++++++-------- .../proxy/storage/optimized/historic_test.go | 39 ++++++++++ 3 files changed, 85 insertions(+), 33 deletions(-) diff --git a/splitio/commitversion.go b/splitio/commitversion.go index 4ba6024b..8f85b7e1 100644 --- a/splitio/commitversion.go +++ b/splitio/commitversion.go @@ -5,4 +5,4 @@ This file is created automatically, please do not edit */ // CommitVersion is the version of the last commit previous to release -const CommitVersion = "fa204db" +const CommitVersion = "dee7ebc" diff --git a/splitio/proxy/storage/optimized/historic.go b/splitio/proxy/storage/optimized/historic.go index 3805e8d9..4829f6f6 100644 --- a/splitio/proxy/storage/optimized/historic.go +++ b/splitio/proxy/storage/optimized/historic.go @@ -15,6 +15,7 @@ type HistoricChanges struct { } func (h *HistoricChanges) GetUpdatedSince(since int64, flagSets []string) []FeatureView { + slices.Sort(flagSets) h.mutex.RLock() views := h.findNewerThan(since) toRet := copyAndFilter(views, flagSets, since) @@ -30,6 +31,8 @@ func (h *HistoricChanges) Update(toAdd []dtos.SplitDTO, toRemove []dtos.SplitDTO h.mutex.Unlock() } +// public interface ends here + func (h *HistoricChanges) updateFrom(source []dtos.SplitDTO) { for idx := range source { if current := h.findByName(source[idx].Name); current != nil { @@ -138,41 +141,54 @@ func copyAndFilter(views []FeatureView, sets []string, since int64) []FeatureVie // precondition: f.Flagsets is sorted by name // precondition: sets is sorted toRet := make([]FeatureView, 0, len(views)) - if len(sets) == 0 { - for idx := range views { + + // this code computes the intersection in o(views * ) + for idx := range views { + if featureShouldBeReturned(&views[idx], since, sets) { toRet = append(toRet, views[idx].clone()) } - return toRet } + return toRet +} - // this code computes the intersection in o(views * (len(views.sets) + len(sets))) - for idx := range views { - viewFlagSetIndex, requestedSetIndex := 0, 0 - for viewFlagSetIndex < len(views[idx].FlagSets) { - switch strings.Compare(views[idx].FlagSets[viewFlagSetIndex].Name, sets[requestedSetIndex]) { - case 0: // we got a match - fsinfo := views[idx].FlagSets[viewFlagSetIndex] - // if an association is active, it's considered and the Feature is added to the result set. - // if an association is inactive and we're fetching from scratch (since=-1), it's not considered. - // if an association was already inactive at the time of the provided `since`, it's not considered. - // if an association was active on the provided `since` and now isn't, the feature IS added to the returned payload. - // - the consumer is responsible for filtering flagsets where active = false when mapping the outcome of - // this function to a []dtos.SplitChanges response. - if fsinfo.Active || (since > -1 && fsinfo.LastUpdated > since) { - toRet = append(toRet, views[idx].clone()) - } - viewFlagSetIndex++ - incrUpTo(&requestedSetIndex, len(sets)) - case -1: +func featureShouldBeReturned(view *FeatureView, since int64, sets []string) bool { + + // if fetching from sratch & the feature is not active, + // or it hasn't been updated since `since`, it shouldn't even be considered for being returned + if since == -1 && !view.Active || view.LastUpdated < since { + return false + } + + // all updated features should be returned if no set filter is being used + if len(sets) == 0 { + return true + } + + // compare the sets for intersection of user supplied sets with currently active ones. + // takes linear o(len(feature.sets) + len(sets)) time since both the incoming sets are sorted + viewFlagSetIndex, requestedSetIndex := 0, 0 + for viewFlagSetIndex < len(view.FlagSets) { + switch strings.Compare(view.FlagSets[viewFlagSetIndex].Name, sets[requestedSetIndex]) { + case 0: // we got a match + fsinfo := view.FlagSets[viewFlagSetIndex] + // if an association is active, it's considered and the Feature is added to the result set. + // if an association is inactive and we're fetching from scratch (since=-1), it's not considered. + // if an association was already inactive at the time of the provided `since`, it's not considered. + // if an association was active on the provided `since` and now isn't, the feature IS added to the returned payload. + if fsinfo.Active || (since > -1 && since < fsinfo.LastUpdated) { + return true + } + viewFlagSetIndex++ + incrUpTo(&requestedSetIndex, len(sets)) + case -1: + viewFlagSetIndex++ + case 1: + if incrUpTo(&requestedSetIndex, len(sets)); requestedSetIndex+1 == len(sets) { viewFlagSetIndex++ - case 1: - if incrUpTo(&requestedSetIndex, len(sets)) { - viewFlagSetIndex++ - } } } } - return toRet + return false } type FlagSetView struct { @@ -181,12 +197,9 @@ type FlagSetView struct { LastUpdated int64 } -// increment `toIncr` by 1 as long as the result is less than `limit`. -// return wether the limit was reached -func incrUpTo(toIncr *int, limit int) bool { +func incrUpTo(toIncr *int, limit int) { if *toIncr+1 >= limit { - return true + return } *toIncr++ - return false } diff --git a/splitio/proxy/storage/optimized/historic_test.go b/splitio/proxy/storage/optimized/historic_test.go index 797e1881..005e9994 100644 --- a/splitio/proxy/storage/optimized/historic_test.go +++ b/splitio/proxy/storage/optimized/historic_test.go @@ -187,6 +187,45 @@ func TestHistoricSplitStorage(t *testing.T) { historic.GetUpdatedSince(3, []string{"s1"})) assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(4, []string{"s1"})) + // process an update that removes f2 (archives the feature) + // fetching from -1 should not return f2 + // fetching from any intermediate CN should return f2 as archived + // fetching from cn=5 should return empty + historic.Update([]dtos.SplitDTO{ + {Name: "f2", Sets: []string{"s2", "s3"}, Status: "ARCHIVED", ChangeNumber: 5, TrafficTypeName: "tt1"}, + }, []dtos.SplitDTO{}, 1) + + // without filter + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", false, 4}, {"s2", true, 1}}, Active: true, LastUpdated: 4}, + }, + historic.GetUpdatedSince(-1, nil)) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", false, 4}, {"s2", true, 1}}, Active: true, LastUpdated: 4}, + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: false, LastUpdated: 5}, + }, + historic.GetUpdatedSince(1, nil)) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", false, 4}, {"s2", true, 1}}, Active: true, LastUpdated: 4}, + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: false, LastUpdated: 5}, + }, + historic.GetUpdatedSince(2, nil)) + assert.Equal(t, + []FeatureView{ + {Name: "f1", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s1", false, 4}, {"s2", true, 1}}, Active: true, LastUpdated: 4}, + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: false, LastUpdated: 5}, + }, + historic.GetUpdatedSince(3, nil)) + assert.Equal(t, + []FeatureView{ + {Name: "f2", TrafficTypeName: "tt1", FlagSets: []FlagSetView{{"s2", true, 3}, {"s3", true, 3}}, Active: false, LastUpdated: 5}, + }, + historic.GetUpdatedSince(4, nil)) + assert.Equal(t, []FeatureView{}, historic.GetUpdatedSince(5, nil)) + } // -- code below is for benchmarking random access using hashsets (map[string]struct{}) vs sorted slices + binary search From 88b12f000c522bcba756e113b838422b39d9a30e Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Thu, 19 Oct 2023 10:39:57 -0300 Subject: [PATCH 6/9] prepare base branch for flagsets project --- go.mod | 6 +++--- go.sum | 11 +++++++---- splitio/commitversion.go | 2 +- splitio/producer/initialization.go | 3 ++- splitio/proxy/caching/workers.go | 3 ++- splitio/proxy/storage/splits.go | 3 ++- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 908d8a86..54944ce8 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/splitio/split-synchronizer/v5 -go 1.18 +go 1.21 require ( github.com/gin-contrib/cors v1.4.0 @@ -8,8 +8,8 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 github.com/splitio/gincache v1.0.1 - github.com/splitio/go-split-commons/v5 v5.0.0 - github.com/splitio/go-toolkit/v5 v5.3.1 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0 + github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a go.etcd.io/bbolt v1.3.6 ) diff --git a/go.sum b/go.sum index bbe5b69d..15c30ae0 100644 --- a/go.sum +++ b/go.sum @@ -3,7 +3,9 @@ github.com/bits-and-blooms/bitset v1.3.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edY github.com/bits-and-blooms/bloom/v3 v3.3.1 h1:K2+A19bXT8gJR5mU7y+1yW6hsKfNCjcP2uNfLFKncjQ= github.com/bits-and-blooms/bloom/v3 v3.3.1/go.mod h1:bhUUknWd5khVbTe4UgMCSiOOVJzr3tMoijSK3WwvW90= github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -31,6 +33,7 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -87,10 +90,10 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/splitio/gincache v1.0.1 h1:dLYdANY/BqH4KcUMCe/LluLyV5WtuE/LEdQWRE06IXU= github.com/splitio/gincache v1.0.1/go.mod h1:CcgJDSM9Af75kyBH0724v55URVwMBuSj5x1eCWIOECY= -github.com/splitio/go-split-commons/v5 v5.0.0 h1:bGRi0cf1JP5VNSi0a4BPQEWv/DACkeSKliazhPMVDPk= -github.com/splitio/go-split-commons/v5 v5.0.0/go.mod h1:lzoVmYJaCqB8UPSxWva0BZe7fF+bRJD+eP0rNi/lL7c= -github.com/splitio/go-toolkit/v5 v5.3.1 h1:9J/byd0fRxWj5/Zg0QZOnUxKBDIAMCGr7rySYzJKdJg= -github.com/splitio/go-toolkit/v5 v5.3.1/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0 h1:t7QuH0+4T2LeJOc2gdRP+PkFPkQEB017arfxBccsArg= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0/go.mod h1:ksVZQYLs+3ZuzU81vEvf1aCjk24pdrVWjUXNq6Qcayo= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a h1:2wjh5hSGlFRuh6Lbmodr0VRqtry2m9pEBNmwiLsY+ss= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/splitio/commitversion.go b/splitio/commitversion.go index 47b58123..4ba6024b 100644 --- a/splitio/commitversion.go +++ b/splitio/commitversion.go @@ -5,4 +5,4 @@ This file is created automatically, please do not edit */ // CommitVersion is the version of the last commit previous to release -const CommitVersion = "da63b9f" +const CommitVersion = "fa204db" diff --git a/splitio/producer/initialization.go b/splitio/producer/initialization.go index 532953b7..cf8da384 100644 --- a/splitio/producer/initialization.go +++ b/splitio/producer/initialization.go @@ -7,6 +7,7 @@ import ( cconf "github.com/splitio/go-split-commons/v5/conf" "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/provisional/strategy" "github.com/splitio/go-split-commons/v5/service/api" "github.com/splitio/go-split-commons/v5/storage/filter" @@ -118,7 +119,7 @@ func Start(logger logging.LoggerInterface, cfg *conf.Main) error { eventEvictionMonitor := evcalc.New(1) workers := synchronizer.Workers{ - SplitUpdater: split.NewSplitUpdater(storages.SplitStorage, splitAPI.SplitFetcher, logger, syncTelemetryStorage, appMonitor), + SplitUpdater: split.NewSplitUpdater(storages.SplitStorage, splitAPI.SplitFetcher, logger, syncTelemetryStorage, appMonitor, flagsets.NewFlagSetFilter(nil)), // TODO(mredolatti) SegmentUpdater: segment.NewSegmentUpdater(storages.SplitStorage, storages.SegmentStorage, splitAPI.SegmentFetcher, logger, syncTelemetryStorage, appMonitor), ImpressionsCountRecorder: impressionscount.NewRecorderSingle(impressionsCounter, splitAPI.ImpressionRecorder, diff --git a/splitio/proxy/caching/workers.go b/splitio/proxy/caching/workers.go index cc4bff18..3931286c 100644 --- a/splitio/proxy/caching/workers.go +++ b/splitio/proxy/caching/workers.go @@ -2,6 +2,7 @@ package caching import ( "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/healthcheck/application" "github.com/splitio/go-split-commons/v5/service" "github.com/splitio/go-split-commons/v5/storage" @@ -29,7 +30,7 @@ func NewCacheAwareSplitSync( appMonitor application.MonitorProducerInterface, ) *CacheAwareSplitSynchronizer { return &CacheAwareSplitSynchronizer{ - wrapped: split.NewSplitUpdater(splitStorage, splitFetcher, logger, runtimeTelemetry, appMonitor), + wrapped: split.NewSplitUpdater(splitStorage, splitFetcher, logger, runtimeTelemetry, appMonitor, flagsets.NewFlagSetFilter(nil)), // TODO(mredolatti): fix this splitStorage: splitStorage, cacheFlusher: cacheFlusher, } diff --git a/splitio/proxy/storage/splits.go b/splitio/proxy/storage/splits.go index bc4a99d3..a5b0cb6f 100644 --- a/splitio/proxy/storage/splits.go +++ b/splitio/proxy/storage/splits.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/storage" "github.com/splitio/go-split-commons/v5/storage/inmemory/mutexmap" "github.com/splitio/go-toolkit/v5/datastructures/set" @@ -43,7 +44,7 @@ type ProxySplitStorageImpl struct { // for snapshot purposes func NewProxySplitStorage(db persistent.DBWrapper, logger logging.LoggerInterface, restoreBackup bool) *ProxySplitStorageImpl { disk := persistent.NewSplitChangesCollection(db, logger) - snapshot := mutexmap.NewMMSplitStorage() + snapshot := mutexmap.NewMMSplitStorage(flagsets.NewFlagSetFilter(nil)) // TODO(mredolatti): fix this recipes := optimized.NewSplitChangesSummaries(maxRecipes) if restoreBackup { snapshotFromDisk(snapshot, recipes, disk, logger) From 15857e37b608eef61bfee8be73738ed76d37d9f2 Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Thu, 19 Oct 2023 10:45:49 -0300 Subject: [PATCH 7/9] bump go version in docker images --- docker/Dockerfile.proxy | 10 +++++----- docker/Dockerfile.synchronizer | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docker/Dockerfile.proxy b/docker/Dockerfile.proxy index e2ea204a..a0392fc6 100644 --- a/docker/Dockerfile.proxy +++ b/docker/Dockerfile.proxy @@ -1,13 +1,13 @@ # Build stage -FROM golang:1.20.6-alpine3.18 AS builder +FROM golang:1.21.3-alpine3.18 AS builder ARG EXTRA_BUILD_ARGS RUN apk add \ - bash \ - build-base \ - python3 \ - git + bash \ + build-base \ + python3 \ + git WORKDIR /code diff --git a/docker/Dockerfile.synchronizer b/docker/Dockerfile.synchronizer index 4d10cc1f..f852ed32 100644 --- a/docker/Dockerfile.synchronizer +++ b/docker/Dockerfile.synchronizer @@ -1,13 +1,13 @@ # Build stage -FROM golang:1.20.6-alpine3.18 AS builder +FROM golang:1.21.3-alpine3.18 AS builder ARG EXTRA_BUILD_ARGS RUN apk add \ - bash \ - build-base \ - python3 \ - git + bash \ + build-base \ + python3 \ + git WORKDIR /code From 7dbd8ccceb3d29bbc43447e4dbd9c91dd7d75579 Mon Sep 17 00:00:00 2001 From: Martin Redolatti Date: Thu, 19 Oct 2023 11:00:07 -0300 Subject: [PATCH 8/9] bump runner stage alpine version --- docker/Dockerfile.proxy | 2 +- docker/Dockerfile.synchronizer | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile.proxy b/docker/Dockerfile.proxy index a0392fc6..0c7e9131 100644 --- a/docker/Dockerfile.proxy +++ b/docker/Dockerfile.proxy @@ -16,7 +16,7 @@ COPY . . RUN make clean split-proxy entrypoints EXTRA_BUILD_ARGS="${EXTRA_BUILD_ARGS}" # Runner stage -FROM alpine:3.18.2 AS runner +FROM alpine:3.18.4 AS runner RUN apk add bash diff --git a/docker/Dockerfile.synchronizer b/docker/Dockerfile.synchronizer index f852ed32..b0854347 100644 --- a/docker/Dockerfile.synchronizer +++ b/docker/Dockerfile.synchronizer @@ -16,7 +16,7 @@ COPY . . RUN make clean split-sync entrypoints EXTRA_BUILD_ARGS="${EXTRA_BUILD_ARGS}" # Runner stage -FROM alpine:3.18.2 AS runner +FROM alpine:3.18.4 AS runner RUN apk add bash From 30983e0621f3805a007c0baf9f8d14e0c1ce6bd2 Mon Sep 17 00:00:00 2001 From: Lucas Echeverz Date: Tue, 24 Oct 2023 13:13:57 -0300 Subject: [PATCH 9/9] no message --- go.mod | 2 +- go.sum | 4 ++-- splitio/commitversion.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 3485f219..7fd92a7b 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.3.0 github.com/splitio/gincache v1.0.1 - github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231004184048-81902536fc1f github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a github.com/stretchr/testify v1.8.4 go.etcd.io/bbolt v1.3.6 diff --git a/go.sum b/go.sum index ff9301c7..460ba75e 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,8 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/splitio/gincache v1.0.1 h1:dLYdANY/BqH4KcUMCe/LluLyV5WtuE/LEdQWRE06IXU= github.com/splitio/gincache v1.0.1/go.mod h1:CcgJDSM9Af75kyBH0724v55URVwMBuSj5x1eCWIOECY= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0 h1:t7QuH0+4T2LeJOc2gdRP+PkFPkQEB017arfxBccsArg= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20230926022914-2101c4dc74c0/go.mod h1:ksVZQYLs+3ZuzU81vEvf1aCjk24pdrVWjUXNq6Qcayo= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231004184048-81902536fc1f h1:g3rsXA0cdMx2uz3MrTEz2tiittf+HDXpHooyYnuYg6w= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231004184048-81902536fc1f/go.mod h1:ksVZQYLs+3ZuzU81vEvf1aCjk24pdrVWjUXNq6Qcayo= github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a h1:2wjh5hSGlFRuh6Lbmodr0VRqtry2m9pEBNmwiLsY+ss= github.com/splitio/go-toolkit/v5 v5.3.2-0.20230920032539-d08915cf020a/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/splitio/commitversion.go b/splitio/commitversion.go index d6403da5..9be7f5cf 100644 --- a/splitio/commitversion.go +++ b/splitio/commitversion.go @@ -5,4 +5,4 @@ This file is created automatically, please do not edit */ // CommitVersion is the version of the last commit previous to release -const CommitVersion = "9ed4ca5" +const CommitVersion = "03a9105"