|
6 | 6 | package commontest
|
7 | 7 |
|
8 | 8 | import (
|
| 9 | + "cmp" |
9 | 10 | "context"
|
| 11 | + "slices" |
10 | 12 | "testing"
|
11 | 13 |
|
12 | 14 | "github.com/cockroachdb/cockroach/pkg/keys"
|
@@ -987,6 +989,135 @@ func (suite *StoreTestSuite) TestTryRemoveFromPartition() {
|
987 | 989 | }
|
988 | 990 | }
|
989 | 991 |
|
| 992 | +func (suite *StoreTestSuite) TestTryMoveVector() { |
| 993 | + store := suite.makeStore(suite.quantizer) |
| 994 | + defer store.Close(suite.T()) |
| 995 | + |
| 996 | + doTest := func(treeID int) { |
| 997 | + treeKey := store.MakeTreeKey(suite.T(), treeID) |
| 998 | + |
| 999 | + // Create source partition with some vectors. |
| 1000 | + sourcePartitionKey, _ := suite.createTestPartition(store, treeKey) |
| 1001 | + |
| 1002 | + // Create empty target partition. |
| 1003 | + targetPartitionKey := cspann.PartitionKey(20) |
| 1004 | + metadata := cspann.PartitionMetadata{ |
| 1005 | + Level: cspann.SecondLevel, |
| 1006 | + Centroid: vector.T{2, 4}, |
| 1007 | + } |
| 1008 | + metadata.StateDetails.MakeReady() |
| 1009 | + suite.NoError(store.TryCreateEmptyPartition(suite.ctx, treeKey, targetPartitionKey, metadata)) |
| 1010 | + targetPartition, err := store.TryGetPartition(suite.ctx, treeKey, targetPartitionKey) |
| 1011 | + suite.NoError(err) |
| 1012 | + |
| 1013 | + // Source partition does not yet exist. |
| 1014 | + expected := *targetPartition.Metadata() |
| 1015 | + moved, err := store.TryMoveVector( |
| 1016 | + suite.ctx, treeKey, cspann.PartitionKey(99), targetPartitionKey, |
| 1017 | + vec1, partitionKey1, valueBytes1, expected) |
| 1018 | + suite.NoError(err) |
| 1019 | + suite.False(moved) |
| 1020 | + |
| 1021 | + // Destination partition does not yet exist. |
| 1022 | + moved, err = store.TryMoveVector( |
| 1023 | + suite.ctx, treeKey, sourcePartitionKey, cspann.PartitionKey(99), |
| 1024 | + vec1, partitionKey1, valueBytes1, cspann.PartitionMetadata{}) |
| 1025 | + suite.NoError(err) |
| 1026 | + suite.False(moved) |
| 1027 | + |
| 1028 | + // Source partition is the same as destination partition. |
| 1029 | + moved, err = store.TryMoveVector( |
| 1030 | + suite.ctx, treeKey, sourcePartitionKey, sourcePartitionKey, |
| 1031 | + vec1, partitionKey1, valueBytes1, expected) |
| 1032 | + suite.NoError(err) |
| 1033 | + suite.False(moved) |
| 1034 | + |
| 1035 | + // Now move should work. |
| 1036 | + moved, err = store.TryMoveVector( |
| 1037 | + suite.ctx, treeKey, sourcePartitionKey, targetPartitionKey, |
| 1038 | + vec1, partitionKey1, valueBytes1, expected) |
| 1039 | + suite.NoError(err) |
| 1040 | + suite.True(moved) |
| 1041 | + |
| 1042 | + // Fetch back the target partition and validate it. |
| 1043 | + targetPartition, err = store.TryGetPartition(suite.ctx, treeKey, targetPartitionKey) |
| 1044 | + suite.NoError(err) |
| 1045 | + suite.Equal([]cspann.ChildKey{partitionKey1}, targetPartition.ChildKeys()) |
| 1046 | + suite.Equal([]cspann.ValueBytes{valueBytes1}, targetPartition.ValueBytes()) |
| 1047 | + |
| 1048 | + // Try to move again, but with mismatched expected metadata. |
| 1049 | + var errConditionFailed *cspann.ConditionFailedError |
| 1050 | + metadata = expected |
| 1051 | + metadata.StateDetails.State = cspann.DrainingForMergeState |
| 1052 | + moved, err = store.TryMoveVector( |
| 1053 | + suite.ctx, treeKey, sourcePartitionKey, targetPartitionKey, |
| 1054 | + vec1, partitionKey3, valueBytes3, metadata) |
| 1055 | + suite.ErrorAs(err, &errConditionFailed) |
| 1056 | + suite.False(moved) |
| 1057 | + suite.True(errConditionFailed.Actual.Equal(&expected)) |
| 1058 | + |
| 1059 | + // Try again, this time with correct expected metadata. |
| 1060 | + moved, err = store.TryMoveVector( |
| 1061 | + suite.ctx, treeKey, sourcePartitionKey, targetPartitionKey, |
| 1062 | + vec1, partitionKey3, valueBytes3, expected) |
| 1063 | + suite.NoError(err) |
| 1064 | + suite.True(moved) |
| 1065 | + |
| 1066 | + // Fetch back the source partition and validate it. |
| 1067 | + sourcePartition, err := store.TryGetPartition(suite.ctx, treeKey, sourcePartitionKey) |
| 1068 | + suite.NoError(err) |
| 1069 | + suite.Equal([]cspann.ChildKey{partitionKey2}, sourcePartition.ChildKeys()) |
| 1070 | + suite.Equal([]cspann.ValueBytes{valueBytes2}, sourcePartition.ValueBytes()) |
| 1071 | + |
| 1072 | + // Try to move a vector that no longer exists in the source partition. |
| 1073 | + moved, err = store.TryMoveVector( |
| 1074 | + suite.ctx, treeKey, sourcePartitionKey, targetPartitionKey, |
| 1075 | + vec1, partitionKey3, valueBytes3, expected) |
| 1076 | + suite.NoError(err) |
| 1077 | + suite.False(moved) |
| 1078 | + |
| 1079 | + // Try to move a vector that already exists in the target partition. |
| 1080 | + added, err := store.TryAddToPartition( |
| 1081 | + suite.ctx, treeKey, targetPartitionKey, vec2.AsSet(), |
| 1082 | + []cspann.ChildKey{partitionKey2}, []cspann.ValueBytes{valueBytes2}, expected) |
| 1083 | + suite.NoError(err) |
| 1084 | + suite.True(added) |
| 1085 | + |
| 1086 | + moved, err = store.TryMoveVector( |
| 1087 | + suite.ctx, treeKey, sourcePartitionKey, targetPartitionKey, |
| 1088 | + vec1, partitionKey2, valueBytes2, expected) |
| 1089 | + suite.NoError(err) |
| 1090 | + suite.False(moved) |
| 1091 | + |
| 1092 | + // Ensure that the vector was not removed from the source partition. |
| 1093 | + sourcePartition, err = store.TryGetPartition(suite.ctx, treeKey, sourcePartitionKey) |
| 1094 | + suite.NoError(err) |
| 1095 | + suite.Equal([]cspann.ChildKey{partitionKey2}, sourcePartition.ChildKeys()) |
| 1096 | + suite.Equal([]cspann.ValueBytes{valueBytes2}, sourcePartition.ValueBytes()) |
| 1097 | + |
| 1098 | + // Ensure that the target partition now has all three vectors. |
| 1099 | + targetPartition, err = store.TryGetPartition(suite.ctx, treeKey, targetPartitionKey) |
| 1100 | + suite.NoError(err) |
| 1101 | + suite.Equal(3, targetPartition.Count()) |
| 1102 | + childKeys := slices.Clone(targetPartition.ChildKeys()) |
| 1103 | + slices.SortFunc(childKeys, func(a, b cspann.ChildKey) int { |
| 1104 | + return cmp.Compare(a.PartitionKey, b.PartitionKey) |
| 1105 | + }) |
| 1106 | + suite.Equal([]cspann.ChildKey{partitionKey1, partitionKey2, partitionKey3}, childKeys) |
| 1107 | + } |
| 1108 | + |
| 1109 | + suite.Run("default tree", func() { |
| 1110 | + doTest(0) |
| 1111 | + }) |
| 1112 | + |
| 1113 | + if store.AllowMultipleTrees() { |
| 1114 | + // Ensure that vectors are independent across trees. |
| 1115 | + suite.Run("different tree", func() { |
| 1116 | + doTest(1) |
| 1117 | + }) |
| 1118 | + } |
| 1119 | +} |
| 1120 | + |
990 | 1121 | func (suite *StoreTestSuite) TestTryClearPartition() {
|
991 | 1122 | store := suite.makeStore(suite.quantizer)
|
992 | 1123 | defer store.Close(suite.T())
|
|
0 commit comments