github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rename_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  package sql
    12  
    13  import (
    14  	"context"
    15  	"sync"
    16  	"testing"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/base"
    19  	"github.com/cockroachdb/cockroach/pkg/keys"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/catalog/lease"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    23  	"github.com/cockroachdb/cockroach/pkg/testutils"
    24  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    25  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    26  	"github.com/cockroachdb/cockroach/pkg/util/syncutil"
    27  )
    28  
    29  // TestRenameTable tests the table descriptor changes during
    30  // a rename operation.
    31  func TestRenameTable(t *testing.T) {
    32  	defer leaktest.AfterTest(t)()
    33  	s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{})
    34  	defer s.Stopper().Stop(context.Background())
    35  
    36  	counter := int64(keys.MinNonPredefinedUserDescID)
    37  
    38  	oldDBID := sqlbase.ID(counter)
    39  	if _, err := db.Exec(`CREATE DATABASE test`); err != nil {
    40  		t.Fatal(err)
    41  	}
    42  
    43  	// Create table in 'test'.
    44  	counter++
    45  	oldName := "foo"
    46  	if _, err := db.Exec(`CREATE TABLE test.foo (k INT PRIMARY KEY, v int)`); err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	// Check the table descriptor.
    51  	desc := &sqlbase.Descriptor{}
    52  	tableDescKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, sqlbase.ID(counter))
    53  	ts, err := kvDB.GetProtoTs(context.Background(), tableDescKey, desc)
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	tableDesc := desc.Table(ts)
    58  	if tableDesc.Name != oldName {
    59  		t.Fatalf("Wrong table name, expected %s, got: %+v", oldName, tableDesc)
    60  	}
    61  	if tableDesc.ParentID != oldDBID {
    62  		t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", oldDBID, tableDesc)
    63  	}
    64  
    65  	// Create database test2.
    66  	counter++
    67  	newDBID := sqlbase.ID(counter)
    68  	if _, err := db.Exec(`CREATE DATABASE test2`); err != nil {
    69  		t.Fatal(err)
    70  	}
    71  
    72  	// Move table to test2 and change its name as well.
    73  	newName := "bar"
    74  	if _, err := db.Exec(`ALTER TABLE test.foo RENAME TO test2.bar`); err != nil {
    75  		t.Fatal(err)
    76  	}
    77  
    78  	// Check the table descriptor again.
    79  	ts, err = kvDB.GetProtoTs(context.Background(), tableDescKey, desc)
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	tableDesc = desc.Table(ts)
    84  	if tableDesc.Name != newName {
    85  		t.Fatalf("Wrong table name, expected %s, got: %+v", newName, tableDesc)
    86  	}
    87  	if tableDesc.ParentID != newDBID {
    88  		t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", newDBID, tableDesc)
    89  	}
    90  }
    91  
    92  // Test that a SQL txn that resolved a name can keep resolving that name during
    93  // its lifetime even after the table has been renamed.
    94  // Also tests that the name of a renamed table cannot be reused until everybody
    95  // has stopped using it. Otherwise, we'd have different transactions in the
    96  // systems using a single name for different tables.
    97  // Also tests that the old name cannot be used by node that doesn't have a lease
    98  // on the old version even while the name mapping still exists.
    99  func TestTxnCanStillResolveOldName(t *testing.T) {
   100  	defer leaktest.AfterTest(t)()
   101  
   102  	var lmKnobs lease.ManagerTestingKnobs
   103  	// renameUnblocked is used to block the rename schema change until the test
   104  	// doesn't need the old name->id mapping to exist anymore.
   105  	renameUnblocked := make(chan interface{})
   106  	serverParams := base.TestServerArgs{
   107  		Knobs: base.TestingKnobs{
   108  			SQLSchemaChanger: &SchemaChangerTestingKnobs{
   109  				OldNamesDrainedNotification: func() {
   110  					<-renameUnblocked
   111  				},
   112  			},
   113  			SQLLeaseManager: &lmKnobs,
   114  		}}
   115  	var mu syncutil.Mutex
   116  	var waitTableID sqlbase.ID
   117  	// renamed is used to block until the node cannot get leases with the original
   118  	// table name. It will be signaled once the table has been renamed and the update
   119  	// about the new name has been processed. Moreover, not only does an update to
   120  	// the name needs to have been received, but the version of the descriptor needs to
   121  	// have also been incremented in order to guarantee that the node cannot get
   122  	// leases using the old name (an update with the new name but the original
   123  	// version is ignored by the leasing refresh mechanism).
   124  	renamed := make(chan interface{})
   125  	lmKnobs.TestingTableRefreshedEvent =
   126  		func(table *sqlbase.TableDescriptor) {
   127  			mu.Lock()
   128  			defer mu.Unlock()
   129  			if waitTableID != table.ID {
   130  				return
   131  			}
   132  			if table.Name == "t2" && table.Version == 2 {
   133  				close(renamed)
   134  				waitTableID = 0
   135  			}
   136  		}
   137  	s, db, kvDB := serverutils.StartServer(t, serverParams)
   138  	defer s.Stopper().Stop(context.Background())
   139  
   140  	sql := `
   141  CREATE DATABASE test;
   142  CREATE TABLE test.t (a INT PRIMARY KEY);
   143  `
   144  	_, err := db.Exec(sql)
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  
   149  	tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t")
   150  	mu.Lock()
   151  	waitTableID = tableDesc.ID
   152  	mu.Unlock()
   153  
   154  	txn, err := db.Begin()
   155  	if err != nil {
   156  		t.Fatal(err)
   157  	}
   158  
   159  	// Run a command to make the transaction resolves the table name.
   160  	if _, err := txn.Exec("SELECT * FROM test.t"); err != nil {
   161  		t.Fatal(err)
   162  	}
   163  
   164  	// Concurrently, rename the table.
   165  	threadDone := make(chan error)
   166  	go func() {
   167  		// The ALTER will commit and signal the main thread through `renamed`, but
   168  		// the schema changer will remain blocked by the lease on the "t" version
   169  		// held by the txn started above.
   170  		_, err := db.Exec("ALTER TABLE test.t RENAME TO test.t2")
   171  		threadDone <- err
   172  	}()
   173  	defer func() {
   174  		close(renameUnblocked)
   175  		// Block until the thread doing the rename has finished, so the test can clean
   176  		// up. It needed to wait for the transaction to release its lease.
   177  		if err := <-threadDone; err != nil {
   178  			t.Fatal(err)
   179  		}
   180  	}()
   181  
   182  	// Block until the Manager has processed the gossip update.
   183  	<-renamed
   184  
   185  	// Run another command in the transaction and make sure that we can still
   186  	// resolve the table name.
   187  	if _, err := txn.Exec("SELECT * FROM test.t"); err != nil {
   188  		t.Fatal(err)
   189  	}
   190  
   191  	// Check that the name cannot be reused while somebody still has a lease on
   192  	// the old one (the mechanism for ensuring this is that the entry for the old
   193  	// name is not deleted from the database until the async schema changer checks
   194  	// that there's no more leases on the old version).
   195  	if _, err := db.Exec("CREATE TABLE test.t (a INT PRIMARY KEY)"); !testutils.IsError(
   196  		err, `relation "t" already exists`) {
   197  		t.Fatal(err)
   198  	}
   199  
   200  	if err := txn.Commit(); err != nil {
   201  		t.Fatal(err)
   202  	}
   203  
   204  	// Check that the old name is not usable outside of the transaction now
   205  	// that the node doesn't have a lease on it anymore (committing the txn
   206  	// should have released the lease on the version of the descriptor with the
   207  	// old name), even though the name mapping still exists.
   208  
   209  	var foundLease bool
   210  	s.LeaseManager().(*lease.Manager).VisitLeases(func(
   211  		desc sqlbase.TableDescriptor, dropped bool, refCount int, expiration tree.DTimestamp,
   212  	) (wantMore bool) {
   213  		if desc.ID == tableDesc.ID && desc.Name == "t" {
   214  			foundLease = true
   215  		}
   216  		return true
   217  	})
   218  	if foundLease {
   219  		t.Fatalf(`still have lease on "t"`)
   220  	}
   221  	if _, err := db.Exec("SELECT * FROM test.t"); !testutils.IsError(
   222  		err, `relation "test.t" does not exist`) {
   223  		t.Fatal(err)
   224  	}
   225  }
   226  
   227  // Test that a txn doing a rename can use the new name immediately.
   228  // It can also use the old name if it took a lease on it before the rename, for
   229  // better or worse.
   230  func TestTxnCanUseNewNameAfterRename(t *testing.T) {
   231  	defer leaktest.AfterTest(t)()
   232  	s, db, _ := serverutils.StartServer(t, base.TestServerArgs{})
   233  	defer s.Stopper().Stop(context.Background())
   234  
   235  	sql := `
   236  CREATE DATABASE test;
   237  CREATE TABLE test.t (a INT PRIMARY KEY);
   238  `
   239  	_, err := db.Exec(sql)
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  
   244  	// Make sure we take a lease on the version called "t".
   245  	if _, err := db.Exec("SELECT * FROM test.t"); err != nil {
   246  		t.Fatal(err)
   247  	}
   248  	{
   249  		txn, err := db.Begin()
   250  		if err != nil {
   251  			t.Fatal(err)
   252  		}
   253  
   254  		if _, err := txn.Exec("ALTER TABLE test.t RENAME TO test.t2"); err != nil {
   255  			t.Fatal(err)
   256  		}
   257  		// Check that we can use the new name.
   258  		if _, err := txn.Exec("SELECT * FROM test.t2"); err != nil {
   259  			t.Fatal(err)
   260  		}
   261  
   262  		if err := txn.Commit(); err != nil {
   263  			t.Fatal(err)
   264  		}
   265  	}
   266  
   267  	{
   268  		txn, err := db.Begin()
   269  		if err != nil {
   270  			t.Fatal(err)
   271  		}
   272  
   273  		if _, err := txn.Exec("ALTER TABLE test.t2 RENAME TO test.t"); err != nil {
   274  			t.Fatal(err)
   275  		}
   276  		// Check that we can use the new name.
   277  		if _, err := txn.Exec("SELECT * FROM test.t"); err != nil {
   278  			t.Fatal(err)
   279  		}
   280  		// Check that we cannot use the old name.
   281  		if _, err := txn.Exec(`
   282  SELECT * FROM test.t2
   283  `); !testutils.IsError(err, "relation \"test.t2\" does not exist") {
   284  			t.Fatalf("err = %v", err)
   285  		}
   286  		if err := txn.Rollback(); err != nil {
   287  			t.Fatal(err)
   288  		}
   289  	}
   290  }
   291  
   292  // Check that we properly cleanup all the temporary names when performing a
   293  // series of renames in a transaction.
   294  func TestSeriesOfRenames(t *testing.T) {
   295  	defer leaktest.AfterTest(t)()
   296  	s, db, _ := serverutils.StartServer(t, base.TestServerArgs{})
   297  	defer s.Stopper().Stop(context.Background())
   298  
   299  	sql := `
   300  CREATE DATABASE test;
   301  CREATE TABLE test.t (a INT PRIMARY KEY);
   302  `
   303  	_, err := db.Exec(sql)
   304  	if err != nil {
   305  		t.Fatal(err)
   306  	}
   307  
   308  	txn, err := db.Begin()
   309  	if err != nil {
   310  		t.Fatal(err)
   311  	}
   312  	if _, err := txn.Exec("ALTER TABLE test.t RENAME TO test.t2"); err != nil {
   313  		t.Fatal(err)
   314  	}
   315  	if _, err := txn.Exec("ALTER TABLE test.t2 RENAME TO test.t3"); err != nil {
   316  		t.Fatal(err)
   317  	}
   318  	if _, err := txn.Exec("ALTER TABLE test.t3 RENAME TO test.t4"); err != nil {
   319  		t.Fatal(err)
   320  	}
   321  	if err := txn.Commit(); err != nil {
   322  		t.Fatal(err)
   323  	}
   324  
   325  	// Check that the temp names have been properly cleaned up by creating tables
   326  	// with those names.
   327  	if _, err := db.Exec("CREATE TABLE test.t (a INT PRIMARY KEY)"); err != nil {
   328  		t.Fatal(err)
   329  	}
   330  	if _, err := db.Exec("CREATE TABLE test.t2 (a INT PRIMARY KEY)"); err != nil {
   331  		t.Fatal(err)
   332  	}
   333  	if _, err := db.Exec("CREATE TABLE test.t3 (a INT PRIMARY KEY)"); err != nil {
   334  		t.Fatal(err)
   335  	}
   336  }
   337  
   338  // Tests that a RENAME while a name is being drained will result in the
   339  // table version being incremented again, implying that all old names
   340  // are drained correctly. The new RENAME will succeed with
   341  // all old names drained.
   342  func TestRenameDuringDrainingName(t *testing.T) {
   343  	defer leaktest.AfterTest(t)()
   344  
   345  	// two channels that signal the start of the second rename
   346  	// and the end of the second rename.
   347  	startRename := make(chan interface{})
   348  	finishRename := make(chan interface{})
   349  	serverParams := base.TestServerArgs{
   350  		Knobs: base.TestingKnobs{
   351  			SQLSchemaChanger: &SchemaChangerTestingKnobs{
   352  				OldNamesDrainedNotification: func() {
   353  					if startRename != nil {
   354  						// Run second rename.
   355  						start := startRename
   356  						startRename = nil
   357  						close(start)
   358  						<-finishRename
   359  					}
   360  				},
   361  				// Don't run the schema changer for the second RENAME so that we can be
   362  				// sure that the first schema changer runs both schema changes. This
   363  				// behavior is due to the fact that the schema changer for the first job
   364  				// will process all the draining names on the table descriptor,
   365  				// including the ones queued up by the second job. It's not ideal since
   366  				// we would like jobs to manage their own state without interference
   367  				// from other jobs, but that's how schema change jobs work right now.
   368  				SchemaChangeJobNoOp: func() bool {
   369  					return startRename == nil
   370  				},
   371  			},
   372  		}}
   373  
   374  	s, db, kvDB := serverutils.StartServer(t, serverParams)
   375  	defer s.Stopper().Stop(context.Background())
   376  
   377  	sql := `
   378  CREATE DATABASE test;
   379  CREATE TABLE test.t (a INT PRIMARY KEY);
   380  `
   381  	_, err := db.Exec(sql)
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  
   386  	tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t")
   387  	// The expected version will be the result of two increments for the two
   388  	// schema changes and one increment for signaling of the completion of the
   389  	// drain. See the above comment for an explanation of why there's only one
   390  	// expected version update for draining names.
   391  	expectedVersion := tableDesc.Version + 3
   392  
   393  	// Concurrently, rename the table.
   394  	start := startRename
   395  	var wg sync.WaitGroup
   396  	wg.Add(1)
   397  	go func() {
   398  		if _, err := db.Exec("ALTER TABLE test.t RENAME TO test.t2"); err != nil {
   399  			t.Error(err)
   400  		}
   401  		wg.Done()
   402  	}()
   403  
   404  	<-start
   405  	if _, err := db.Exec("ALTER TABLE test.t2 RENAME TO test.t3"); err != nil {
   406  		t.Fatal(err)
   407  	}
   408  	close(finishRename)
   409  
   410  	wg.Wait()
   411  
   412  	// Table rename to t3 was successful.
   413  	tableDesc = sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t3")
   414  	if version := tableDesc.Version; expectedVersion != version {
   415  		t.Fatalf("version mismatch: expected = %d, current = %d", expectedVersion, version)
   416  	}
   417  
   418  	// Old names are gone.
   419  	if _, err := db.Exec("SELECT * FROM test.t"); !testutils.IsError(
   420  		err, `relation "test.t" does not exist`) {
   421  		t.Fatal(err)
   422  	}
   423  	if _, err := db.Exec("SELECT * FROM test.t2"); !testutils.IsError(
   424  		err, `relation "test.t2" does not exist`) {
   425  		t.Fatal(err)
   426  	}
   427  }