diff --git a/satellite/metainfo/config.go b/satellite/metainfo/config.go index 8ceceb943..2ad5ac394 100644 --- a/satellite/metainfo/config.go +++ b/satellite/metainfo/config.go @@ -4,6 +4,7 @@ package metainfo import ( + "encoding/binary" "fmt" "strconv" "strings" @@ -148,8 +149,9 @@ type Config struct { ServerSideCopyDisabled bool `help:"disable already enabled server-side copy. this is because once server side copy is enabled, delete code should stay changed, even if you want to disable server side copy" default:"false"` UsePendingObjectsTable bool `help:"enable new flow for upload which is using pending_objects table" default:"false"` - // flag to simplify testing by enabling feature only for specific projects + // flags to simplify testing by enabling feature only for specific projects or for for specific percentage of projects UsePendingObjectsTableProjects []string `help:"list of projects which will have UsePendingObjectsTable feature flag enabled" default:"" hidden:"true"` + UsePendingObjectsTableRollout int `help:"percentage (0-100) of projects which should have this feature enabled" default:"0" hidden:"true"` // TODO remove when we benchmarking are done and decision is made. TestListingQuery bool `default:"false" help:"test the new query for non-recursive listing"` @@ -170,11 +172,12 @@ func (c Config) Metabase(applicationName string) metabase.Config { type ExtendedConfig struct { Config - usePendingObjectsTableProjects []uuid.UUID + usePendingObjectsTableProjects []uuid.UUID + usePendingObjectsTableRolloutCursor uuid.UUID } // NewExtendedConfig creates new instance of extended config. -func NewExtendedConfig(config Config) (ExtendedConfig, error) { +func NewExtendedConfig(config Config) (_ ExtendedConfig, err error) { extendedConfig := ExtendedConfig{Config: config} for _, projectIDString := range config.UsePendingObjectsTableProjects { projectID, err := uuid.FromString(projectIDString) @@ -183,6 +186,12 @@ func NewExtendedConfig(config Config) (ExtendedConfig, error) { } extendedConfig.usePendingObjectsTableProjects = append(extendedConfig.usePendingObjectsTableProjects, projectID) } + + extendedConfig.usePendingObjectsTableRolloutCursor, err = createRolloutCursor(config.UsePendingObjectsTableRollout) + if err != nil { + return ExtendedConfig{}, err + } + return extendedConfig, nil } @@ -197,5 +206,25 @@ func (ec ExtendedConfig) UsePendingObjectsTableByProject(projectID uuid.UUID) bo return true } } + + if !ec.usePendingObjectsTableRolloutCursor.IsZero() { + if projectID.Less(ec.usePendingObjectsTableRolloutCursor) { + return true + } + } + return false } + +func createRolloutCursor(percentage int) (uuid.UUID, error) { + if percentage <= 0 { + return uuid.UUID{}, nil + } else if percentage >= 100 { + return uuid.Max(), nil + } + + cursorValue := uint32(1 << 32 * (float32(percentage) / 100)) + bytes := make([]byte, 16) + binary.BigEndian.PutUint32(bytes, cursorValue) + return uuid.FromBytes(bytes) +} diff --git a/satellite/metainfo/config_test.go b/satellite/metainfo/config_test.go index 7e5665e9e..ca3be7181 100644 --- a/satellite/metainfo/config_test.go +++ b/satellite/metainfo/config_test.go @@ -137,3 +137,50 @@ func TestExtendedConfig_UsePendingObjectsTable(t *testing.T) { require.NoError(t, err) require.True(t, config.UsePendingObjectsTableByProject(uuid.UUID{1})) } + +func TestExtendedConfig_UsePendingObjectsTableRollout(t *testing.T) { + uuidA := testrand.UUID() + config, err := metainfo.NewExtendedConfig(metainfo.Config{ + UsePendingObjectsTable: false, + UsePendingObjectsTableRollout: 0, + }) + require.NoError(t, err) + + require.False(t, config.UsePendingObjectsTableByProject(uuidA)) + require.False(t, config.UsePendingObjectsTableByProject(makeUUID("00000001-0000-0000-0000-000000000000"))) + require.False(t, config.UsePendingObjectsTableByProject(makeUUID("FFFFFFFF-0000-0000-0000-000000000000"))) + + config, err = metainfo.NewExtendedConfig(metainfo.Config{ + UsePendingObjectsTable: false, + UsePendingObjectsTableRollout: 50, + }) + require.NoError(t, err) + + require.True(t, config.UsePendingObjectsTableByProject(makeUUID("00000001-0000-0000-0000-000000000000"))) + require.False(t, config.UsePendingObjectsTableByProject(makeUUID("FFFFFFFF-0000-0000-0000-000000000000"))) + + config, err = metainfo.NewExtendedConfig(metainfo.Config{ + UsePendingObjectsTable: false, + UsePendingObjectsTableRollout: 25, + }) + require.NoError(t, err) + + require.True(t, config.UsePendingObjectsTableByProject(makeUUID("00000001-0000-0000-0000-000000000000"))) + require.True(t, config.UsePendingObjectsTableByProject(makeUUID("3FFFFFFF-0000-0000-0000-000000000000"))) + require.False(t, config.UsePendingObjectsTableByProject(makeUUID("40000000-0000-0000-0000-000000000000"))) + require.False(t, config.UsePendingObjectsTableByProject(makeUUID("FFFFFFFF-0000-0000-0000-000000000000"))) + + config, err = metainfo.NewExtendedConfig(metainfo.Config{ + UsePendingObjectsTable: false, + UsePendingObjectsTableRollout: 100, + }) + require.NoError(t, err) + + require.True(t, config.UsePendingObjectsTableByProject(makeUUID("00000001-0000-0000-0000-000000000000"))) + require.True(t, config.UsePendingObjectsTableByProject(makeUUID("FFFFFFFF-0000-0000-0000-000000000000"))) +} + +func makeUUID(uuidString string) uuid.UUID { + value, _ := uuid.FromString(uuidString) + return value +}