Skip to content

Commit c78d4db

Browse files
craig[bot]irfansharif
craig[bot]
andcommitted
Merge #40260
40260: storage/spanlatch: add test for overlapping spans r=irfansharif a=irfansharif When overlapping spans are acquired, the spanlatch Manager should grant access based on the more restrictive latch over the specific overlapped sub-span. Release note: None Co-authored-by: irfan sharif <[email protected]>
2 parents 08c90fb + b98fef3 commit c78d4db

File tree

3 files changed

+73
-17
lines changed

3 files changed

+73
-17
lines changed

pkg/storage/spanlatch/manager.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import (
2828
)
2929

3030
// A Manager maintains an interval tree of key and key range latches. Latch
31-
// acquitions affecting keys or key ranges must wait on already-acquired latches
32-
// which overlap their key ranges to be released.
31+
// acquisitions affecting keys or key ranges must wait on already-acquired
32+
// latches which overlap their key ranges to be released.
3333
//
3434
// Latch acquisition attempts invoke Manager.Acquire and provide details about
3535
// the spans that they plan to touch and the timestamps they plan to touch them

pkg/storage/spanlatch/manager_test.go

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,30 @@ var write = true
3333
var zeroTS = hlc.Timestamp{}
3434

3535
func spans(from, to string, write bool) *spanset.SpanSet {
36-
var span roachpb.Span
36+
var spans spanset.SpanSet
37+
add(&spans, from, to, write)
38+
return &spans
39+
}
40+
41+
func add(spans *spanset.SpanSet, from, to string, write bool) {
42+
var start, end roachpb.Key
3743
if to == "" {
38-
span = roachpb.Span{Key: roachpb.Key(from)}
44+
start = roachpb.Key(from)
3945
} else {
40-
span = roachpb.Span{Key: roachpb.Key(from), EndKey: roachpb.Key(to)}
46+
start = roachpb.Key(from)
47+
end = roachpb.Key(to)
4148
}
4249
if strings.HasPrefix(from, "local") {
43-
span.Key = append(keys.LocalRangePrefix, span.Key...)
44-
if span.EndKey != nil {
45-
span.EndKey = append(keys.LocalRangePrefix, span.EndKey...)
50+
start = append(keys.LocalRangePrefix, start...)
51+
if end != nil {
52+
end = append(keys.LocalRangePrefix, end...)
4653
}
4754
}
48-
var spans spanset.SpanSet
4955
access := spanset.SpanReadOnly
5056
if write {
5157
access = spanset.SpanReadWrite
5258
}
53-
spans.Add(access, span)
54-
return &spans
59+
spans.Add(access, roachpb.Span{Key: start, EndKey: end})
5560
}
5661

5762
func testLatchSucceeds(t *testing.T, lgC <-chan *Guard) *Guard {
@@ -118,7 +123,7 @@ func TestLatchManager(t *testing.T) {
118123
defer leaktest.AfterTest(t)()
119124
var m Manager
120125

121-
// Try latches with no overlapping already-acquired lathes.
126+
// Try latches with no overlapping already-acquired latches.
122127
lg1 := m.MustAcquire(spans("a", "", write), zeroTS)
123128
m.Release(lg1)
124129

@@ -137,6 +142,50 @@ func TestLatchManager(t *testing.T) {
137142
testLatchSucceeds(t, lg4C)
138143
}
139144

145+
func TestLatchManagerAcquireOverlappingSpans(t *testing.T) {
146+
defer leaktest.AfterTest(t)()
147+
var m Manager
148+
149+
// Acquire overlapping latches with different access patterns.
150+
// |----------| <- Read latch [a-c)@t1
151+
// |----------| <- Write latch [b-d)@t1
152+
//
153+
// ^ ^ ^ ^
154+
// | | | |
155+
// a b c d
156+
//
157+
var ts0, ts1 = hlc.Timestamp{WallTime: 0}, hlc.Timestamp{WallTime: 1}
158+
var spanSet spanset.SpanSet
159+
add(&spanSet, "a", "c", read)
160+
add(&spanSet, "b", "d", write)
161+
lg1 := m.MustAcquire(&spanSet, ts1)
162+
163+
lg2C := m.MustAcquireCh(spans("a", "b", read), ts0)
164+
lg2 := testLatchSucceeds(t, lg2C)
165+
m.Release(lg2)
166+
167+
// We acquire reads at lower timestamps than writes to check for blocked
168+
// acquisitions based on the original latch, not the latches declared in
169+
// earlier test cases.
170+
var latchCs []<-chan *Guard
171+
latchCs = append(latchCs, m.MustAcquireCh(spans("a", "b", write), ts1))
172+
latchCs = append(latchCs, m.MustAcquireCh(spans("b", "c", read), ts0))
173+
latchCs = append(latchCs, m.MustAcquireCh(spans("b", "c", write), ts1))
174+
latchCs = append(latchCs, m.MustAcquireCh(spans("c", "d", write), ts1))
175+
latchCs = append(latchCs, m.MustAcquireCh(spans("c", "d", read), ts0))
176+
177+
for _, lgC := range latchCs {
178+
testLatchBlocks(t, lgC)
179+
}
180+
181+
m.Release(lg1)
182+
183+
for _, lgC := range latchCs {
184+
lg := testLatchSucceeds(t, lgC)
185+
m.Release(lg)
186+
}
187+
}
188+
140189
func TestLatchManagerNoWaitOnReadOnly(t *testing.T) {
141190
defer leaktest.AfterTest(t)()
142191
var m Manager
@@ -207,11 +256,11 @@ func TestLatchManagerMultipleOverlappingSpans(t *testing.T) {
207256
lg4 := m.MustAcquire(spans("g", "", write), zeroTS)
208257

209258
// Attempt to acquire latches overlapping each of them.
210-
var spans spanset.SpanSet
211-
spans.Add(spanset.SpanReadWrite, roachpb.Span{Key: roachpb.Key("a")})
212-
spans.Add(spanset.SpanReadWrite, roachpb.Span{Key: roachpb.Key("b")})
213-
spans.Add(spanset.SpanReadWrite, roachpb.Span{Key: roachpb.Key("e")})
214-
lg5C := m.MustAcquireCh(&spans, zeroTS)
259+
var spanSet spanset.SpanSet
260+
add(&spanSet, "a", "", write)
261+
add(&spanSet, "b", "", write)
262+
add(&spanSet, "e", "", write)
263+
lg5C := m.MustAcquireCh(&spanSet, zeroTS)
215264

216265
// Blocks until the first three prerequisite latches release.
217266
testLatchBlocks(t, lg5C)

pkg/storage/spanset/spanset.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ func (ss *SpanSet) AssertAllowed(access SpanAccess, span roachpb.Span) {
150150
}
151151

152152
// CheckAllowed returns an error if the access is not allowed.
153+
//
154+
// TODO(irfansharif): This does not currently work for spans that straddle
155+
// across multiple added spans. Specifically a spanset with spans [a-c) and
156+
// [b-d) added under read only and read write access modes respectively would
157+
// fail at checking if read only access over the span [a-d) was requested. This
158+
// is also a problem if the added spans were read only and the spanset wasn't
159+
// already SortAndDedup-ed.
153160
func (ss *SpanSet) CheckAllowed(access SpanAccess, span roachpb.Span) error {
154161
scope := SpanGlobal
155162
if keys.IsLocal(span.Key) {

0 commit comments

Comments
 (0)