github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/spanlatch/manager_test.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package spanlatch 12 13 import ( 14 "bytes" 15 "context" 16 "fmt" 17 "math/rand" 18 "strings" 19 "testing" 20 "time" 21 22 "github.com/cockroachdb/cockroach/pkg/keys" 23 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/spanset" 24 "github.com/cockroachdb/cockroach/pkg/roachpb" 25 "github.com/cockroachdb/cockroach/pkg/testutils" 26 "github.com/cockroachdb/cockroach/pkg/util/hlc" 27 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 28 "github.com/stretchr/testify/require" 29 ) 30 31 var read = false 32 var write = true 33 var zeroTS = hlc.Timestamp{} 34 35 func spans(from, to string, write bool, ts hlc.Timestamp) *spanset.SpanSet { 36 var spanSet spanset.SpanSet 37 add(&spanSet, from, to, write, ts) 38 return &spanSet 39 } 40 41 func add(spanSet *spanset.SpanSet, from, to string, write bool, ts hlc.Timestamp) { 42 var start, end roachpb.Key 43 if to == "" { 44 start = roachpb.Key(from) 45 } else { 46 start = roachpb.Key(from) 47 end = roachpb.Key(to) 48 } 49 if strings.HasPrefix(from, "local") { 50 start = append(keys.LocalRangePrefix, start...) 51 if end != nil { 52 end = append(keys.LocalRangePrefix, end...) 53 } 54 } 55 access := spanset.SpanReadOnly 56 if write { 57 access = spanset.SpanReadWrite 58 } 59 60 if strings.HasPrefix(from, "local") { 61 spanSet.AddNonMVCC(access, roachpb.Span{Key: start, EndKey: end}) 62 } else { 63 spanSet.AddMVCC(access, roachpb.Span{Key: start, EndKey: end}, ts) 64 } 65 } 66 67 func testLatchSucceeds(t *testing.T, lgC <-chan *Guard) *Guard { 68 t.Helper() 69 select { 70 case lg := <-lgC: 71 return lg 72 case <-time.After(testutils.DefaultSucceedsSoonDuration): 73 // False positives are not ok, so we use a more 74 // conservative timeout than in testLatchBlocks. 75 t.Fatal("latch acquisition should succeed") 76 } 77 return nil 78 } 79 80 func testLatchBlocks(t *testing.T, lgC <-chan *Guard) { 81 t.Helper() 82 select { 83 case <-lgC: 84 t.Fatal("latch acquisition should block") 85 case <-time.After(3 * time.Millisecond): 86 // False positives are ok as long as they are rare, so we 87 // use an aggressive timeout to avoid slowing down tests. 88 } 89 } 90 91 // MustAcquire is like Acquire, except it can't return context cancellation 92 // errors. 93 func (m *Manager) MustAcquire(spans *spanset.SpanSet) *Guard { 94 lg, err := m.Acquire(context.Background(), spans) 95 if err != nil { 96 panic(err) 97 } 98 return lg 99 } 100 101 // MustAcquireCh is like Acquire, except it only sequences the latch latch 102 // attempt synchronously and waits on dependent latches asynchronously. It 103 // returns a channel that provides the Guard when the latches are acquired (i.e. 104 // after waiting). If the context expires, a nil Guard will be delivered on the 105 // channel. 106 func (m *Manager) MustAcquireCh(spans *spanset.SpanSet) <-chan *Guard { 107 return m.MustAcquireChCtx(context.Background(), spans) 108 } 109 110 // MustAcquireChCtx is like MustAcquireCh, except it accepts a context. 111 func (m *Manager) MustAcquireChCtx(ctx context.Context, spans *spanset.SpanSet) <-chan *Guard { 112 ch := make(chan *Guard) 113 lg, snap := m.sequence(spans) 114 go func() { 115 err := m.wait(ctx, lg, snap) 116 if err != nil { 117 m.Release(lg) 118 lg = nil 119 } 120 ch <- lg 121 }() 122 return ch 123 } 124 125 func TestLatchManager(t *testing.T) { 126 defer leaktest.AfterTest(t)() 127 var m Manager 128 129 // Try latches with no overlapping already-acquired latches. 130 lg1 := m.MustAcquire(spans("a", "", write, zeroTS)) 131 m.Release(lg1) 132 133 lg2 := m.MustAcquire(spans("a", "b", write, zeroTS)) 134 m.Release(lg2) 135 136 // Add a latch and verify overlapping latches wait on it. 137 lg3 := m.MustAcquire(spans("a", "b", write, zeroTS)) 138 lg4C := m.MustAcquireCh(spans("a", "b", write, zeroTS)) 139 140 // Second write should block. 141 testLatchBlocks(t, lg4C) 142 143 // First write completes, second grabs latch. 144 m.Release(lg3) 145 testLatchSucceeds(t, lg4C) 146 } 147 148 func TestLatchManagerAcquireOverlappingSpans(t *testing.T) { 149 defer leaktest.AfterTest(t)() 150 var m Manager 151 152 // Acquire overlapping latches with different access patterns. 153 // |----------| <- Read latch [a-c)@t1 154 // |----------| <- Write latch [b-d)@t1 155 // 156 // ^ ^ ^ ^ 157 // | | | | 158 // a b c d 159 // 160 var ts0, ts1 = hlc.Timestamp{WallTime: 0}, hlc.Timestamp{WallTime: 1} 161 var spanSet spanset.SpanSet 162 add(&spanSet, "a", "c", read, ts1) 163 add(&spanSet, "b", "d", write, ts1) 164 lg1 := m.MustAcquire(&spanSet) 165 166 lg2C := m.MustAcquireCh(spans("a", "b", read, ts0)) 167 lg2 := testLatchSucceeds(t, lg2C) 168 m.Release(lg2) 169 170 // We acquire reads at lower timestamps than writes to check for blocked 171 // acquisitions based on the original latch, not the latches declared in 172 // earlier test cases. 173 var latchCs []<-chan *Guard 174 latchCs = append(latchCs, m.MustAcquireCh(spans("a", "b", write, ts1))) 175 latchCs = append(latchCs, m.MustAcquireCh(spans("b", "c", read, ts0))) 176 latchCs = append(latchCs, m.MustAcquireCh(spans("b", "c", write, ts1))) 177 latchCs = append(latchCs, m.MustAcquireCh(spans("c", "d", write, ts1))) 178 latchCs = append(latchCs, m.MustAcquireCh(spans("c", "d", read, ts0))) 179 180 for _, lgC := range latchCs { 181 testLatchBlocks(t, lgC) 182 } 183 184 m.Release(lg1) 185 186 for _, lgC := range latchCs { 187 lg := testLatchSucceeds(t, lgC) 188 m.Release(lg) 189 } 190 } 191 192 func TestLatchManagerAcquiringReadsVaryingTimestamps(t *testing.T) { 193 defer leaktest.AfterTest(t)() 194 var m Manager 195 196 var ts0, ts1 = hlc.Timestamp{WallTime: 0}, hlc.Timestamp{WallTime: 1} 197 var spanSet spanset.SpanSet 198 add(&spanSet, "a", "", read, ts0) 199 add(&spanSet, "a", "", read, ts1) 200 lg1 := m.MustAcquire(&spanSet) 201 202 for _, walltime := range []int64{0, 1, 2} { 203 ts := hlc.Timestamp{WallTime: walltime} 204 lg := testLatchSucceeds(t, m.MustAcquireCh(spans("a", "", read, ts))) 205 m.Release(lg) 206 } 207 208 var latchCs []<-chan *Guard 209 for _, walltime := range []int64{0, 1, 2} { 210 ts := hlc.Timestamp{WallTime: walltime} 211 latchCs = append(latchCs, m.MustAcquireCh(spans("a", "", write, ts))) 212 } 213 214 for _, lgC := range latchCs { 215 testLatchBlocks(t, lgC) 216 } 217 218 m.Release(lg1) 219 220 for _, lgC := range latchCs { 221 lg := testLatchSucceeds(t, lgC) 222 m.Release(lg) 223 } 224 } 225 226 func TestLatchManagerNoWaitOnReadOnly(t *testing.T) { 227 defer leaktest.AfterTest(t)() 228 var m Manager 229 230 // Acquire latch for read-only span. 231 m.MustAcquire(spans("a", "", read, zeroTS)) 232 233 // Verify no wait with another read-only span. 234 m.MustAcquire(spans("a", "", read, zeroTS)) 235 } 236 237 func TestLatchManagerWriteWaitForMultipleReads(t *testing.T) { 238 defer leaktest.AfterTest(t)() 239 var m Manager 240 241 // Acquire latch for read-only span. 242 lg1 := m.MustAcquire(spans("a", "", read, zeroTS)) 243 // Acquire another one on top. 244 lg2 := m.MustAcquire(spans("a", "", read, zeroTS)) 245 246 // A write span should have to wait for **both** reads. 247 lg3C := m.MustAcquireCh(spans("a", "", write, zeroTS)) 248 249 // Certainly blocks now. 250 testLatchBlocks(t, lg3C) 251 252 // The second read releases latch, but the first one remains. 253 m.Release(lg2) 254 255 // Should still block. 256 testLatchBlocks(t, lg3C) 257 258 // First read releases latch. 259 m.Release(lg1) 260 261 // Now it goes through. 262 testLatchSucceeds(t, lg3C) 263 } 264 265 func TestLatchManagerMultipleOverlappingLatches(t *testing.T) { 266 defer leaktest.AfterTest(t)() 267 var m Manager 268 269 // Acquire multiple latches. 270 lg1C := m.MustAcquireCh(spans("a", "", write, zeroTS)) 271 lg2C := m.MustAcquireCh(spans("b", "c", write, zeroTS)) 272 lg3C := m.MustAcquireCh(spans("a", "d", write, zeroTS)) 273 274 // Attempt to acquire latch which overlaps them all. 275 lg4C := m.MustAcquireCh(spans("0", "z", write, zeroTS)) 276 testLatchBlocks(t, lg4C) 277 m.Release(<-lg1C) 278 testLatchBlocks(t, lg4C) 279 m.Release(<-lg2C) 280 testLatchBlocks(t, lg4C) 281 m.Release(<-lg3C) 282 testLatchSucceeds(t, lg4C) 283 } 284 285 func TestLatchManagerMultipleOverlappingSpans(t *testing.T) { 286 defer leaktest.AfterTest(t)() 287 var m Manager 288 289 // Acquire multiple latches. 290 lg1 := m.MustAcquire(spans("a", "", write, zeroTS)) 291 lg2 := m.MustAcquire(spans("b", "c", read, zeroTS)) 292 lg3 := m.MustAcquire(spans("d", "f", write, zeroTS)) 293 lg4 := m.MustAcquire(spans("g", "", write, zeroTS)) 294 295 // Attempt to acquire latches overlapping each of them. 296 var spans spanset.SpanSet 297 spans.AddNonMVCC(spanset.SpanReadWrite, roachpb.Span{Key: roachpb.Key("a")}) 298 spans.AddNonMVCC(spanset.SpanReadWrite, roachpb.Span{Key: roachpb.Key("b")}) 299 spans.AddNonMVCC(spanset.SpanReadWrite, roachpb.Span{Key: roachpb.Key("e")}) 300 lg5C := m.MustAcquireCh(&spans) 301 302 // Blocks until the first three prerequisite latches release. 303 testLatchBlocks(t, lg5C) 304 m.Release(lg2) 305 testLatchBlocks(t, lg5C) 306 m.Release(lg3) 307 testLatchBlocks(t, lg5C) 308 m.Release(lg1) 309 lg5 := testLatchSucceeds(t, lg5C) 310 m.Release(lg4) 311 m.Release(lg5) 312 } 313 314 func TestLatchManagerDependentLatches(t *testing.T) { 315 defer leaktest.AfterTest(t)() 316 317 cases := []struct { 318 name string 319 sp1 *spanset.SpanSet 320 sp2 *spanset.SpanSet 321 dependent bool 322 }{ 323 { 324 name: "point writes, same key", 325 sp1: spans("a", "", write, zeroTS), 326 sp2: spans("a", "", write, zeroTS), 327 dependent: true, 328 }, 329 { 330 name: "point writes, different key", 331 sp1: spans("a", "", write, zeroTS), 332 sp2: spans("b", "", write, zeroTS), 333 dependent: false, 334 }, 335 { 336 name: "range writes, overlapping span", 337 sp1: spans("a", "c", write, zeroTS), 338 sp2: spans("b", "d", write, zeroTS), 339 dependent: true, 340 }, 341 { 342 name: "range writes, non-overlapping span", 343 sp1: spans("a", "b", write, zeroTS), 344 sp2: spans("b", "c", write, zeroTS), 345 dependent: false, 346 }, 347 { 348 name: "point reads, same key", 349 sp1: spans("a", "", read, zeroTS), 350 sp2: spans("a", "", read, zeroTS), 351 dependent: false, 352 }, 353 { 354 name: "point reads, different key", 355 sp1: spans("a", "", read, zeroTS), 356 sp2: spans("b", "", read, zeroTS), 357 dependent: false, 358 }, 359 { 360 name: "range reads, overlapping span", 361 sp1: spans("a", "c", read, zeroTS), 362 sp2: spans("b", "d", read, zeroTS), 363 dependent: false, 364 }, 365 { 366 name: "range reads, non-overlapping span", 367 sp1: spans("a", "b", read, zeroTS), 368 sp2: spans("b", "c", read, zeroTS), 369 dependent: false, 370 }, 371 { 372 name: "read and write, same ts", 373 sp1: spans("a", "", write, hlc.Timestamp{WallTime: 1}), 374 sp2: spans("a", "", read, hlc.Timestamp{WallTime: 1}), 375 dependent: true, 376 }, 377 { 378 name: "read and write, causal ts", 379 sp1: spans("a", "", write, hlc.Timestamp{WallTime: 1}), 380 sp2: spans("a", "", read, hlc.Timestamp{WallTime: 2}), 381 dependent: true, 382 }, 383 { 384 name: "read and write, non-causal ts", 385 sp1: spans("a", "", write, hlc.Timestamp{WallTime: 2}), 386 sp2: spans("a", "", read, hlc.Timestamp{WallTime: 1}), 387 dependent: false, 388 }, 389 { 390 name: "read and write, zero ts read", 391 sp1: spans("a", "", write, hlc.Timestamp{WallTime: 1}), 392 sp2: spans("a", "", read, hlc.Timestamp{WallTime: 0}), 393 dependent: true, 394 }, 395 { 396 name: "point reads, different ts", 397 sp1: spans("a", "", read, hlc.Timestamp{WallTime: 1}), 398 sp2: spans("a", "", read, hlc.Timestamp{WallTime: 0}), 399 dependent: false, 400 }, 401 { 402 name: "read and write, zero ts write", 403 sp1: spans("a", "", write, hlc.Timestamp{WallTime: 0}), 404 sp2: spans("a", "", read, hlc.Timestamp{WallTime: 1}), 405 dependent: true, 406 }, 407 { 408 name: "read and write, non-overlapping", 409 sp1: spans("a", "b", write, zeroTS), 410 sp2: spans("b", "", read, zeroTS), 411 dependent: false, 412 }, 413 { 414 name: "local range writes, overlapping span", 415 sp1: spans("local a", "local c", write, zeroTS), 416 sp2: spans("local b", "local d", write, zeroTS), 417 dependent: true, 418 }, 419 { 420 name: "local range writes, non-overlapping span", 421 sp1: spans("local a", "local b", write, zeroTS), 422 sp2: spans("local b", "local c", write, zeroTS), 423 dependent: false, 424 }, 425 { 426 name: "local range reads, overlapping span", 427 sp1: spans("local a", "local c", read, zeroTS), 428 sp2: spans("local b", "local d", read, zeroTS), 429 dependent: false, 430 }, 431 { 432 name: "local range reads, non-overlapping span", 433 sp1: spans("local a", "local b", read, zeroTS), 434 sp2: spans("local b", "local c", read, zeroTS), 435 dependent: false, 436 }, 437 { 438 name: "local read and write, same ts", 439 sp1: spans("local a", "", write, hlc.Timestamp{WallTime: 1}), 440 sp2: spans("local a", "", read, hlc.Timestamp{WallTime: 1}), 441 dependent: true, 442 }, 443 { 444 name: "local read and write, causal ts", 445 sp1: spans("local a", "", write, hlc.Timestamp{WallTime: 1}), 446 sp2: spans("local a", "", read, hlc.Timestamp{WallTime: 2}), 447 dependent: true, 448 }, 449 { 450 name: "local read and write, non-causal ts", 451 sp1: spans("local a", "", write, hlc.Timestamp{WallTime: 2}), 452 sp2: spans("local a", "", read, hlc.Timestamp{WallTime: 1}), 453 dependent: true, 454 }, 455 { 456 name: "local read and write, zero ts read", 457 sp1: spans("local a", "", write, hlc.Timestamp{WallTime: 1}), 458 sp2: spans("local a", "", read, hlc.Timestamp{WallTime: 0}), 459 dependent: true, 460 }, 461 { 462 name: "local read and write, zero ts write", 463 sp1: spans("local a", "", write, hlc.Timestamp{WallTime: 0}), 464 sp2: spans("local a", "", read, hlc.Timestamp{WallTime: 1}), 465 dependent: true, 466 }, 467 { 468 name: "local read and write, non-overlapping", 469 sp1: spans("a", "b", write, zeroTS), 470 sp2: spans("b", "", read, zeroTS), 471 dependent: false, 472 }, 473 { 474 name: "local read and global write, overlapping", 475 sp1: spans("a", "b", write, zeroTS), 476 sp2: spans("local b", "", read, zeroTS), 477 dependent: false, 478 }, 479 { 480 name: "local write and global read, overlapping", 481 sp1: spans("local a", "local b", write, zeroTS), 482 sp2: spans("b", "", read, zeroTS), 483 dependent: false, 484 }, 485 } 486 for _, c := range cases { 487 t.Run(c.name, func(t *testing.T) { 488 testutils.RunTrueAndFalse(t, "inv", func(t *testing.T, inv bool) { 489 c := c 490 if inv { 491 c.sp1, c.sp2 = c.sp2, c.sp1 492 } 493 494 var m Manager 495 lg1 := m.MustAcquire(c.sp1) 496 lg2C := m.MustAcquireCh(c.sp2) 497 if c.dependent { 498 testLatchBlocks(t, lg2C) 499 m.Release(lg1) 500 lg2 := testLatchSucceeds(t, lg2C) 501 m.Release(lg2) 502 } else { 503 lg2 := testLatchSucceeds(t, lg2C) 504 m.Release(lg1) 505 m.Release(lg2) 506 } 507 }) 508 }) 509 } 510 } 511 512 func TestLatchManagerContextCancellation(t *testing.T) { 513 defer leaktest.AfterTest(t)() 514 var m Manager 515 516 // Attempt to acquire three latches that all block on each other. 517 lg1 := m.MustAcquire(spans("a", "", write, zeroTS)) 518 // The second one is given a cancelable context. 519 ctx2, cancel2 := context.WithCancel(context.Background()) 520 lg2C := m.MustAcquireChCtx(ctx2, spans("a", "", write, zeroTS)) 521 lg3C := m.MustAcquireCh(spans("a", "", write, zeroTS)) 522 523 // The second and third latch attempt block on the first. 524 testLatchBlocks(t, lg2C) 525 testLatchBlocks(t, lg3C) 526 527 // Cancel the second acquisition's context. It should stop waiting. 528 cancel2() 529 require.Nil(t, <-lg2C) 530 531 // The third latch attempt still blocks. 532 testLatchBlocks(t, lg3C) 533 534 // Release the first latch. The third succeeds in acquiring the latch. 535 m.Release(lg1) 536 testLatchSucceeds(t, lg3C) 537 } 538 539 func BenchmarkLatchManagerReadOnlyMix(b *testing.B) { 540 for _, size := range []int{1, 4, 16, 64, 128, 256} { 541 b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) { 542 var m Manager 543 ss := spans("a", "b", read, zeroTS) 544 for i := 0; i < size; i++ { 545 _ = m.MustAcquire(ss) 546 } 547 548 b.ResetTimer() 549 for i := 0; i < b.N; i++ { 550 _ = m.MustAcquire(ss) 551 } 552 }) 553 } 554 } 555 556 func BenchmarkLatchManagerReadWriteMix(b *testing.B) { 557 for _, readsPerWrite := range []int{0, 1, 4, 16, 64, 128, 256} { 558 b.Run(fmt.Sprintf("readsPerWrite=%d", readsPerWrite), func(b *testing.B) { 559 var m Manager 560 lgBuf := make(chan *Guard, 16) 561 562 spans := make([]spanset.SpanSet, b.N) 563 for i := range spans { 564 a, b := randBytes(100), randBytes(100) 565 // Overwrite first byte so that we do not mix local and global ranges 566 a[0], b[0] = 'a', 'a' 567 if bytes.Compare(a, b) > 0 { 568 a, b = b, a 569 } 570 span := roachpb.Span{Key: a, EndKey: b} 571 access := spanset.SpanReadOnly 572 if i%(readsPerWrite+1) == 0 { 573 access = spanset.SpanReadWrite 574 } 575 spans[i].AddNonMVCC(access, span) 576 } 577 578 b.ResetTimer() 579 for i := range spans { 580 lg, snap := m.sequence(&spans[i]) 581 snap.close() 582 if len(lgBuf) == cap(lgBuf) { 583 m.Release(<-lgBuf) 584 } 585 lgBuf <- lg 586 } 587 }) 588 } 589 } 590 591 func randBytes(n int) []byte { 592 b := make([]byte, n) 593 _, err := rand.Read(b) 594 if err != nil { 595 panic(err) 596 } 597 return b 598 }