github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/catalog/lease/lease_internal_test.go (about) 1 // Copyright 2015 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 // Note that there's also a lease_test.go, in package sql_test. 12 13 package lease 14 15 import ( 16 "context" 17 "fmt" 18 "sync" 19 "sync/atomic" 20 "testing" 21 22 "github.com/cockroachdb/cockroach/pkg/base" 23 "github.com/cockroachdb/cockroach/pkg/keys" 24 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 25 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 26 "github.com/cockroachdb/cockroach/pkg/util/hlc" 27 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 28 "github.com/cockroachdb/logtags" 29 ) 30 31 func TestTableSet(t *testing.T) { 32 defer leaktest.AfterTest(t)() 33 34 type data struct { 35 version sqlbase.DescriptorVersion 36 expiration int64 37 } 38 type insert data 39 type remove data 40 41 type newest struct { 42 version sqlbase.DescriptorVersion 43 } 44 45 testData := []struct { 46 op interface{} 47 expected string 48 }{ 49 {newest{0}, "<nil>"}, 50 {insert{2, 3}, "2:3"}, 51 {newest{0}, "2:3"}, 52 {newest{2}, "2:3"}, 53 {newest{3}, "<nil>"}, 54 {remove{2, 3}, ""}, 55 {insert{2, 4}, "2:4"}, 56 {newest{0}, "2:4"}, 57 {newest{2}, "2:4"}, 58 {newest{3}, "<nil>"}, 59 {insert{3, 1}, "2:4 3:1"}, 60 {newest{0}, "3:1"}, 61 {newest{1}, "<nil>"}, 62 {newest{2}, "2:4"}, 63 {newest{3}, "3:1"}, 64 {newest{4}, "<nil>"}, 65 {insert{1, 1}, "1:1 2:4 3:1"}, 66 {newest{0}, "3:1"}, 67 {newest{1}, "1:1"}, 68 {newest{2}, "2:4"}, 69 {newest{3}, "3:1"}, 70 {newest{4}, "<nil>"}, 71 {remove{3, 1}, "1:1 2:4"}, 72 {remove{1, 1}, "2:4"}, 73 {remove{2, 4}, ""}, 74 } 75 76 set := &tableSet{} 77 for i, d := range testData { 78 switch op := d.op.(type) { 79 case insert: 80 s := &tableVersionState{} 81 s.Version = op.version 82 s.expiration = hlc.Timestamp{WallTime: op.expiration} 83 set.insert(s) 84 85 case remove: 86 s := &tableVersionState{} 87 s.Version = op.version 88 s.expiration = hlc.Timestamp{WallTime: op.expiration} 89 set.remove(s) 90 91 case newest: 92 n := set.findNewest() 93 if op.version != 0 { 94 n = set.findVersion(op.version) 95 } 96 s := "<nil>" 97 if n != nil { 98 s = fmt.Sprintf("%d:%d", n.Version, n.expiration.WallTime) 99 } 100 if d.expected != s { 101 t.Fatalf("%d: expected %s, but found %s", i, d.expected, s) 102 } 103 continue 104 } 105 if s := set.String(); d.expected != s { 106 t.Fatalf("%d: expected %s, but found %s", i, d.expected, s) 107 } 108 } 109 } 110 111 func getNumVersions(ts *tableState) int { 112 ts.mu.Lock() 113 defer ts.mu.Unlock() 114 return len(ts.mu.active.data) 115 } 116 117 func TestPurgeOldVersions(t *testing.T) { 118 defer leaktest.AfterTest(t)() 119 // We're going to block gossip so it doesn't come randomly and clear up the 120 // leases we're artificially setting up. 121 gossipSem := make(chan struct{}, 1) 122 serverParams := base.TestServerArgs{ 123 Knobs: base.TestingKnobs{ 124 SQLLeaseManager: &ManagerTestingKnobs{ 125 TestingTableUpdateEvent: func(t *sqlbase.TableDescriptor) error { 126 gossipSem <- struct{}{} 127 <-gossipSem 128 return nil 129 }, 130 }, 131 }, 132 } 133 s, db, kvDB := serverutils.StartServer(t, serverParams) 134 defer s.Stopper().Stop(context.Background()) 135 leaseManager := s.LeaseManager().(*Manager) 136 137 // Block gossip. 138 gossipSem <- struct{}{} 139 defer func() { 140 // Unblock gossip. 141 <-gossipSem 142 }() 143 144 if _, err := db.Exec(` 145 CREATE DATABASE t; 146 CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR); 147 `); err != nil { 148 t.Fatal(err) 149 } 150 151 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "test") 152 153 var tables []sqlbase.ImmutableTableDescriptor 154 var expiration hlc.Timestamp 155 getLeases := func() { 156 for i := 0; i < 3; i++ { 157 if err := leaseManager.AcquireFreshestFromStore(context.Background(), tableDesc.ID); err != nil { 158 t.Fatal(err) 159 } 160 table, exp, err := leaseManager.Acquire(context.Background(), s.Clock().Now(), tableDesc.ID) 161 if err != nil { 162 t.Fatal(err) 163 } 164 tables = append(tables, *table) 165 expiration = exp 166 if err := leaseManager.Release(table); err != nil { 167 t.Fatal(err) 168 } 169 } 170 } 171 getLeases() 172 ts := leaseManager.findTableState(tableDesc.ID, false) 173 if numLeases := getNumVersions(ts); numLeases != 1 { 174 t.Fatalf("found %d versions instead of 1", numLeases) 175 } 176 177 // Verifies that ErrDidntUpdateDescriptor doesn't leak from Publish(). 178 if _, err := leaseManager.Publish(context.Background(), tableDesc.ID, func(*sqlbase.MutableTableDescriptor) error { 179 return ErrDidntUpdateDescriptor 180 }, nil); err != nil { 181 t.Fatal(err) 182 } 183 184 // Publish a new version for the table 185 if _, err := leaseManager.Publish(context.Background(), tableDesc.ID, func(*sqlbase.MutableTableDescriptor) error { 186 return nil 187 }, nil); err != nil { 188 t.Fatal(err) 189 } 190 191 getLeases() 192 ts = leaseManager.findTableState(tableDesc.ID, false) 193 if numLeases := getNumVersions(ts); numLeases != 2 { 194 t.Fatalf("found %d versions instead of 2", numLeases) 195 } 196 if err := purgeOldVersions( 197 context.Background(), kvDB, tableDesc.ID, false, 2 /* minVersion */, leaseManager); err != nil { 198 t.Fatal(err) 199 } 200 201 if numLeases := getNumVersions(ts); numLeases != 1 { 202 t.Fatalf("found %d versions instead of 1", numLeases) 203 } 204 ts.mu.Lock() 205 correctLease := ts.mu.active.data[0].TableDescriptor.ID == tables[5].ID && 206 ts.mu.active.data[0].TableDescriptor.Version == tables[5].Version 207 correctExpiration := ts.mu.active.data[0].expiration == expiration 208 ts.mu.Unlock() 209 if !correctLease { 210 t.Fatalf("wrong lease survived purge") 211 } 212 if !correctExpiration { 213 t.Fatalf("wrong lease expiration survived purge") 214 } 215 216 // Test that purgeOldVersions correctly removes a table version 217 // without a lease. 218 ts.mu.Lock() 219 tableVersion := &tableVersionState{ 220 ImmutableTableDescriptor: tables[0], 221 expiration: tables[5].ModificationTime, 222 } 223 ts.mu.active.insert(tableVersion) 224 ts.mu.Unlock() 225 if numLeases := getNumVersions(ts); numLeases != 2 { 226 t.Fatalf("found %d versions instead of 2", numLeases) 227 } 228 if err := purgeOldVersions( 229 context.Background(), kvDB, tableDesc.ID, false, 2 /* minVersion */, leaseManager); err != nil { 230 t.Fatal(err) 231 } 232 if numLeases := getNumVersions(ts); numLeases != 1 { 233 t.Fatalf("found %d versions instead of 1", numLeases) 234 } 235 } 236 237 // Test that a database with conflicting table names under different schemas 238 // do not cause issues. 239 func TestNameCacheDBConflictingTableNames(t *testing.T) { 240 defer leaktest.AfterTest(t)() 241 242 s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 243 defer s.Stopper().Stop(context.Background()) 244 leaseManager := s.LeaseManager().(*Manager) 245 246 if _, err := db.Exec(`SET experimental_enable_temp_tables = true`); err != nil { 247 t.Fatal(err) 248 } 249 250 if _, err := db.Exec(` 251 CREATE TABLE t (public int); 252 CREATE TEMP TABLE t (temp int); 253 CREATE TABLE t2 (public int); 254 CREATE TEMP TABLE t2 (temp int); 255 `); err != nil { 256 t.Fatal(err) 257 } 258 259 // Select in different orders, and make sure the right one is returned. 260 if _, err := db.Exec("SELECT * FROM pg_temp.t;"); err != nil { 261 t.Fatal(err) 262 } 263 if _, err := db.Exec("SELECT * FROM public.t;"); err != nil { 264 t.Fatal(err) 265 } 266 if _, err := db.Exec("SELECT * FROM public.t2;"); err != nil { 267 t.Fatal(err) 268 } 269 if _, err := db.Exec("SELECT * FROM pg_temp.t2;"); err != nil { 270 t.Fatal(err) 271 } 272 273 for _, tableName := range []string{"t", "t2"} { 274 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "defaultdb", tableName) 275 lease := leaseManager.tableNames.get( 276 tableDesc.ParentID, 277 sqlbase.ID(keys.PublicSchemaID), 278 tableName, 279 s.Clock().Now(), 280 ) 281 if lease.ID != tableDesc.ID { 282 t.Fatalf("lease has wrong ID: %d (expected: %d)", lease.ID, tableDesc.ID) 283 } 284 } 285 } 286 287 // Test that changing a descriptor's name updates the name cache. 288 func TestNameCacheIsUpdated(t *testing.T) { 289 defer leaktest.AfterTest(t)() 290 s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 291 defer s.Stopper().Stop(context.Background()) 292 leaseManager := s.LeaseManager().(*Manager) 293 294 if _, err := db.Exec(` 295 CREATE DATABASE t; 296 CREATE DATABASE t1; 297 CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR); 298 `); err != nil { 299 t.Fatal(err) 300 } 301 302 // Populate the name cache. 303 if _, err := db.Exec("SELECT * FROM t.test;"); err != nil { 304 t.Fatal(err) 305 } 306 307 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "test") 308 309 // Rename. 310 if _, err := db.Exec("ALTER TABLE t.test RENAME TO t.test2;"); err != nil { 311 t.Fatal(err) 312 } 313 314 // Check that the cache has been updated. 315 if leaseManager.tableNames.get(tableDesc.ParentID, tableDesc.GetParentSchemaID(), "test", s.Clock().Now()) != nil { 316 t.Fatalf("old name still in cache") 317 } 318 319 lease := leaseManager.tableNames.get(tableDesc.ParentID, tableDesc.GetParentSchemaID(), "test2", s.Clock().Now()) 320 if lease == nil { 321 t.Fatalf("new name not found in cache") 322 } 323 if lease.ID != tableDesc.ID { 324 t.Fatalf("new name has wrong ID: %d (expected: %d)", lease.ID, tableDesc.ID) 325 } 326 if err := leaseManager.Release(&lease.ImmutableTableDescriptor); err != nil { 327 t.Fatal(err) 328 } 329 330 // Rename to a different database. 331 if _, err := db.Exec("ALTER TABLE t.test2 RENAME TO t1.test2;"); err != nil { 332 t.Fatal(err) 333 } 334 335 // Re-read the descriptor, to get the new ParentID. 336 newTableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t1", "test2") 337 if tableDesc.ParentID == newTableDesc.ParentID { 338 t.Fatalf("database didn't change") 339 } 340 341 // Check that the cache has been updated. 342 if leaseManager.tableNames.get(tableDesc.ParentID, tableDesc.GetParentSchemaID(), "test2", s.Clock().Now()) != nil { 343 t.Fatalf("old name still in cache") 344 } 345 346 lease = leaseManager.tableNames.get(newTableDesc.ParentID, tableDesc.GetParentSchemaID(), "test2", s.Clock().Now()) 347 if lease == nil { 348 t.Fatalf("new name not found in cache") 349 } 350 if lease.ID != tableDesc.ID { 351 t.Fatalf("new name has wrong ID: %d (expected: %d)", lease.ID, tableDesc.ID) 352 } 353 if err := leaseManager.Release(&lease.ImmutableTableDescriptor); err != nil { 354 t.Fatal(err) 355 } 356 } 357 358 // Tests that a name cache entry with by an expired lease is not returned. 359 func TestNameCacheEntryDoesntReturnExpiredLease(t *testing.T) { 360 defer leaktest.AfterTest(t)() 361 s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 362 defer s.Stopper().Stop(context.Background()) 363 leaseManager := s.LeaseManager().(*Manager) 364 365 const tableName = "test" 366 367 if _, err := db.Exec(fmt.Sprintf(` 368 CREATE DATABASE t; 369 CREATE TABLE t.%s (k CHAR PRIMARY KEY, v CHAR); 370 `, tableName)); err != nil { 371 t.Fatal(err) 372 } 373 374 // Populate the name cache. 375 if _, err := db.Exec("SELECT * FROM t.test;"); err != nil { 376 t.Fatal(err) 377 } 378 379 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", tableName) 380 381 // Check the assumptions this tests makes: that there is a cache entry 382 // (with a valid lease). 383 if lease := leaseManager.tableNames.get(tableDesc.ParentID, tableDesc.GetParentSchemaID(), tableName, s.Clock().Now()); lease == nil { 384 t.Fatalf("name cache has no unexpired entry for (%d, %s)", tableDesc.ParentID, tableName) 385 } else { 386 if err := leaseManager.Release(&lease.ImmutableTableDescriptor); err != nil { 387 t.Fatal(err) 388 } 389 } 390 391 leaseManager.ExpireLeases(s.Clock()) 392 393 // Check the name no longer resolves. 394 if lease := leaseManager.tableNames.get(tableDesc.ParentID, tableDesc.GetParentSchemaID(), tableName, s.Clock().Now()); lease != nil { 395 t.Fatalf("name cache has unexpired entry for (%d, %s): %s", tableDesc.ParentID, tableName, lease) 396 } 397 } 398 399 // Tests that a name cache entry always exists for the latest lease and 400 // the lease expiration time is monotonically increasing. 401 func TestNameCacheContainsLatestLease(t *testing.T) { 402 defer leaktest.AfterTest(t)() 403 removalTracker := NewLeaseRemovalTracker() 404 testingKnobs := base.TestingKnobs{ 405 SQLLeaseManager: &ManagerTestingKnobs{ 406 LeaseStoreTestingKnobs: StorageTestingKnobs{ 407 LeaseReleasedEvent: removalTracker.LeaseRemovedNotification, 408 }, 409 }, 410 } 411 s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{Knobs: testingKnobs}) 412 defer s.Stopper().Stop(context.Background()) 413 leaseManager := s.LeaseManager().(*Manager) 414 415 const tableName = "test" 416 417 if _, err := db.Exec(fmt.Sprintf(` 418 CREATE DATABASE t; 419 CREATE TABLE t.%s (k CHAR PRIMARY KEY, v CHAR); 420 `, tableName)); err != nil { 421 t.Fatal(err) 422 } 423 424 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", tableName) 425 426 // Populate the name cache. 427 if _, err := db.Exec("SELECT * FROM t.test;"); err != nil { 428 t.Fatal(err) 429 } 430 431 // There is a cache entry. 432 lease := leaseManager.tableNames.get(tableDesc.ParentID, tableDesc.GetParentSchemaID(), tableName, s.Clock().Now()) 433 if lease == nil { 434 t.Fatalf("name cache has no unexpired entry for (%d, %s)", tableDesc.ParentID, tableName) 435 } 436 437 tracker := removalTracker.TrackRemoval(&lease.ImmutableTableDescriptor) 438 439 // Acquire another lease. 440 if _, err := acquireNodeLease(context.Background(), leaseManager, tableDesc.ID); err != nil { 441 t.Fatal(err) 442 } 443 444 // Check the name resolves to the new lease. 445 newLease := leaseManager.tableNames.get(tableDesc.ParentID, tableDesc.GetParentSchemaID(), tableName, s.Clock().Now()) 446 if newLease == nil { 447 t.Fatalf("name cache doesn't contain entry for (%d, %s)", tableDesc.ParentID, tableName) 448 } 449 if newLease == lease { 450 t.Fatalf("same lease %s", newLease.expiration.GoTime()) 451 } 452 453 if err := leaseManager.Release(&lease.ImmutableTableDescriptor); err != nil { 454 t.Fatal(err) 455 } 456 457 // The first lease acquisition was released. 458 if err := tracker.WaitForRemoval(); err != nil { 459 t.Fatal(err) 460 } 461 462 if err := leaseManager.Release(&newLease.ImmutableTableDescriptor); err != nil { 463 t.Fatal(err) 464 } 465 } 466 467 // Test that table names are treated as case sensitive by the name cache. 468 func TestTableNameCaseSensitive(t *testing.T) { 469 defer leaktest.AfterTest(t)() 470 s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 471 defer s.Stopper().Stop(context.Background()) 472 leaseManager := s.LeaseManager().(*Manager) 473 474 if _, err := db.Exec(` 475 CREATE DATABASE t; 476 CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR); 477 `); err != nil { 478 t.Fatal(err) 479 } 480 481 // Populate the name cache. 482 if _, err := db.Exec("SELECT * FROM t.test;"); err != nil { 483 t.Fatal(err) 484 } 485 486 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "test") 487 488 // Check that we cannot get the table by a different name. 489 if leaseManager.tableNames.get(tableDesc.ParentID, tableDesc.GetParentSchemaID(), "tEsT", s.Clock().Now()) != nil { 490 t.Fatalf("lease manager incorrectly found table with different case") 491 } 492 } 493 494 // Test that there's no deadlock between AcquireByName and Release. 495 // We used to have one due to lock inversion between the tableNameCache lock and 496 // the tableVersionState lock, triggered when the same lease was Release()d after the 497 // table had been dropped (which means it's removed from the tableNameCache) and 498 // AcquireByName()d at the same time. 499 func TestReleaseAcquireByNameDeadlock(t *testing.T) { 500 defer leaktest.AfterTest(t)() 501 removalTracker := NewLeaseRemovalTracker() 502 testingKnobs := base.TestingKnobs{ 503 SQLLeaseManager: &ManagerTestingKnobs{ 504 LeaseStoreTestingKnobs: StorageTestingKnobs{ 505 LeaseReleasedEvent: removalTracker.LeaseRemovedNotification, 506 RemoveOnceDereferenced: true, 507 }, 508 }, 509 } 510 s, sqlDB, kvDB := serverutils.StartServer( 511 t, base.TestServerArgs{Knobs: testingKnobs}) 512 defer s.Stopper().Stop(context.Background()) 513 leaseManager := s.LeaseManager().(*Manager) 514 515 if _, err := sqlDB.Exec(` 516 CREATE DATABASE t; 517 CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR); 518 `); err != nil { 519 t.Fatal(err) 520 } 521 522 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "test") 523 524 // Populate the name cache. 525 ctx := context.Background() 526 table, _, err := leaseManager.AcquireByName( 527 ctx, 528 leaseManager.clock.Now(), 529 tableDesc.ParentID, 530 tableDesc.GetParentSchemaID(), 531 "test", 532 ) 533 if err != nil { 534 t.Fatal(err) 535 } 536 if err := leaseManager.Release(table); err != nil { 537 t.Fatal(err) 538 } 539 540 // Try to trigger the race repeatedly: race an AcquireByName against a 541 // Release. 542 // tableChan acts as a barrier, synchronizing the two routines at every 543 // iteration. 544 tableChan := make(chan *sqlbase.ImmutableTableDescriptor) 545 errChan := make(chan error) 546 go func() { 547 for table := range tableChan { 548 // Move errors to the main goroutine. 549 errChan <- leaseManager.Release(table) 550 } 551 }() 552 553 for i := 0; i < 50; i++ { 554 timestamp := leaseManager.clock.Now() 555 ctx := context.Background() 556 table, _, err := leaseManager.AcquireByName( 557 ctx, 558 timestamp, 559 tableDesc.ParentID, 560 tableDesc.GetParentSchemaID(), 561 "test", 562 ) 563 if err != nil { 564 t.Fatal(err) 565 } 566 // This test will need to wait until leases are removed from the store 567 // before creating new leases because the jitter used in the leases' 568 // expiration causes duplicate key errors when trying to create new 569 // leases. This is not a problem in production, since leases are not 570 // removed from the store until they expire, and the jitter is small 571 // compared to their lifetime, but it is a problem in this test because 572 // we churn through leases quickly. 573 tracker := removalTracker.TrackRemoval(table) 574 // Start the race: signal the other guy to release, and we do another 575 // acquire at the same time. 576 tableChan <- table 577 tableByName, _, err := leaseManager.AcquireByName( 578 ctx, 579 timestamp, 580 tableDesc.ParentID, 581 tableDesc.GetParentSchemaID(), 582 "test", 583 ) 584 if err != nil { 585 t.Fatal(err) 586 } 587 588 // See if there was an error releasing lease. 589 err = <-errChan 590 if err != nil { 591 t.Fatal(err) 592 } 593 594 // Even after waiting for the error above, the lease might still 595 // need removal from the store because lease removal is asynchronous. 596 // Depending on how the race went, there are two cases - either the 597 // AcquireByName ran first, and got the same lease as we already had, 598 // or the Release ran first and so we got a new lease and can wait here 599 // for the old lease to be released. 600 if tableByName != table { 601 if err := tracker.WaitForRemoval(); err != nil { 602 t.Fatal(err) 603 } 604 } 605 606 // Track removal only after the above call to WaitForRemoval 607 // so that if there is an existing removal of a lease 608 // (Release occurred before AcquireByName) it is guaranteed 609 // to not reuse an existing tracker. 610 tracker2 := removalTracker.TrackRemoval(tableByName) 611 612 if err := leaseManager.Release(tableByName); err != nil { 613 t.Fatal(err) 614 } 615 616 if err := tracker2.WaitForRemoval(); err != nil { 617 t.Fatal(err) 618 } 619 } 620 close(tableChan) 621 } 622 623 // TestAcquireFreshestFromStoreRaces runs 624 // Manager.acquireFreshestFromStore() in parallel to test for races. 625 func TestAcquireFreshestFromStoreRaces(t *testing.T) { 626 defer leaktest.AfterTest(t)() 627 s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 628 defer s.Stopper().Stop(context.Background()) 629 leaseManager := s.LeaseManager().(*Manager) 630 631 if _, err := db.Exec(` 632 CREATE DATABASE t; 633 CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR); 634 `); err != nil { 635 t.Fatal(err) 636 } 637 638 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "test") 639 640 var wg sync.WaitGroup 641 numRoutines := 10 642 wg.Add(numRoutines) 643 for i := 0; i < numRoutines; i++ { 644 go func() { 645 defer wg.Done() 646 if err := leaseManager.AcquireFreshestFromStore(context.Background(), tableDesc.ID); err != nil { 647 t.Error(err) 648 } 649 table, _, err := leaseManager.Acquire(context.Background(), s.Clock().Now(), tableDesc.ID) 650 if err != nil { 651 t.Error(err) 652 } 653 if err := leaseManager.Release(table); err != nil { 654 t.Error(err) 655 } 656 }() 657 } 658 wg.Wait() 659 } 660 661 // This test checks that multiple threads can simultaneously acquire the 662 // latest table version with a lease. When multiple threads 663 // wait on a particular thread acquiring a lease for the latest table version, 664 // they are able to check after waiting that the lease they were waiting on 665 // is still valid. They are able to reacquire a lease if needed. 666 func TestParallelLeaseAcquireWithImmediateRelease(t *testing.T) { 667 defer leaktest.AfterTest(t)() 668 testingKnobs := base.TestingKnobs{ 669 SQLLeaseManager: &ManagerTestingKnobs{ 670 LeaseStoreTestingKnobs: StorageTestingKnobs{ 671 // Immediate remove tableVersionState and release its 672 // lease when it is dereferenced. This forces threads 673 // waiting on a lease to reacquire the lease. 674 RemoveOnceDereferenced: true, 675 }, 676 }, 677 } 678 s, sqlDB, kvDB := serverutils.StartServer( 679 t, base.TestServerArgs{Knobs: testingKnobs}) 680 defer s.Stopper().Stop(context.Background()) 681 leaseManager := s.LeaseManager().(*Manager) 682 683 if _, err := sqlDB.Exec(` 684 CREATE DATABASE t; 685 CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR); 686 `); err != nil { 687 t.Fatal(err) 688 } 689 690 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "test") 691 692 var wg sync.WaitGroup 693 numRoutines := 10 694 now := s.Clock().Now() 695 wg.Add(numRoutines) 696 for i := 0; i < numRoutines; i++ { 697 go func() { 698 defer wg.Done() 699 table, _, err := leaseManager.Acquire(context.Background(), now, tableDesc.ID) 700 if err != nil { 701 t.Error(err) 702 } 703 if err := leaseManager.Release(table); err != nil { 704 t.Error(err) 705 } 706 }() 707 } 708 709 wg.Wait() 710 } 711 712 // Test one possible outcome of a race between a lease acquisition (the first 713 // case through tableState.acquire(), the second through 714 // tableState.acquireFreshestFromStore()) and a release of the lease that was 715 // just acquired. Precisely: 716 // 1. Thread 1 calls either acquireFreshestFromStore() or acquire(). 717 // 2. Thread 1 releases the lock on tableState and starts acquisition of a lease 718 // from the store, blocking until it's finished. 719 // 3. Thread 2 calls acquire(). The lease has not been acquired yet, so it 720 // also enters the acquisition code path (calling DoChan). 721 // 4. Thread 2 proceeds to release the lock on tableState waiting for the 722 // in-flight acquisition. 723 // 4. The lease is acquired from the store and the waiting routines are 724 // unblocked. 725 // 5. Thread 2 unblocks first, and releases the new lease, for whatever reason. 726 // 5. Thread 1 wakes up. At this point, a naive implementation would use the 727 // newly acquired lease, which would be incorrect. The test checks that 728 // acquireFreshestFromStore() or acquire() notices, after re-acquiring the 729 // tableState lock, that the new lease has been released and acquires a new 730 // one. 731 func TestLeaseAcquireAndReleaseConcurrently(t *testing.T) { 732 defer leaktest.AfterTest(t)() 733 734 t.Skip("fails in the presence of migrations requiring backfill, but cannot import sqlmigrations") 735 736 // Result is a struct for moving results to the main result routine. 737 type Result struct { 738 table *sqlbase.ImmutableTableDescriptor 739 exp hlc.Timestamp 740 err error 741 } 742 743 descID := sqlbase.ID(keys.LeaseTableID) 744 745 // acquireBlock calls Acquire. 746 acquireBlock := func( 747 ctx context.Context, 748 m *Manager, 749 acquireChan chan Result, 750 ) { 751 table, e, err := m.Acquire(ctx, m.clock.Now(), descID) 752 acquireChan <- Result{err: err, exp: e, table: table} 753 } 754 755 testCases := []struct { 756 name string 757 // Whether the second routine is a call to Manager.acquireFreshest or 758 // not. This determines which channel we unblock. 759 isSecondCallAcquireFreshest bool 760 }{ 761 762 // Checks what happens when the race between between acquire() and 763 // lease release occurs. 764 { 765 name: "CallAcquireConcurrently", 766 isSecondCallAcquireFreshest: false, 767 }, 768 // Checks what happens when the race between 769 // acquireFreshestFromStore() and lease release occurs. 770 { 771 name: "CallAcquireFreshestAndAcquireConcurrently", 772 isSecondCallAcquireFreshest: true, 773 }, 774 } 775 776 for _, test := range testCases { 777 ctx := logtags.AddTag(context.Background(), "test: Lease", nil) 778 779 t.Run(test.name, func(t *testing.T) { 780 // blockChan and freshestBlockChan is used to set up the race condition. 781 blockChan := make(chan struct{}) 782 freshestBlockChan := make(chan struct{}) 783 // acquisitionBlock is used to prevent acquireNodeLease from 784 // completing, to force a lease to delay its acquisition. 785 acquisitionBlock := make(chan struct{}) 786 787 // preblock is used for the main routine to wait for all acquisition 788 // routines to catch up. 789 var preblock sync.WaitGroup 790 // acquireArrivals and acquireFreshestArrivals tracks how many times 791 // we've arrived at the knob codepath for the corresponding functions. 792 // This is needed because the fix to the race condition hits the knob more 793 // than once in a single routine, so we need to ignore any extra passes. 794 var acquireArrivals int32 795 var acquireFreshestArrivals int32 796 // leasesAcquiredCount counts how many leases were acquired in total. 797 var leasesAcquiredCount int32 798 799 removalTracker := NewLeaseRemovalTracker() 800 testingKnobs := base.TestingKnobs{ 801 SQLLeaseManager: &ManagerTestingKnobs{ 802 LeaseStoreTestingKnobs: StorageTestingKnobs{ 803 RemoveOnceDereferenced: true, 804 LeaseReleasedEvent: removalTracker.LeaseRemovedNotification, 805 LeaseAcquireResultBlockEvent: func(leaseBlockType AcquireBlockType) { 806 if leaseBlockType == AcquireBlock { 807 if count := atomic.LoadInt32(&acquireArrivals); (count < 1 && test.isSecondCallAcquireFreshest) || 808 (count < 2 && !test.isSecondCallAcquireFreshest) { 809 atomic.AddInt32(&acquireArrivals, 1) 810 preblock.Done() 811 <-blockChan 812 } 813 } else if leaseBlockType == AcquireFreshestBlock { 814 if atomic.LoadInt32(&acquireFreshestArrivals) < 1 { 815 atomic.AddInt32(&acquireFreshestArrivals, 1) 816 preblock.Done() 817 <-freshestBlockChan 818 } 819 } 820 }, 821 LeaseAcquiredEvent: func(_ sqlbase.TableDescriptor, _ error) { 822 atomic.AddInt32(&leasesAcquiredCount, 1) 823 <-acquisitionBlock 824 }, 825 }, 826 }, 827 } 828 829 serverArgs := base.TestServerArgs{Knobs: testingKnobs} 830 831 serverArgs.LeaseManagerConfig = base.NewLeaseManagerConfig() 832 // The LeaseJitterFraction is zero so leases will have 833 // monotonically increasing expiration. This prevents two leases 834 // from having the same expiration due to randomness, as the 835 // leases are checked for having a different expiration. 836 serverArgs.LeaseManagerConfig.TableDescriptorLeaseJitterFraction = 0.0 837 838 s, _, _ := serverutils.StartServer( 839 t, serverArgs) 840 defer s.Stopper().Stop(context.Background()) 841 leaseManager := s.LeaseManager().(*Manager) 842 843 acquireResultChan := make(chan Result) 844 845 // Start two routines to acquire and release. 846 preblock.Add(2) 847 go acquireBlock(ctx, leaseManager, acquireResultChan) 848 if test.isSecondCallAcquireFreshest { 849 go func(ctx context.Context, m *Manager, acquireChan chan Result) { 850 if err := m.AcquireFreshestFromStore(ctx, descID); err != nil { 851 acquireChan <- Result{err: err, exp: hlc.Timestamp{}, table: nil} 852 return 853 } 854 table, e, err := m.Acquire(ctx, s.Clock().Now(), descID) 855 acquireChan <- Result{err: err, exp: e, table: table} 856 }(ctx, leaseManager, acquireResultChan) 857 858 } else { 859 go acquireBlock(ctx, leaseManager, acquireResultChan) 860 } 861 862 // Wait until both routines arrive. 863 preblock.Wait() 864 865 // Allow the acquisition to finish. By delaying it until now, we guarantee 866 // both routines will receive the same lease. 867 acquisitionBlock <- struct{}{} 868 869 // Allow the first routine to finish acquisition. In the case where both 870 // routines are calling Acquire(), first refers to whichever routine 871 // continues, order does not matter. 872 blockChan <- struct{}{} 873 // Wait for the first routine's results. 874 result1 := <-acquireResultChan 875 if result1.err != nil { 876 t.Fatal(result1.err) 877 } 878 879 // Release the lease. This also causes it to get removed as the 880 // knob RemoveOnceDereferenced is set. 881 tracker := removalTracker.TrackRemoval(result1.table) 882 if err := leaseManager.Release(result1.table); err != nil { 883 t.Fatal(err) 884 } 885 // Wait until the lease is removed. 886 if err := tracker.WaitForRemoval(); err != nil { 887 t.Fatal(err) 888 } 889 890 // Allow the second routine to proceed. 891 if test.isSecondCallAcquireFreshest { 892 freshestBlockChan <- struct{}{} 893 } else { 894 blockChan <- struct{}{} 895 } 896 897 // Allow all future acquisitions to complete. 898 close(acquisitionBlock) 899 900 // Get the acquisition results of the second routine. 901 result2 := <-acquireResultChan 902 if result2.err != nil { 903 t.Fatal(result2.err) 904 } 905 906 if result1.table == result2.table && result1.exp == result2.exp { 907 t.Fatalf("Expected the leases to be different. TableDescriptor pointers are equal and both the same expiration") 908 } 909 if count := atomic.LoadInt32(&leasesAcquiredCount); count != 2 { 910 t.Fatalf("Expected to acquire 2 leases, instead got %d", count) 911 } 912 }) 913 } 914 }