Skip to content

Commit 62c553c

Browse files
committed
cspann: do not overwrite root level when searching targets
In the case where the root partition is in a non-Ready state, we need to search its target partitions. Previously, we were overwriting the root partition's level, which should be the same as the root partition's level. However, if there's a bug, it can be different, and overriding the root level causes cascading problems downstream, including a panic that can take down the server. This commit adds code to check the level and assert that it's equal to the root partition level rather than silently overwriting it. Epic: CRDB-42943 Release note: None
1 parent 1496755 commit 62c553c

File tree

3 files changed

+78
-14
lines changed

3 files changed

+78
-14
lines changed

pkg/sql/vecindex/cspann/index.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,17 +1107,6 @@ func (vi *Index) Format(
11071107
return buf.String(), nil
11081108
}
11091109

1110-
// ensureSliceCap returns a slice of length = 0, of the given capacity and
1111-
// generic type. If the existing slice has enough capacity, that slice is
1112-
// returned after setting its length to zero. Otherwise, a new, larger slice is
1113-
// allocated.
1114-
func ensureSliceCap[T any](s []T, c int) []T {
1115-
if cap(s) < c {
1116-
return make([]T, 0, c)
1117-
}
1118-
return s[:0]
1119-
}
1120-
11211110
// ensureSliceLen returns a slice of the given length and generic type. If the
11221111
// existing slice has enough capacity, that slice is returned after adjusting
11231112
// its length. Otherwise, a new, larger slice is allocated.

pkg/sql/vecindex/cspann/searcher.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func (s *searcher) Next(ctx context.Context) (ok bool, err error) {
9393
// Next must have been called by an insert operation. This code path
9494
// should only be hit when the insert needs to go into the root partition.
9595
if root.Level() != s.idxCtx.level-1 {
96-
panic(errors.AssertionFailedf("caller passed invalid level %d", s.idxCtx.level))
96+
return false, errors.AssertionFailedf("caller passed invalid level %d", s.idxCtx.level)
9797
}
9898
s.searchSet.Add(&SearchResult{
9999
ChildKey: ChildKey{PartitionKey: RootKey},
@@ -479,11 +479,15 @@ func (s *levelSearcher) searchChildPartitions(
479479
// In the DrainingForSplit state, the target partitions are still at
480480
// the same level as the root partition, so merge their contents into
481481
// the search set (which will remove any duplicates).
482-
s.idxCtx.tempToSearch = ensureSliceCap(s.idxCtx.tempToSearch, 2)
483-
level, err = s.searchChildPartitions(ctx, s.tempResults[:2])
482+
targetLevel, err := s.searchChildPartitions(ctx, s.tempResults[:2])
484483
if err != nil {
485484
return InvalidLevel, err
486485
}
486+
if targetLevel != level {
487+
return InvalidLevel, errors.AssertionFailedf(
488+
"target partitions cannot have level %d when DrainingForSplit root has level %d",
489+
targetLevel, level)
490+
}
487491
} else if rootState.State == AddingLevelState {
488492
// In the AddingLevel state, the target partitions should be treated as
489493
// children of the root partition. Add their partition keys to the search

pkg/sql/vecindex/cspann/testdata/search-for-insert.ddt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,74 @@ format-tree
108108
├───• vec2 (7, 4)
109109
├───• vec4 (5, 5)
110110
└───• vec5 (8, 11)
111+
112+
# ----------------------------------------------------------------------
113+
# Search for insert when tree is empty in various states.
114+
# ----------------------------------------------------------------------
115+
116+
# Splitting state.
117+
load-index min-partition-size=1 max-partition-size=3 beam-size=2
118+
• 1 (0, 0) [Splitting:2,3]
119+
----
120+
Loaded 0 vectors.
121+
122+
search-for-insert
123+
(1, 1)
124+
----
125+
partition 1, centroid=(0, 0), sqdist=0
126+
127+
# DrainingForSplit state.
128+
load-index min-partition-size=1 max-partition-size=3 beam-size=2
129+
• 1 (0, 0)
130+
----
131+
Loaded 0 vectors.
132+
133+
force-split partition-key=1 steps=4
134+
----
135+
• 1 (0, 0) [DrainingForSplit:2,3]
136+
137+
search-for-insert
138+
(1, 1)
139+
----
140+
partition 2, centroid=(0, 0), sqdist=2
141+
142+
# AddingLevel state before sub-partitions have been added.
143+
load-index min-partition-size=1 max-partition-size=3 beam-size=2
144+
• 1 (0, 0) [AddingLevel:2,3]
145+
----
146+
Loaded 0 vectors.
147+
148+
search-for-insert
149+
(1, 1)
150+
----
151+
partition 1, centroid=(0, 0), sqdist=0
152+
153+
# AddingLevel state after sub-partitions have been added.
154+
load-index min-partition-size=1 max-partition-size=3 beam-size=2
155+
• 1 (0, 0) [AddingLevel:2,3]
156+
157+
├───• 2 (1, 1)
158+
159+
└───• 3 (2, 2)
160+
----
161+
Loaded 0 vectors.
162+
163+
search-for-insert
164+
(1, 1)
165+
----
166+
partition 2, centroid=(1, 1), sqdist=0
167+
168+
# DeletingForSplit state.
169+
load-index min-partition-size=1 max-partition-size=3 beam-size=2
170+
• 1 (0, 0)
171+
172+
├───• 2 (1, 1) [DeletingForSplit:2,3]
173+
174+
└───• 3 (2, 2)
175+
----
176+
Loaded 0 vectors.
177+
178+
search-for-insert
179+
(1, 1)
180+
----
181+
partition 3, centroid=(2, 2), sqdist=2

0 commit comments

Comments
 (0)