Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions storage/inmemory/mutexmap/splits.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ func (m *MMSplitStorage) addToFlagSets(name string, sets []string) {
func (m *MMSplitStorage) Update(toAdd []dtos.SplitDTO, toRemove []dtos.SplitDTO, till int64) {
m.mutex.Lock()
defer m.mutex.Unlock()
m.update(toAdd, toRemove, till)
}

func (m *MMSplitStorage) update(toAdd []dtos.SplitDTO, toRemove []dtos.SplitDTO, till int64) {
for _, split := range toAdd {
existing, thisIsAnUpdate := m.data[split.Name]
if thisIsAnUpdate {
Expand Down Expand Up @@ -266,5 +270,20 @@ func (m *MMSplitStorage) GetNamesByFlagSets(sets []string) map[string][]string {
return toReturn
}

func (m *MMSplitStorage) ReplaceAll(toAdd []dtos.SplitDTO, changeNumber int64) {
// Get all current splits under read lock
m.mutex.RLock()
toRemove := make([]dtos.SplitDTO, 0)
for _, split := range m.data {
toRemove = append(toRemove, split)
}
m.mutex.RUnlock()

// Now acquire write lock for the update
m.mutex.Lock()
defer m.mutex.Unlock()
m.update(toAdd, toRemove, changeNumber)
}

var _ storage.SplitStorageConsumer = (*MMSplitStorage)(nil)
var _ storage.SplitStorageProducer = (*MMSplitStorage)(nil)
56 changes: 56 additions & 0 deletions storage/inmemory/mutexmap/splits_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/splitio/go-split-commons/v7/dtos"
"github.com/splitio/go-split-commons/v7/flagsets"
"github.com/splitio/go-toolkit/v5/datastructures/set"
"github.com/stretchr/testify/assert"
)

func TestMMSplitStorage(t *testing.T) {
Expand Down Expand Up @@ -328,6 +329,61 @@ func TestGetNamesByFlagSets(t *testing.T) {
}
}

func TestReplaceAll(t *testing.T) {
// Initialize storage with some initial splits
splitStorage := NewMMSplitStorage(flagsets.NewFlagSetFilter(nil))
initialSplits := []dtos.SplitDTO{
{Name: "split1", TrafficTypeName: "tt1", Sets: []string{"set1"}, ChangeNumber: 1},
{Name: "split2", TrafficTypeName: "tt2", Sets: []string{"set2"}, ChangeNumber: 2},
}
splitStorage.Update(initialSplits, nil, 100)

// Verify initial state
assert.Equal(t, 2, len(splitStorage.All()), "Should have 2 initial splits")
assert.False(t, !splitStorage.TrafficTypeExists("tt1") || !splitStorage.TrafficTypeExists("tt2"), "Initial traffic types should exist")

// Prepare new splits for replacement
newSplits := []dtos.SplitDTO{
{Name: "split3", TrafficTypeName: "tt3", Sets: []string{"set3"}, ChangeNumber: 3},
{Name: "split4", TrafficTypeName: "tt4", Sets: []string{"set4"}, ChangeNumber: 4},
{Name: "split5", TrafficTypeName: "tt4", Sets: []string{"set5"}, ChangeNumber: 5},
}

// Replace all splits
splitStorage.ReplaceAll(newSplits, 200)

// Verify the replacement
allSplits := splitStorage.All()
assert.Equal(t, 3, len(allSplits), "Should have 3 splits after replacement")

// Verify old splits are removed
assert.False(t, splitStorage.Split("split1") != nil || splitStorage.Split("split2") != nil, "Old splits should have been removed")

// Verify new splits are present
assert.ElementsMatch(t, newSplits, allSplits, "All splits should match the new splits")
for _, expectedSplit := range newSplits {
split := splitStorage.Split(expectedSplit.Name)
assert.NotNil(t, split, "Split %s should exist", expectedSplit.Name)
assert.Equal(t, expectedSplit.TrafficTypeName, split.TrafficTypeName, "Split %s should have traffic type %s", expectedSplit.Name, expectedSplit.TrafficTypeName)
}

// Verify old traffic types are removed and new ones exist
assert.False(t, splitStorage.TrafficTypeExists("tt1") || splitStorage.TrafficTypeExists("tt2"), "Old traffic types should not exist")
assert.True(t, splitStorage.TrafficTypeExists("tt3") && splitStorage.TrafficTypeExists("tt4"), "New traffic types should exist")

// Verify change number is updated
cn, err := splitStorage.ChangeNumber()
assert.NoError(t, err)
assert.Equal(t, int64(200), cn, "Change number should be updated to 200")

// Test replacing with empty list
splitStorage.ReplaceAll([]dtos.SplitDTO{}, 300)
assert.Empty(t, splitStorage.All(), "All splits should be removed when replacing with empty list")
cn, err = splitStorage.ChangeNumber()
assert.NoError(t, err)
assert.Equal(t, int64(300), cn, "Change number should be updated to 300")
}

func TestLargeSegmentNames(t *testing.T) {
splitStorage := NewMMSplitStorage(flagsets.NewFlagSetFilter(nil))

Expand Down
2 changes: 2 additions & 0 deletions storage/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type SplitStorageProducer interface {
Update(toAdd []dtos.SplitDTO, toRemove []dtos.SplitDTO, changeNumber int64)
KillLocally(splitName string, defaultTreatment string, changeNumber int64)
SetChangeNumber(changeNumber int64) error
ReplaceAll(toAdd []dtos.SplitDTO, changeNumber int64)
}

// SplitStorageConsumer should be implemented by structs that offer reading splits from storage
Expand Down Expand Up @@ -211,6 +212,7 @@ type SplitStorage interface {
TrafficTypeExists(trafficType string) bool
GetNamesByFlagSets(sets []string) map[string][]string
GetAllFlagSetNames() []string
ReplaceAll(toAdd []dtos.SplitDTO, changeNumber int64)
}

// SegmentStorage wraps consumer and producer interfaces
Expand Down
5 changes: 5 additions & 0 deletions storage/mocks/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type MockSplitStorage struct {
TrafficTypeExistsCall func(trafficType string) bool
GetNamesByFlagSetsCall func(sets []string) map[string][]string
GetAllFlagSetNamesCall func() []string
ReplaceAllCall func(toAdd []dtos.SplitDTO, changeNumber int64)
}

// All mock
Expand Down Expand Up @@ -91,3 +92,7 @@ func (m MockSplitStorage) GetNamesByFlagSets(sets []string) map[string][]string
func (m MockSplitStorage) GetAllFlagSetNames() []string {
return m.GetAllFlagSetNamesCall()
}

func (m MockSplitStorage) ReplaceAll(toAdd []dtos.SplitDTO, changeNumber int64) {
m.ReplaceAllCall(toAdd, changeNumber)
}
4 changes: 4 additions & 0 deletions storage/redis/splits.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,4 +493,8 @@ func (r *SplitStorage) splitKeysClusterMode() ([]string, error) {
return result, nil
}

func (r *SplitStorage) ReplaceAll(toAdd []dtos.SplitDTO, changeNumber int64) {
//to do
}

var _ storage.SplitStorage = (*SplitStorage)(nil)
Loading