func TestInsert(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.kv ( k CHAR PRIMARY KEY, v CHAR, CONSTRAINT a INDEX (k, v), CONSTRAINT b UNIQUE (v) ); INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); `); err != nil { t.Fatal(err) } // The first `MaxReservedDescID` (plus 0) are set aside. nameKey := sql.MakeNameMetadataKey(sql.MaxReservedDescID+1, "kv") gr, err := kvDB.Get(nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("TableDescriptor %q does not exist", nameKey) } descKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt())) desc := sql.TableDescriptor{} if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } var tablePrefix []byte tablePrefix = append(tablePrefix, keys.TableDataPrefix...) tablePrefix = encoding.EncodeUvarint(tablePrefix, uint64(desc.ID)) tableStartKey := proto.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 12; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } // Insert that will fail after the index `a` is written. if _, err := sqlDB.Exec(`INSERT INTO t.kv VALUES ('d', 'd')`); !testutils.IsError(err, "duplicate key value .* violates unique constraint") { t.Fatalf("unexpected error %s", err) } // Verify nothing was written. if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 12; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } }
func TestDelete(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.kv ( k CHAR PRIMARY KEY, v CHAR, CONSTRAINT a UNIQUE (v) ); INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); `); err != nil { t.Fatal(err) } // The first `MaxReservedDescID` (plus 0) are set aside. nameKey := sql.MakeNameMetadataKey(sql.MaxReservedDescID+1, "kv") gr, err := kvDB.Get(nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("TableDescriptor %q does not exist", nameKey) } descKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt())) desc := sql.TableDescriptor{} if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } var tablePrefix []byte tablePrefix = append(tablePrefix, keys.TableDataPrefix...) tablePrefix = encoding.EncodeUvarint(tablePrefix, uint64(desc.ID)) tableStartKey := proto.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 9; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if _, err := sqlDB.Exec(`DELETE FROM t.kv`); err != nil { t.Fatal(err) } if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 0; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } }
// TestStoreRangeSplitAtTablePrefix verifies a range can be split at // UserTableDataMin and still gossip the SystemConfig properly. func TestStoreRangeSplitAtTablePrefix(t *testing.T) { defer leaktest.AfterTest(t) defer config.TestingDisableTableSplits()() store, stopper := createTestStore(t) defer stopper.Stop() key := keys.MakeNonColumnKey(append([]byte(nil), keys.UserTableDataMin...)) args := adminSplitArgs(key, key) _, err := client.SendWrapped(rg1(store), nil, &args) if err != nil { t.Fatalf("%q: split unexpected error: %s", key, err) } desc := &sql.TableDescriptor{} descBytes, err := desc.Marshal() if err != nil { t.Fatal(err) } // Update SystemConfig to trigger gossip. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemConfigTrigger() // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + 1)) return txn.Put(k, desc) }); err != nil { t.Fatal(err) } successChan := make(chan struct{}, 1) store.Gossip().RegisterCallback(gossip.KeySystemConfig, func(_ string, content roachpb.Value) { contentBytes, err := content.GetBytes() if err != nil { t.Fatal(err) } if bytes.Contains(contentBytes, descBytes) { select { case successChan <- struct{}{}: default: } } }) select { case <-time.After(time.Second): t.Errorf("expected a schema gossip containing %q, but did not see one", descBytes) case <-successChan: } }
// TestStoreRangeSplitAtTablePrefix verifies a range can be split // at TableDataPrefix and still gossip the SystemConfig properly. func TestStoreRangeSplitAtTablePrefix(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) defer stopper.Stop() key := keys.TableDataPrefix args := adminSplitArgs(key, key) _, err := client.SendWrapped(rg1(store), nil, &args) if err != nil { t.Fatalf("%q: split unexpected error: %s", key, err) } // Update SystemConfig to trigger gossip. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger() k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + 1)) return txn.Put(k, 10) }); err != nil { t.Fatal(err) } }
func TestSystemDBGossip(t *testing.T) { defer leaktest.AfterTest(t) s := StartTestServer(t) defer s.Stop() resultChan := make(chan roachpb.Value) var count int32 db := s.db key := sql.MakeDescMetadataKey(keys.MaxReservedDescID) valAt := func(i int) *sql.DatabaseDescriptor { return &sql.DatabaseDescriptor{Name: "foo", ID: sql.ID(i)} } // Register a callback for gossip updates. s.Gossip().RegisterCallback(gossip.KeySystemConfig, func(_ string, content roachpb.Value) { newCount := atomic.AddInt32(&count, 1) if newCount != 2 { // RegisterCallback calls us right away with the contents, // so ignore the very first call. // We also only want the first value of all our writes. return } resultChan <- content }) // The span only gets gossiped when it first shows up, or when // the EndTransaction trigger is set. // Try a plain KV write first. if err := db.Put(key, valAt(0)); err != nil { t.Fatal(err) } // Now do it as part of a transaction, but without the trigger set. if err := db.Txn(func(txn *client.Txn) error { return txn.Put(key, valAt(1)) }); err != nil { t.Fatal(err) } // This time mark the transaction as having a SystemDB trigger. if err := db.Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger() return txn.Put(key, valAt(2)) }); err != nil { t.Fatal(err) } // Wait for the callback. var systemConfig config.SystemConfig select { case content := <-resultChan: if err := content.GetProto(&systemConfig); err != nil { t.Fatal(err) } case <-time.After(500 * time.Millisecond): t.Fatal("did not receive gossip callback") } // Now check the gossip callback. var val *roachpb.Value for _, kv := range systemConfig.Values { if bytes.Equal(key, kv.Key) { val = &kv.Value break } } if val == nil { t.Fatal("key not found in gossiped info") } // Make sure the returned value is valAt(2). var got sql.DatabaseDescriptor if err := val.GetProto(&got); err != nil { t.Fatal(err) } if got.ID != 2 { t.Fatalf("mismatch: expected %+v, got %+v", valAt(2), got) } }
// TestStoreRangeSystemSplits verifies that splits are based on the contents of // the SystemConfig span. func TestStoreRangeSystemSplits(t *testing.T) { defer leaktest.AfterTest(t)() store, stopper, _ := createTestStore(t) defer stopper.Stop() schema := sql.MakeMetadataSchema() initialSystemValues := schema.GetInitialValues() var userTableMax int // Write the initial sql values to the system DB as well // as the equivalent of table descriptors for X user tables. // This does two things: // - descriptor IDs are used to determine split keys // - the write triggers a SystemConfig update and gossip. // We should end up with splits at each user table prefix. if pErr := store.DB().Txn(func(txn *client.Txn) *roachpb.Error { prefix := keys.MakeTablePrefix(keys.DescriptorTableID) txn.SetSystemConfigTrigger() for i, kv := range initialSystemValues { if !bytes.HasPrefix(kv.Key, prefix) { continue } bytes, err := kv.Value.GetBytes() if err != nil { log.Info(err) continue } if pErr := txn.Put(kv.Key, bytes); pErr != nil { return pErr } descID := keys.MaxReservedDescID + i + 1 userTableMax = i + 1 // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(descID)) if pErr := txn.Put(k, bytes); pErr != nil { return pErr } } return nil }); pErr != nil { t.Fatal(pErr) } verifySplitsAtTablePrefixes := func(maxTableID int) { // We expect splits at each of the user tables, but not at the system // tables boundaries. expKeys := make([]roachpb.Key, 0, maxTableID+2) // We can't simply set numReservedTables to schema.TableCount(), because // some system tables are created at cluster bootstrap time. So, before the // cluster bootstrap, TableCount() will return a value that's too low. numReservedTables := schema.MaxTableID() - keys.MaxSystemConfigDescID for i := 1; i <= int(numReservedTables); i++ { expKeys = append(expKeys, testutils.MakeKey(keys.Meta2Prefix, keys.MakeTablePrefix(keys.MaxSystemConfigDescID+uint32(i))), ) } for i := 1; i <= maxTableID; i++ { expKeys = append(expKeys, testutils.MakeKey(keys.Meta2Prefix, keys.MakeTablePrefix(keys.MaxReservedDescID+uint32(i))), ) } expKeys = append(expKeys, testutils.MakeKey(keys.Meta2Prefix, roachpb.RKeyMax)) util.SucceedsSoonDepth(1, t, func() error { rows, pErr := store.DB().Scan(keys.Meta2Prefix, keys.MetaMax, 0) if pErr != nil { return pErr.GoError() } keys := make([]roachpb.Key, 0, len(expKeys)) for _, r := range rows { keys = append(keys, r.Key) } if !reflect.DeepEqual(keys, expKeys) { return util.Errorf("expected split keys:\n%v\nbut found:\n%v", expKeys, keys) } return nil }) } verifySplitsAtTablePrefixes(userTableMax) numTotalValues := keys.MaxSystemConfigDescID + 5 // Write another, disjoint descriptor for a user table. if pErr := store.DB().Txn(func(txn *client.Txn) *roachpb.Error { txn.SetSystemConfigTrigger() // This time, only write the last table descriptor. Splits // still occur for every intervening ID. // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + numTotalValues)) return txn.Put(k, &sql.TableDescriptor{}) }); pErr != nil { t.Fatal(pErr) } verifySplitsAtTablePrefixes(numTotalValues) }
func TestCommandsWithPendingMutations(t *testing.T) { defer leaktest.AfterTest(t) // The descriptor changes made must have an immediate effect // so disable leases on tables. defer csql.TestDisableTableLeases()() // Disable external processing of mutations. defer csql.TestDisableAsyncSchemaChangeExec()() server, sqlDB, kvDB := setup(t) defer cleanup(server, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (a CHAR PRIMARY KEY, b CHAR, c CHAR, INDEX foo (c)); `); err != nil { t.Fatal(err) } // Read table descriptor nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test") gr, err := kvDB.Get(nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt())) desc := &csql.Descriptor{} if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } mt := mutationTest{ T: t, kvDB: kvDB, sqlDB: sqlDB, descKey: descKey, desc: desc, } // Test CREATE INDEX in the presence of mutations. // Add index DROP mutation "foo"" mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP}) if _, err := sqlDB.Exec(`CREATE INDEX foo ON t.test (c)`); !testutils.IsError(err, `index "foo" being dropped, try again later`) { t.Fatal(err) } // Make "foo" live. mt.makeMutationsActive() // "foo" is being added. mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD}) if _, err := sqlDB.Exec(`CREATE INDEX foo ON t.test (c)`); !testutils.IsError(err, `duplicate index name: "foo"`) { t.Fatal(err) } // Make "foo" live. mt.makeMutationsActive() // Add column DROP mutation "b" mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP}) if _, err := sqlDB.Exec(`CREATE INDEX bar ON t.test (b)`); !testutils.IsError(err, `index "bar" contains unknown column "b"`) { t.Fatal(err) } // Make "b" live. mt.makeMutationsActive() // "b" is being added. mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD}) // An index referencing a column mutation that is being added // is allowed to be added. if _, err := sqlDB.Exec(`CREATE INDEX bar ON t.test (b)`); err != nil { t.Fatal(err) } // Make "b" live. mt.makeMutationsActive() // Test DROP INDEX in the presence of mutations. // Add index DROP mutation "foo"" mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP}) // Noop. if _, err := sqlDB.Exec(`DROP INDEX t.test@foo`); err != nil { t.Fatal(err) } // Make "foo" live. mt.makeMutationsActive() // "foo" is being added. mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD}) if _, err := sqlDB.Exec(`DROP INDEX t.test@foo`); !testutils.IsError(err, `index "foo" in the middle of being added, try again later`) { t.Fatal(err) } // Make "foo" live. mt.makeMutationsActive() // Test ALTER TABLE ADD/DROP column in the presence of mutations. // Add column DROP mutation "b" mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP}) if _, err := sqlDB.Exec(`ALTER TABLE t.test ADD b CHAR`); !testutils.IsError(err, `column "b" being dropped, try again later`) { t.Fatal(err) } // Noop. if _, err := sqlDB.Exec(`ALTER TABLE t.test DROP b`); err != nil { t.Fatal(err) } // Make "b" live. mt.makeMutationsActive() // "b" is being added. mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD}) if _, err := sqlDB.Exec(`ALTER TABLE t.test ADD b CHAR`); !testutils.IsError(err, `duplicate column name: "b"`) { t.Fatal(err) } if _, err := sqlDB.Exec(`ALTER TABLE t.test DROP b`); !testutils.IsError(err, `column "b" in the middle of being added, try again later`) { t.Fatal(err) } // Make "b" live. mt.makeMutationsActive() // Test ALTER TABLE ADD CONSTRAINT in the presence of mutations. // Add index DROP mutation "foo"" mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP}) if _, err := sqlDB.Exec(`ALTER TABLE t.test ADD CONSTRAINT foo UNIQUE (c)`); !testutils.IsError(err, `index "foo" being dropped, try again later`) { t.Fatal(err) } // Make "foo" live. mt.makeMutationsActive() // "foo" is being added. mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD}) if _, err := sqlDB.Exec(`ALTER TABLE t.test ADD CONSTRAINT foo UNIQUE (c)`); !testutils.IsError(err, `duplicate index name: "foo"`) { t.Fatal(err) } // Make "foo" live. mt.makeMutationsActive() // Add column mutation "b" mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP}) if _, err := sqlDB.Exec(`ALTER TABLE t.test ADD CONSTRAINT bar UNIQUE (b)`); !testutils.IsError(err, `index "bar" contains unknown column "b"`) { t.Fatal(err) } // Make "b" live. mt.makeMutationsActive() // "b" is being added. mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD}) // Noop. if _, err := sqlDB.Exec(`ALTER TABLE t.test ADD CONSTRAINT bar UNIQUE (b)`); err != nil { t.Fatal(err) } // Make "b" live. mt.makeMutationsActive() // Test DROP CONSTRAINT in the presence of mutations. // Add index mutation "foo"" mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP}) // Noop. if _, err := sqlDB.Exec(`ALTER TABLE t.test DROP CONSTRAINT foo`); err != nil { t.Fatal(err) } // Make "foo" live. mt.makeMutationsActive() // "foo" is being added. mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD}) if _, err := sqlDB.Exec(`ALTER TABLE t.test DROP CONSTRAINT foo`); !testutils.IsError(err, `constraint "foo" in the middle of being added, try again later`) { t.Fatal(err) } // Make "foo" live. mt.makeMutationsActive() // Rename column/index, while index is under mutation. // Add index mutation "foo"" mt.writeIndexMutation("foo", csql.DescriptorMutation{}) if _, err := sqlDB.Exec(`ALTER INDEX t.test@foo RENAME to ufo`); err != nil { mt.Fatal(err) } if _, err := sqlDB.Exec(`ALTER TABLE t.test RENAME COLUMN c TO d`); err != nil { mt.Fatal(err) } // The mutation in the table descriptor has changed and we would like // to update our copy to make it live. if err := mt.kvDB.GetProto(mt.descKey, mt.desc); err != nil { mt.Fatal(err) } // Make "ufo" live. mt.makeMutationsActive() // The index has been renamed to ufo, and the column to d. _ = mt.checkQueryResponse("SHOW INDEX FROM t.test", [][]string{{"test", "primary", "true", "1", "a", "ASC", "false"}, {"test", "ufo", "false", "1", "d", "ASC", "false"}}) // Rename column under mutation works properly. // Add column mutation "b". mt.writeColumnMutation("b", csql.DescriptorMutation{}) if _, err := sqlDB.Exec(`ALTER TABLE t.test RENAME COLUMN b TO e`); err != nil { mt.Fatal(err) } // The mutation in the table descriptor has changed and we would like // to update our copy to make it live. if err := mt.kvDB.GetProto(mt.descKey, mt.desc); err != nil { mt.Fatal(err) } // Make column "e" live. mt.makeMutationsActive() // Column b changed to d. _ = mt.checkQueryResponse("SHOW COLUMNS FROM t.test", [][]string{{"a", "STRING", "true", "NULL"}, {"d", "STRING", "true", "NULL"}, {"e", "STRING", "true", "NULL"}}) }
// TestStoreRangeSystemSplits verifies that splits are based on the // contents of the SystemDB span. func TestStoreRangeSystemSplits(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) defer stopper.Stop() // Write the initial sql values to the system DB as well // as the equivalent of table descriptors for X user tables. // This does two things: // - descriptor IDs are used to determine split keys // - the write triggers a SystemConfig update and gossip. // We should end up with splits at each user table prefix. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger() for _, kv := range sql.GetInitialSystemValues() { if err := txn.Put(kv.Key, kv.Value.GetRawBytes()); err != nil { return err } } for i := 1; i <= 5; i++ { // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + i)) v, err := txn.Get(k) if err != nil { return err } if err := txn.Put(k, v.ValueBytes()); err != nil { return err } } return nil }); err != nil { t.Fatal(err) } expKeys := []roachpb.Key{} for i := 1; i <= 5; i++ { expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, keys.MakeTablePrefix(uint32(keys.MaxReservedDescID+i)))) } expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, roachpb.RKeyMax)) if err := util.IsTrueWithin(func() bool { rows, err := store.DB().Scan(keys.Meta2Prefix, keys.MetaMax, 0) if err != nil { t.Fatalf("failed to scan meta2 keys: %s", err) } var keys []roachpb.Key for _, r := range rows { keys = append(keys, r.Key) } return reflect.DeepEqual(keys, expKeys) }, 5*time.Second); err != nil { t.Errorf("expected splits not found: %s", err) } // Write more descriptors for user tables. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger() // This time, only write the last table descriptor. Splits // still occur for every ID. // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + 10)) v, err := txn.Get(k) if err != nil { return err } return txn.Put(k, v.ValueBytes()) }); err != nil { t.Fatal(err) } expKeys = []roachpb.Key{} for i := 1; i <= 10; i++ { expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, keys.MakeTablePrefix(uint32(keys.MaxReservedDescID+i)))) } expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, roachpb.RKeyMax)) if err := util.IsTrueWithin(func() bool { rows, err := store.DB().Scan(keys.Meta2Prefix, keys.MetaMax, 0) if err != nil { t.Fatalf("failed to scan meta2 keys: %s", err) } var keys []roachpb.Key for _, r := range rows { keys = append(keys, r.Key) } return reflect.DeepEqual(keys, expKeys) }, 5*time.Second); err != nil { t.Errorf("expected splits not found: %s", err) } }
// TestStoreRangeSystemSplits verifies that splits are based on the // contents of the SystemDB span. func TestStoreRangeSystemSplits(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) defer stopper.Stop() initialSystemValues := sql.MakeMetadataSchema().GetInitialValues() numInitialValues := len(initialSystemValues) // Write the initial sql values to the system DB as well // as the equivalent of table descriptors for X user tables. // This does two things: // - descriptor IDs are used to determine split keys // - the write triggers a SystemConfig update and gossip. // We should end up with splits at each user table prefix. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger() for i, kv := range initialSystemValues { bytes, err := kv.Value.GetBytes() if err != nil { log.Info(err) continue } if err := txn.Put(kv.Key, bytes); err != nil { return err } descID := keys.MaxReservedDescID + i + 1 // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(descID)) if err := txn.Put(k, bytes); err != nil { return err } } return nil }); err != nil { t.Fatal(err) } verifySplitsAtTablePrefixes := func(maxTableID int) { // We expect splits at each of the user tables, but not at the system // tables boundaries. expKeys := make([]roachpb.Key, 0, maxTableID+1) for i := 1; i <= maxTableID; i++ { expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, keys.MakeTablePrefix(keys.MaxReservedDescID+uint32(i))), ) } expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, roachpb.RKeyMax)) util.SucceedsWithinDepth(1, t, 5*time.Second, func() error { rows, err := store.DB().Scan(keys.Meta2Prefix, keys.MetaMax, 0) if err != nil { return err } keys := make([]roachpb.Key, 0, len(expKeys)) for _, r := range rows { keys = append(keys, r.Key) } if !reflect.DeepEqual(keys, expKeys) { return util.Errorf("expected split keys:\n%v\nbut found:\n%v", expKeys, keys) } return nil }) } verifySplitsAtTablePrefixes(len(initialSystemValues)) numTotalValues := numInitialValues + 5 // Write another, disjoint descriptor for a user table. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger() // This time, only write the last table descriptor. Splits // still occur for every intervening ID. // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + numTotalValues)) return txn.Put(k, &sql.TableDescriptor{}) }); err != nil { t.Fatal(err) } verifySplitsAtTablePrefixes(numTotalValues) }
// Test schema change backfills are not affected by various operations // that run simultaneously. func TestRaceWithBackfill(t *testing.T) { defer leaktest.AfterTest(t)() server, sqlDB, kvDB := setup(t) defer cleanup(server, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (k INT PRIMARY KEY, v INT); `); err != nil { t.Fatal(err) } // Bulk insert. max_value := 2000 insert := fmt.Sprintf(`INSERT INTO t.test VALUES (%d, %d)`, 0, max_value) for i := 1; i <= max_value; i++ { insert += fmt.Sprintf(` ,(%d, %d)`, i, max_value-i) } if _, err := sqlDB.Exec(insert); err != nil { t.Fatal(err) } // Read table descriptor for version. nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test") gr, pErr := kvDB.Get(nameKey) if pErr != nil { t.Fatal(pErr) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt())) desc := &csql.Descriptor{} if pErr := kvDB.GetProto(descKey, desc); pErr != nil { t.Fatal(pErr) } version := desc.GetTable().Version // Run the schema changes in a separate goroutine. var wg sync.WaitGroup wg.Add(1) go func() { start := timeutil.Now() // Start schema change that eventually runs a number of backfills. if _, err := sqlDB.Exec(` BEGIN; ALTER TABLE t.test ADD COLUMN x DECIMAL DEFAULT (DECIMAL '1.4'); CREATE UNIQUE INDEX foo ON t.test (v); END; `); err != nil { t.Error(err) } t.Logf("schema changes took %v", time.Since(start)) wg.Done() }() // Wait until the backfills for the schema changes above have // started. util.SucceedsSoon(t, func() error { if pErr := kvDB.GetProto(descKey, desc); pErr != nil { t.Fatal(pErr) } if desc.GetTable().Version == version+2 { // Version upgrade has happened, backfills can proceed. return nil } return errors.New("version not updated") }) // TODO(vivek): uncomment these inserts when #5817 is fixed. // Insert some new rows in the table while the backfills are running. //num_values := 5 //for i := 0; i < num_values; i++ { // t.Logf("inserting a new value into the table") // if _, err := sqlDB.Exec(`INSERT INTO t.test VALUES($1, $2)`, max_value+i+1, max_value+i+1); err != nil { // t.Fatal(err) // } //} // Renaming an index in the middle of the backfills will not affect // the backfills because the above schema changes have the schema change // lease on the table. All future schema changes have to wait in line for // the lease. if _, err := sqlDB.Exec(` ALTER INDEX t.test@foo RENAME TO bar; `); err != nil { t.Fatal(err) } // Wait until schema changes have completed. wg.Wait() // Verify that the index over v is consistent. rows, err := sqlDB.Query(`SELECT v from t.test@bar`) if err != nil { t.Fatal(err) } i := 0 for ; rows.Next(); i++ { var val int if err := rows.Scan(&val); err != nil { t.Fatal(err) } if i != val { t.Errorf("e = %d, v = %d", i, val) } } if err := rows.Err(); err != nil { t.Fatal(err) } if max_value+1 != i { t.Fatalf("read the wrong number of rows: e = %d, v = %d", max_value+1, i) } }
func TestDropDatabase(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR); INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); `); err != nil { t.Fatal(err) } dbNameKey := sql.MakeNameMetadataKey(sql.RootNamespaceID, "t") r, err := kvDB.Get(dbNameKey) if err != nil { t.Fatal(err) } if !r.Exists() { t.Fatalf(`database "t" does not exist`) } dbDescKey := sql.MakeDescMetadataKey(sql.ID(r.ValueInt())) dbDesc := sql.DatabaseDescriptor{} if err := kvDB.GetProto(dbDescKey, &dbDesc); err != nil { t.Fatal(err) } tbNameKey := sql.MakeNameMetadataKey(dbDesc.ID, "kv") gr, err := kvDB.Get(tbNameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf(`table "kv" does not exist`) } tbDescKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt())) tbDesc := sql.TableDescriptor{} if err := kvDB.GetProto(tbDescKey, &tbDesc); err != nil { t.Fatal(err) } var tablePrefix []byte tablePrefix = append(tablePrefix, keys.TableDataPrefix...) tablePrefix = encoding.EncodeUvarint(tablePrefix, uint64(tbDesc.ID)) tableStartKey := proto.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 6; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if _, err := sqlDB.Exec(`DROP DATABASE t`); err != nil { t.Fatal(err) } if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 0; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if gr, err := kvDB.Get(tbDescKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table descriptor still exists after database is dropped") } if gr, err := kvDB.Get(tbNameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table descriptor key still exists after database is dropped") } if gr, err := kvDB.Get(dbDescKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("database descriptor still exists after database is dropped") } if gr, err := kvDB.Get(dbNameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("database descriptor key still exists after database is dropped") } }
// TestRenameTable tests the table descriptor changes during // a rename operation. func TestRenameTable(t *testing.T) { defer leaktest.AfterTest(t) defer config.TestingDisableTableSplits()() s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) counter := int64(keys.MaxReservedDescID + 1) // Table creation should fail, and nothing should have been written. oldDBID := sql.ID(counter) if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } counter++ // Create table in 'test'. tableCounter := counter oldName := "foo" if _, err := sqlDB.Exec(`CREATE TABLE test.foo (k INT PRIMARY KEY, v int)`); err != nil { t.Fatal(err) } counter++ // Check the table descriptor. desc := &sql.Descriptor{} tableDescKey := sql.MakeDescMetadataKey(sql.ID(tableCounter)) if err := kvDB.GetProto(tableDescKey, desc); err != nil { t.Fatal(err) } tableDesc := desc.GetTable() if tableDesc.Name != oldName { t.Fatalf("Wrong table name, expected %s, got: %+v", oldName, tableDesc) } if tableDesc.ParentID != oldDBID { t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", oldDBID, tableDesc) } // Create database test2. newDBID := sql.ID(counter) if _, err := sqlDB.Exec(`CREATE DATABASE test2`); err != nil { t.Fatal(err) } counter++ // Move table to test2 and change its name as well. newName := "bar" if _, err := sqlDB.Exec(`ALTER TABLE test.foo RENAME TO test2.bar`); err != nil { t.Fatal(err) } // Check the table descriptor again. if err := kvDB.GetProto(tableDescKey, desc); err != nil { t.Fatal(err) } tableDesc = desc.GetTable() if tableDesc.Name != newName { t.Fatalf("Wrong table name, expected %s, got: %+v", newName, tableDesc) } if tableDesc.ParentID != newDBID { t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", newDBID, tableDesc) } }
func TestSchemaChangeProcess(t *testing.T) { defer leaktest.AfterTest(t) // The descriptor changes made must have an immediate effect // so disable leases on tables. defer csql.TestDisableTableLeases()() // Disable external processing of mutations. defer csql.TestDisableAsyncSchemaChangeExec()() server, sqlDB, kvDB := setup(t) defer cleanup(server, sqlDB) var id = csql.ID(keys.MaxReservedDescID + 2) var node = roachpb.NodeID(2) db := server.DB() leaseMgr := csql.NewLeaseManager(0, *db, hlc.NewClock(hlc.UnixNano)) changer := csql.NewSchemaChangerForTesting(id, 0, node, *db, leaseMgr) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo(v)); INSERT INTO t.test VALUES ('a', 'b'), ('c', 'd'); `); err != nil { t.Fatal(err) } // Read table descriptor for version. nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test") gr, err := kvDB.Get(nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt())) desc := &csql.Descriptor{} // Check that MaybeIncrementVersion doesn't increment the version // when the up_version bit is not set. if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } expectedVersion := desc.GetTable().Version if err := changer.MaybeIncrementVersion(); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } newVersion := desc.GetTable().Version if newVersion != expectedVersion { t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion) } isDone, err := changer.IsDone() if err != nil { t.Fatal(err) } if !isDone { t.Fatalf("table expected to not have an outstanding schema change: %v", desc.GetTable()) } // Check that MaybeIncrementVersion increments the version // correctly. expectedVersion++ desc.GetTable().UpVersion = true if err := kvDB.Put(descKey, desc); err != nil { t.Fatal(err) } isDone, err = changer.IsDone() if err != nil { t.Fatal(err) } if isDone { t.Fatalf("table expected to have an outstanding schema change: %v", desc.GetTable()) } if err := changer.MaybeIncrementVersion(); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } newVersion = desc.GetTable().Version if newVersion != expectedVersion { t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion) } isDone, err = changer.IsDone() if err != nil { t.Fatal(err) } if !isDone { t.Fatalf("table expected to not have an outstanding schema change: %v", desc.GetTable()) } // Check that RunStateMachineBeforeBackfill doesn't do anything // if there are no mutations queued. if err := changer.RunStateMachineBeforeBackfill(); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } newVersion = desc.GetTable().Version if newVersion != expectedVersion { t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion) } // Check that RunStateMachineBeforeBackfill functions properly. if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } table := desc.GetTable() expectedVersion = table.Version // Make a copy of the index for use in a mutation. index := proto.Clone(&table.Indexes[0]).(*csql.IndexDescriptor) index.Name = "bar" index.ID = table.NextIndexID table.NextIndexID++ changer = csql.NewSchemaChangerForTesting(id, table.NextMutationID, node, *db, leaseMgr) table.Mutations = append(table.Mutations, csql.DescriptorMutation{ Descriptor_: &csql.DescriptorMutation_Index{Index: index}, Direction: csql.DescriptorMutation_ADD, State: csql.DescriptorMutation_DELETE_ONLY, MutationID: table.NextMutationID, }) table.NextMutationID++ // Run state machine in both directions. for _, direction := range []csql.DescriptorMutation_Direction{csql.DescriptorMutation_ADD, csql.DescriptorMutation_DROP} { table.Mutations[0].Direction = direction expectedVersion++ if err := kvDB.Put(descKey, desc); err != nil { t.Fatal(err) } // The expected end state. expectedState := csql.DescriptorMutation_WRITE_ONLY if direction == csql.DescriptorMutation_DROP { expectedState = csql.DescriptorMutation_DELETE_ONLY } // Run two times to ensure idempotency of operations. for i := 0; i < 2; i++ { if err := changer.RunStateMachineBeforeBackfill(); err != nil { t.Fatal(err) } if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } table = desc.GetTable() newVersion = table.Version if newVersion != expectedVersion { t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion) } state := table.Mutations[0].State if state != expectedState { t.Fatalf("bad state; e = %d, v = %d", expectedState, state) } } } // RunStateMachineBeforeBackfill() doesn't complete the schema change. isDone, err = changer.IsDone() if err != nil { t.Fatal(err) } if isDone { t.Fatalf("table expected to have an outstanding schema change: %v", desc.GetTable()) } }
func TestAsyncSchemaChanger(t *testing.T) { defer leaktest.AfterTest(t) // Disable synchronous schema change execution so // the asynchronous schema changer executes all // schema changes. defer csql.TestDisableSyncSchemaChangeExec()() // The descriptor changes made must have an immediate effect // so disable leases on tables. defer csql.TestDisableTableLeases()() server, sqlDB, kvDB := setup(t) defer cleanup(server, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR); INSERT INTO t.test VALUES ('a', 'b'), ('c', 'd'); `); err != nil { t.Fatal(err) } // Read table descriptor for version. nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test") gr, err := kvDB.Get(nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt())) desc := &csql.Descriptor{} if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } // A long running schema change operation runs through // a state machine that increments the version by 3. expectedVersion := desc.GetTable().Version + 3 // Run some schema change if _, err := sqlDB.Exec(` CREATE INDEX foo ON t.test (v) `); err != nil { t.Fatal(err) } retryOpts := retry.Options{ InitialBackoff: 20 * time.Millisecond, MaxBackoff: 200 * time.Millisecond, Multiplier: 2, } // Wait until index is created. for r := retry.Start(retryOpts); r.Next(); { if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } if len(desc.GetTable().Indexes) == 1 { break } } // Ensure that the indexes have been created. mTest := mutationTest{ T: t, kvDB: kvDB, sqlDB: sqlDB, descKey: descKey, desc: desc, } indexQuery := `SELECT * FROM t.test@foo` _ = mTest.checkQueryResponse(indexQuery, [][]string{{"b"}, {"d"}}) // Ensure that the version has been incremented. if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } newVersion := desc.GetTable().Version if newVersion != expectedVersion { t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion) } // Apply a schema change that only sets the UpVersion bit. expectedVersion = newVersion + 1 if _, err := sqlDB.Exec(` ALTER INDEX t.test@foo RENAME TO ufo `); err != nil { t.Fatal(err) } for r := retry.Start(retryOpts); r.Next(); { // Ensure that the version gets incremented. if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } name := desc.GetTable().Indexes[0].Name if name != "ufo" { t.Fatalf("bad index name %s", name) } newVersion = desc.GetTable().Version if newVersion == expectedVersion { break } } // Run many schema changes simultaneously and check // that they all get executed. count := 5 for i := 0; i < count; i++ { cmd := fmt.Sprintf(`CREATE INDEX foo%d ON t.test (v)`, i) if _, err := sqlDB.Exec(cmd); err != nil { t.Fatal(err) } } // Wait until indexes are created. for r := retry.Start(retryOpts); r.Next(); { if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } if len(desc.GetTable().Indexes) == count+1 { break } } for i := 0; i < count; i++ { indexQuery := fmt.Sprintf(`SELECT * FROM t.test@foo%d`, i) _ = mTest.checkQueryResponse(indexQuery, [][]string{{"b"}, {"d"}}) } }
func TestDropDatabase(t *testing.T) { defer leaktest.AfterTest(t)() s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR); INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); `); err != nil { t.Fatal(err) } dbNameKey := sql.MakeNameMetadataKey(keys.RootNamespaceID, "t") r, pErr := kvDB.Get(dbNameKey) if pErr != nil { t.Fatal(pErr) } if !r.Exists() { t.Fatalf(`database "t" does not exist`) } dbDescKey := sql.MakeDescMetadataKey(sql.ID(r.ValueInt())) desc := &sql.Descriptor{} if pErr := kvDB.GetProto(dbDescKey, desc); pErr != nil { t.Fatal(pErr) } dbDesc := desc.GetDatabase() tbNameKey := sql.MakeNameMetadataKey(dbDesc.ID, "kv") gr, pErr := kvDB.Get(tbNameKey) if pErr != nil { t.Fatal(pErr) } if !gr.Exists() { t.Fatalf(`table "kv" does not exist`) } tbDescKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt())) if pErr := kvDB.GetProto(tbDescKey, desc); pErr != nil { t.Fatal(pErr) } tbDesc := desc.GetTable() // Add a zone config for both the table and database. cfg := config.DefaultZoneConfig() buf, err := proto.Marshal(&cfg) if err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, tbDesc.ID, buf); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, dbDesc.ID, buf); err != nil { t.Fatal(err) } tbZoneKey := sql.MakeZoneKey(tbDesc.ID) dbZoneKey := sql.MakeZoneKey(dbDesc.ID) if gr, err := kvDB.Get(tbZoneKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatalf("table zone config entry not found") } if gr, err := kvDB.Get(dbZoneKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatalf("database zone config entry not found") } tablePrefix := keys.MakeTablePrefix(uint32(tbDesc.ID)) tableStartKey := roachpb.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 6; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if _, err := sqlDB.Exec(`DROP DATABASE t`); err != nil { t.Fatal(err) } if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 0; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if gr, err := kvDB.Get(tbDescKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table descriptor still exists after database is dropped") } if gr, err := kvDB.Get(tbNameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table descriptor key still exists after database is dropped") } if gr, err := kvDB.Get(dbDescKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("database descriptor still exists after database is dropped") } if gr, err := kvDB.Get(dbNameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("database descriptor key still exists after database is dropped") } if gr, err := kvDB.Get(tbZoneKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table zone config entry still exists after the database is dropped") } if gr, err := kvDB.Get(dbZoneKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("database zone config entry still exists after the database is dropped") } }
func TestDropIndex(t *testing.T) { defer leaktest.AfterTest(t)() s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR); CREATE INDEX foo on t.kv (v); INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); `); err != nil { t.Fatal(err) } nameKey := sql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "kv") gr, pErr := kvDB.Get(nameKey) if pErr != nil { t.Fatal(pErr) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt())) desc := &sql.Descriptor{} if pErr := kvDB.GetProto(descKey, desc); pErr != nil { t.Fatal(pErr) } tableDesc := desc.GetTable() status, i, err := tableDesc.FindIndexByName("foo") if err != nil { t.Fatal(err) } if status != sql.DescriptorActive { t.Fatal("Index 'foo' is not active.") } indexPrefix := sql.MakeIndexKeyPrefix(tableDesc.ID, tableDesc.Indexes[i].ID) indexStartKey := roachpb.Key(indexPrefix) indexEndKey := indexStartKey.PrefixEnd() if kvs, err := kvDB.Scan(indexStartKey, indexEndKey, 0); err != nil { t.Fatal(err) } else if l := 3; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if _, err := sqlDB.Exec(`DROP INDEX t.kv@foo`); err != nil { t.Fatal(err) } if kvs, err := kvDB.Scan(indexStartKey, indexEndKey, 0); err != nil { t.Fatal(err) } else if l := 0; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } tableDesc = desc.GetTable() if _, _, err := tableDesc.FindIndexByName("foo"); err == nil { t.Fatalf("table descriptor still contains index after index is dropped") } if err != nil { t.Fatal(err) } }
func TestDropTable(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR); INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); `); err != nil { t.Fatal(err) } nameKey := sql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "kv") gr, err := kvDB.Get(nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt())) desc := sql.TableDescriptor{} if err := kvDB.GetProto(descKey, &desc); err != nil { t.Fatal(err) } // Add a zone config for the table. buf, err := gogoproto.Marshal(config.DefaultZoneConfig) if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, desc.ID, buf); err != nil { t.Fatal(err) } zoneKey := sql.MakeZoneKey(desc.ID) if gr, err := kvDB.Get(zoneKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatalf("zone config entry not found") } var tablePrefix []byte tablePrefix = append(tablePrefix, keys.TableDataPrefix...) tablePrefix = encoding.EncodeUvarint(tablePrefix, uint64(desc.ID)) tableStartKey := proto.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 6; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if _, err := sqlDB.Exec(`DROP TABLE t.kv`); err != nil { t.Fatal(err) } if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { t.Fatal(err) } else if l := 0; len(kvs) != l { t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs)) } if gr, err := kvDB.Get(descKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table descriptor still exists after the table is dropped") } if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("table namekey still exists after the table is dropped") } if gr, err := kvDB.Get(zoneKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatalf("zone config entry still exists after the table is dropped") } }
func TestDatabaseDescriptor(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) expectedCounter := int64(keys.MaxReservedDescID + 1) // Test values before creating the database. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. nameKey := sql.MakeNameMetadataKey(keys.RootNamespaceID, "test") if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatal("expected non-existing key") } // Write a descriptor key that will interfere with database creation. dbDescKey := sql.MakeDescMetadataKey(sql.ID(expectedCounter)) dbDesc := &sql.Descriptor{ Union: &sql.Descriptor_Database{ Database: &sql.DatabaseDescriptor{ Name: "sentinel", ID: sql.ID(expectedCounter), Privileges: &sql.PrivilegeDescriptor{}, }, }, } if err := kvDB.CPut(dbDescKey, dbDesc, nil); err != nil { t.Fatal(err) } // Database creation should fail, and nothing should have been written. if _, err := sqlDB.Exec(`CREATE DATABASE test`); !testutils.IsError(err, "unexpected value") { t.Fatalf("unexpected error %s", err) } if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } start := roachpb.Key(keys.MakeTablePrefix(uint32(keys.NamespaceTableID))) if kvs, err := kvDB.Scan(start, start.PrefixEnd(), 0); err != nil { t.Fatal(err) } else { if a, e := len(kvs), server.GetBootstrapSchema().DescriptorCount(); a != e { t.Fatalf("expected %d keys to have been written, found %d keys", e, a) } } // Remove the junk; allow database creation to proceed. if err := kvDB.Del(dbDescKey); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } expectedCounter++ // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(dbDescKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // Now try to create it again. We should fail, but not increment the counter. if _, err := sqlDB.Exec(`CREATE DATABASE test`); err == nil { t.Fatal("failure expected") } // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(dbDescKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } }
func TestOperationsWithColumnMutation(t *testing.T) { defer leaktest.AfterTest(t) // The descriptor changes made must have an immediate effect // so disable leases on tables. defer csql.TestDisableTableLeases()() // Disable external processing of mutations. defer csql.TestDisableAsyncSchemaChangeExec()() server, sqlDB, kvDB := setup(t) defer cleanup(server, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, i CHAR DEFAULT 'i'); `); err != nil { t.Fatal(err) } // read table descriptor nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test") gr, err := kvDB.Get(nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt())) desc := &csql.Descriptor{} if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } mTest := mutationTest{ T: t, kvDB: kvDB, sqlDB: sqlDB, descKey: descKey, desc: desc, } starQuery := `SELECT * FROM t.test` // Run the tests for both states. for _, state := range []csql.DescriptorMutation_State{csql.DescriptorMutation_DELETE_ONLY, csql.DescriptorMutation_WRITE_ONLY} { // Init table to start state. if _, err := sqlDB.Exec(`TRUNCATE TABLE t.test`); err != nil { t.Fatal(err) } initRows := [][]string{{"a", "z", "q"}} for _, row := range initRows { if _, err := sqlDB.Exec(`INSERT INTO t.test VALUES ($1, $2, $3)`, row[0], row[1], row[2]); err != nil { t.Fatal(err) } } // Check that the table only contains the initRows. _ = mTest.checkQueryResponse(starQuery, initRows) // Add column "i" as a mutation. mTest.writeColumnMutation("i", csql.DescriptorMutation{State: state}) // A direct read of column "i" fails. if _, err := sqlDB.Query(`SELECT i FROM t.test`); err == nil { t.Fatalf("Read succeeded despite column being in %v state", csql.DescriptorMutation{State: state}) } // The table only contains columns "k" and "v". _ = mTest.checkQueryResponse(starQuery, [][]string{{"a", "z"}}) // Inserting a row into the table while specifying column "i" results in an error. if _, err := sqlDB.Exec(`INSERT INTO t.test (k, v, i) VALUES ('b', 'y', 'i')`); !testutils.IsError(err, `column "i" does not exist`) { t.Fatal(err) } // Repeating the same without specifying the columns results in a different error. if _, err := sqlDB.Exec(`INSERT INTO t.test VALUES ('b', 'y', 'i')`); !testutils.IsError(err, "INSERT has more expressions than target columns: 3/2") { t.Fatal(err) } // Make column "i" live so that it is read. mTest.makeMutationsActive() // Check that we can read all the rows and columns. _ = mTest.checkQueryResponse(starQuery, initRows) var afterInsert, afterUpdate, afterDelete [][]string if state == csql.DescriptorMutation_DELETE_ONLY { // The default value of "i" for column "i" is not written. afterInsert = [][]string{{"a", "z", "q"}, {"c", "x", "NULL"}} // Update is a noop for column "i". afterUpdate = [][]string{{"a", "u", "q"}, {"c", "x", "NULL"}} // Delete also deletes column "i". afterDelete = [][]string{{"c", "x", "NULL"}} } else { // The default value of "i" for column "i" is written. afterInsert = [][]string{{"a", "z", "q"}, {"c", "x", "i"}} // Update is a noop for column "i". afterUpdate = [][]string{{"a", "u", "q"}, {"c", "x", "i"}} // Delete also deletes column "i". afterDelete = [][]string{{"c", "x", "i"}} } // Make column "i" a mutation. mTest.writeColumnMutation("i", csql.DescriptorMutation{State: state}) // Insert a row into the table. if _, err := sqlDB.Exec(`INSERT INTO t.test VALUES ('c', 'x')`); err != nil { t.Fatal(err) } // Make column "i" live so that it is read. mTest.makeMutationsActive() // Notice that the default value of "i" is only written when the // descriptor is in the WRITE_ONLY state. _ = mTest.checkQueryResponse(starQuery, afterInsert) // Make column "i" a mutation. mTest.writeColumnMutation("i", csql.DescriptorMutation{State: state}) // Updating column "i" for a row fails. if _, err := sqlDB.Exec(`UPDATE t.test SET (v, i) = ('u', 'u') WHERE k = 'a'`); !testutils.IsError(err, `column "i" does not exist`) { t.Fatal(err) } // Make column "i" live so that it is read. mTest.makeMutationsActive() // The above failed update was a noop. _ = mTest.checkQueryResponse(starQuery, afterInsert) // Make column "i" a mutation. mTest.writeColumnMutation("i", csql.DescriptorMutation{State: state}) // Update a row without specifying mutation column "i". if _, err := sqlDB.Exec(`UPDATE t.test SET v = 'u' WHERE k = 'a'`); err != nil { t.Fatal(err) } // Make column "i" live so that it is read. mTest.makeMutationsActive() // The update to column "v" is seen; there is no effect on column "i". _ = mTest.checkQueryResponse(starQuery, afterUpdate) // Make column "i" a mutation. mTest.writeColumnMutation("i", csql.DescriptorMutation{State: state}) // Delete row "a". if _, err := sqlDB.Exec(`DELETE FROM t.test WHERE k = 'a'`); err != nil { t.Fatal(err) } // Make column "i" live so that it is read. mTest.makeMutationsActive() // Row "a" is deleted. numVals is the number of non-NULL values seen, // or the number of KV values belonging to all the rows in the table // excluding row "a" since it's deleted. numVals := mTest.checkQueryResponse(starQuery, afterDelete) // Check that there are no hidden KV values for row "a", // and column "i" for row "a" was deleted. mTest.checkTableSize(numVals) } // Check that a mutation can only be inserted with an explicit mutation state, and direction. tableDesc := desc.GetTable() tableDesc.Mutations = []csql.DescriptorMutation{{}} if err := tableDesc.Validate(); !testutils.IsError(err, "mutation in state UNKNOWN, direction NONE, and no column/index descriptor") { t.Fatal(err) } tableDesc.Mutations = []csql.DescriptorMutation{{Descriptor_: &csql.DescriptorMutation_Column{Column: &tableDesc.Columns[len(tableDesc.Columns)-1]}}} tableDesc.Columns = tableDesc.Columns[:len(tableDesc.Columns)-1] if err := tableDesc.Validate(); !testutils.IsError(err, "mutation in state UNKNOWN, direction NONE, col i, id 3") { t.Fatal(err) } tableDesc.Mutations[0].State = csql.DescriptorMutation_DELETE_ONLY if err := tableDesc.Validate(); !testutils.IsError(err, "mutation in state DELETE_ONLY, direction NONE, col i, id 3") { t.Fatal(err) } tableDesc.Mutations[0].State = csql.DescriptorMutation_UNKNOWN tableDesc.Mutations[0].Direction = csql.DescriptorMutation_DROP if err := tableDesc.Validate(); !testutils.IsError(err, "mutation in state UNKNOWN, direction DROP, col i, id 3") { t.Fatal(err) } }
"testing" "time" "github.com/cockroachdb/cockroach/client" "github.com/cockroachdb/cockroach/config" "github.com/cockroachdb/cockroach/gossip" "github.com/cockroachdb/cockroach/keys" "github.com/cockroachdb/cockroach/server" "github.com/cockroachdb/cockroach/sql" "github.com/cockroachdb/cockroach/util" "github.com/cockroachdb/cockroach/util/leaktest" "github.com/gogo/protobuf/proto" ) var configID = sql.ID(1) var configDescKey = sql.MakeDescMetadataKey(keys.MaxReservedDescID) // forceNewConfig forces a system config update by writing a bogus descriptor with an // incremented value inside. It then repeatedly fetches the gossip config until the // just-written descriptor is found. func forceNewConfig(t *testing.T, s *server.TestServer) (*config.SystemConfig, error) { configID++ configDesc := sql.DatabaseDescriptor{ Name: "sentinel", ID: configID, Privileges: &sql.PrivilegeDescriptor{}, } // This needs to be done in a transaction with the system trigger set. if err := s.DB().Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger()
func TestOperationsWithIndexMutation(t *testing.T) { defer leaktest.AfterTest(t) // The descriptor changes made must have an immediate effect. defer csql.TestDisableTableLeases()() // Disable external processing of mutations. defer csql.TestDisableAsyncSchemaChangeExec()() server, sqlDB, kvDB := setup(t) defer cleanup(server, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo (v)); `); err != nil { t.Fatal(err) } // read table descriptor nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test") gr, err := kvDB.Get(nameKey) if err != nil { t.Fatal(err) } if !gr.Exists() { t.Fatalf("Name entry %q does not exist", nameKey) } descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt())) desc := &csql.Descriptor{} if err := kvDB.GetProto(descKey, desc); err != nil { t.Fatal(err) } mTest := mutationTest{ T: t, kvDB: kvDB, sqlDB: sqlDB, descKey: descKey, desc: desc, } starQuery := `SELECT * FROM t.test` indexQuery := `SELECT * FROM t.test@foo` // See the effect of the operations depending on the state. for _, state := range []csql.DescriptorMutation_State{csql.DescriptorMutation_DELETE_ONLY, csql.DescriptorMutation_WRITE_ONLY} { // Init table with some entries. if _, err := sqlDB.Exec(`TRUNCATE TABLE t.test`); err != nil { t.Fatal(err) } initRows := [][]string{{"a", "z"}, {"b", "y"}} for _, row := range initRows { if _, err := sqlDB.Exec(`INSERT INTO t.test VALUES ($1, $2)`, row[0], row[1]); err != nil { t.Fatal(err) } } _ = mTest.checkQueryResponse(starQuery, initRows) // Index foo is visible. _ = mTest.checkQueryResponse(indexQuery, [][]string{{"y"}, {"z"}}) // Index foo is invisible once it's a mutation. mTest.writeIndexMutation("foo", csql.DescriptorMutation{State: state}) if _, err := sqlDB.Query(indexQuery); !testutils.IsError(err, `index "foo" not found`) { t.Fatal(err) } // Insert a new entry. if _, err := sqlDB.Exec(`INSERT INTO t.test VALUES ('c', 'x')`); err != nil { t.Fatal(err) } _ = mTest.checkQueryResponse(starQuery, [][]string{{"a", "z"}, {"b", "y"}, {"c", "x"}}) // Make index "foo" live so that we can read it. mTest.makeMutationsActive() if state == csql.DescriptorMutation_DELETE_ONLY { // "x" didn't get added to the index. _ = mTest.checkQueryResponse(indexQuery, [][]string{{"y"}, {"z"}}) } else { // "x" got added to the index. _ = mTest.checkQueryResponse(indexQuery, [][]string{{"x"}, {"y"}, {"z"}}) } // Make "foo" a mutation. mTest.writeIndexMutation("foo", csql.DescriptorMutation{State: state}) // Update. if _, err := sqlDB.Exec(`UPDATE t.test SET v = 'w' WHERE k = 'c'`); err != nil { t.Fatal(err) } // Update "v" to its current value "z" in row "a". if _, err := sqlDB.Exec(`UPDATE t.test SET v = 'z' WHERE k = 'a'`); err != nil { t.Fatal(err) } _ = mTest.checkQueryResponse(starQuery, [][]string{{"a", "z"}, {"b", "y"}, {"c", "w"}}) // Make index "foo" live so that we can read it. mTest.makeMutationsActive() if state == csql.DescriptorMutation_DELETE_ONLY { // updating "x" -> "w" is a noop on the index, // updating "z" -> "z" results in "z" being deleted from the index. _ = mTest.checkQueryResponse(indexQuery, [][]string{{"y"}, {"z"}}) } else { // updating "x" -> "w" results in the index updating from "x" -> "w", // updating "z" -> "z" is a noop on the index. _ = mTest.checkQueryResponse(indexQuery, [][]string{{"w"}, {"y"}, {"z"}}) } // Make "foo" a mutation. mTest.writeIndexMutation("foo", csql.DescriptorMutation{State: state}) // Delete row "b". if _, err := sqlDB.Exec(`DELETE FROM t.test WHERE k = 'b'`); err != nil { t.Fatal(err) } _ = mTest.checkQueryResponse(starQuery, [][]string{{"a", "z"}, {"c", "w"}}) // Make index "foo" live so that we can read it. mTest.makeMutationsActive() // Deleting row "b" deletes "y" from the index. if state == csql.DescriptorMutation_DELETE_ONLY { mTest.checkQueryResponse(indexQuery, [][]string{{"z"}}) } else { mTest.checkQueryResponse(indexQuery, [][]string{{"w"}, {"z"}}) } } // Check that a mutation can only be inserted with an explicit mutation state. tableDesc := desc.GetTable() tableDesc.Mutations = []csql.DescriptorMutation{{Descriptor_: &csql.DescriptorMutation_Index{Index: &tableDesc.Indexes[len(tableDesc.Indexes)-1]}}} tableDesc.Indexes = tableDesc.Indexes[:len(tableDesc.Indexes)-1] if err := tableDesc.Validate(); !testutils.IsError(err, "mutation in state UNKNOWN, direction NONE, index foo, id 2") { t.Fatal(err) } }
func TestSystemConfigGossip(t *testing.T) { defer leaktest.AfterTest(t)() s := StartTestServer(t) defer s.Stop() db := s.db key := sql.MakeDescMetadataKey(keys.MaxReservedDescID) valAt := func(i int) *sql.DatabaseDescriptor { return &sql.DatabaseDescriptor{Name: "foo", ID: sql.ID(i)} } // Register a callback for gossip updates. resultChan := s.Gossip().RegisterSystemConfigChannel() // The span gets gossiped when it first shows up. select { case <-resultChan: case <-time.After(500 * time.Millisecond): t.Fatal("did not receive gossip message") } // Try a plain KV write first. if err := db.Put(key, valAt(0)); err != nil { t.Fatal(err) } // Now do it as part of a transaction, but without the trigger set. if pErr := db.Txn(func(txn *client.Txn) *roachpb.Error { return txn.Put(key, valAt(1)) }); pErr != nil { t.Fatal(pErr) } // Gossip channel should be dormant. var systemConfig config.SystemConfig select { case <-resultChan: systemConfig = *s.gossip.GetSystemConfig() t.Fatalf("unexpected message received on gossip channel: %v", systemConfig) case <-time.After(50 * time.Millisecond): } // This time mark the transaction as having a Gossip trigger. if pErr := db.Txn(func(txn *client.Txn) *roachpb.Error { txn.SetSystemConfigTrigger() return txn.Put(key, valAt(2)) }); pErr != nil { t.Fatal(pErr) } // New system config received. select { case <-resultChan: systemConfig = *s.gossip.GetSystemConfig() case <-time.After(500 * time.Millisecond): t.Fatal("did not receive gossip message") } // Now check the new config. var val *roachpb.Value for _, kv := range systemConfig.Values { if bytes.Equal(key, kv.Key) { val = &kv.Value break } } if val == nil { t.Fatal("key not found in gossiped info") } // Make sure the returned value is valAt(2). got := new(sql.DatabaseDescriptor) if err := val.GetProto(got); err != nil { t.Fatal(err) } if expected := valAt(2); !reflect.DeepEqual(got, expected) { t.Fatalf("mismatch: expected %+v, got %+v", *expected, *got) } }
func TestDatabaseDescriptor(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) // The first `MaxReservedDescID` (plus 0) are set aside. expectedCounter := int64(sql.MaxReservedDescID + 1) // Test values before creating the database. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. nameKey := sql.MakeNameMetadataKey(sql.RootNamespaceID, "test") if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if gr.Exists() { t.Fatal("expected non-existing key") } // Write some junk that is going to interfere with table creation. dbDescKey := sql.MakeDescMetadataKey(sql.ID(expectedCounter)) if err := kvDB.CPut(dbDescKey, "foo", nil); err != nil { t.Fatal(err) } // Table creation should fail, and nothing should have been written. if _, err := sqlDB.Exec(`CREATE DATABASE test`); !testutils.IsError(err, "unexpected value") { t.Fatalf("unexpected error %s", err) } if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } if kvs, err := kvDB.Scan(keys.NameMetadataPrefix, keys.NameMetadataPrefix.PrefixEnd(), 0); err != nil { t.Fatal(err) } else { if a, e := len(kvs), 0; a != e { t.Fatalf("expected %d keys to have been written, found %d keys", e, a) } } // Remove the junk; allow table creation to proceed. if err := kvDB.Del(dbDescKey); err != nil { t.Fatal(err) } if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } expectedCounter++ // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(dbDescKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // Now try to create it again. We should fail, but not increment the counter. if _, err := sqlDB.Exec(`CREATE DATABASE test`); err == nil { t.Fatal("failure expected") } // Check keys again. // descriptor ID counter. if ir, err := kvDB.Get(keys.DescIDGenerator); err != nil { t.Fatal(err) } else if actual := ir.ValueInt(); actual != expectedCounter { t.Fatalf("expected descriptor ID == %d, got %d", expectedCounter, actual) } // Database name. if gr, err := kvDB.Get(nameKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } // database descriptor. if gr, err := kvDB.Get(dbDescKey); err != nil { t.Fatal(err) } else if !gr.Exists() { t.Fatal("key is missing") } }