// getCachedDatabaseDesc looks up the database descriptor given its name in the // descriptor cache. func (p *planner) getCachedDatabaseDesc(name string) (*sqlbase.DatabaseDescriptor, error) { if name == sqlbase.SystemDB.Name { return &sqlbase.SystemDB, nil } nameKey := databaseKey{name} nameVal := p.systemConfig.GetValue(nameKey.Key()) if nameVal == nil { return nil, fmt.Errorf("database %q does not exist in system cache", name) } id, err := nameVal.GetInt() if err != nil { return nil, err } descKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(id)) descVal := p.systemConfig.GetValue(descKey) if descVal == nil { return nil, fmt.Errorf("database %q has name entry, but no descriptor in system cache", name) } desc := &sqlbase.Descriptor{} if err := descVal.GetProto(desc); err != nil { return nil, err } database := desc.GetDatabase() if database == nil { return nil, util.Errorf("%q is not a database", name) } return database, database.Validate() }
// Convert all the mutations into live descriptors for the table // and write the updated table descriptor to the DB. func (mt mutationTest) makeMutationsActive() { // Remove mutation to check real values in DB using SQL if mt.tableDesc.Mutations == nil || len(mt.tableDesc.Mutations) == 0 { mt.Fatal("No mutations to make active") } for _, m := range mt.tableDesc.Mutations { if col := m.GetColumn(); col != nil { mt.tableDesc.Columns = append(mt.tableDesc.Columns, *col) } else if index := m.GetIndex(); index != nil { mt.tableDesc.Indexes = append(mt.tableDesc.Indexes, *index) } else { mt.Fatalf("no descriptor in mutation: %v", m) } } mt.tableDesc.Mutations = nil if err := mt.tableDesc.Validate(); err != nil { mt.Fatal(err) } if err := mt.kvDB.Put( sqlbase.MakeDescMetadataKey(mt.tableDesc.ID), sqlbase.WrapDescriptor(mt.tableDesc), ); err != nil { mt.Fatal(err) } }
// AcquireLease acquires a schema change lease on the table if // an unexpired lease doesn't exist. It returns the lease. func (sc *SchemaChanger) AcquireLease() (sqlbase.TableDescriptor_SchemaChangeLease, error) { var lease sqlbase.TableDescriptor_SchemaChangeLease err := sc.db.Txn(func(txn *client.Txn) error { txn.SetSystemConfigTrigger() tableDesc, err := getTableDescFromID(txn, sc.tableID) if err != nil { return err } // A second to deal with the time uncertainty across nodes. // It is perfectly valid for two or more goroutines to hold a valid // lease and execute a schema change in parallel, because schema // changes are executed using transactions that run sequentially. // This just reduces the probability of a write collision. expirationTimeUncertainty := time.Second if tableDesc.Lease != nil { if time.Unix(0, tableDesc.Lease.ExpirationTime).Add(expirationTimeUncertainty).After(timeutil.Now()) { return errExistingSchemaChangeLease } log.Infof("Overriding existing expired lease %v", tableDesc.Lease) } lease = sc.createSchemaChangeLease() tableDesc.Lease = &lease return txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc)) }) return lease, err }
func (p *planner) createDescriptorWithID( idKey roachpb.Key, id sqlbase.ID, descriptor sqlbase.DescriptorProto, ) (bool, error) { descriptor.SetID(id) // TODO(pmattis): The error currently returned below is likely going to be // difficult to interpret. // // TODO(pmattis): Need to handle if-not-exists here as well. // // TODO(pmattis): This is writing the namespace and descriptor table entries, // but not going through the normal INSERT logic and not performing a precise // mimicry. In particular, we're only writing a single key per table, while // perfect mimicry would involve writing a sentinel key for each row as well. descKey := sqlbase.MakeDescMetadataKey(descriptor.GetID()) b := &client.Batch{} descID := descriptor.GetID() descDesc := sqlbase.WrapDescriptor(descriptor) if log.V(2) { log.Infof(p.ctx(), "CPut %s -> %d", idKey, descID) log.Infof(p.ctx(), "CPut %s -> %s", descKey, descDesc) } b.CPut(idKey, descID, nil) b.CPut(descKey, descDesc, nil) p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, idKey, descID); err != nil { return err } return expectDescriptor(systemConfig, descKey, descDesc) }) return true, p.txn.Run(b) }
// writeTableDesc implements the SchemaAccessor interface. func (p *planner) writeTableDesc(tableDesc *sqlbase.TableDescriptor) error { if isVirtualDescriptor(tableDesc) { panic(fmt.Sprintf("Virtual Descriptors cannot be stored, found: %v", tableDesc)) } return p.txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.GetID()), sqlbase.WrapDescriptor(tableDesc)) }
// writeMutation writes the mutation to the table descriptor. If the // State or the Direction is undefined, these values are populated via // picking random values before the mutation is written. func (mt mutationTest) writeMutation(m sqlbase.DescriptorMutation) { if m.Direction == sqlbase.DescriptorMutation_NONE { // randomly pick ADD/DROP mutation if this is the first mutation, or // pick the direction already chosen for the first mutation. if len(mt.tableDesc.Mutations) > 0 { m.Direction = mt.tableDesc.Mutations[0].Direction } else { m.Direction = sqlbase.DescriptorMutation_DROP if rand.Intn(2) == 0 { m.Direction = sqlbase.DescriptorMutation_ADD } } } if m.State == sqlbase.DescriptorMutation_UNKNOWN { // randomly pick DELETE_ONLY/WRITE_ONLY state. r := rand.Intn(2) if r == 0 { m.State = sqlbase.DescriptorMutation_DELETE_ONLY } else { m.State = sqlbase.DescriptorMutation_WRITE_ONLY } } mt.tableDesc.Mutations = append(mt.tableDesc.Mutations, m) if err := mt.tableDesc.Validate(); err != nil { mt.Fatal(err) } if err := mt.kvDB.Put( sqlbase.MakeDescMetadataKey(mt.tableDesc.ID), sqlbase.WrapDescriptor(mt.tableDesc), ); err != nil { mt.Fatal(err) } }
// waitForOneVersion returns once there are no unexpired leases on the // previous version of the table descriptor. It returns the current version. // After returning there can only be versions of the descriptor >= to the // returned version. Lease acquisition (see acquire()) maintains the // invariant that no new leases for desc.Version-1 will be granted once // desc.Version exists. func (s LeaseStore) waitForOneVersion(tableID sqlbase.ID, retryOpts retry.Options) ( sqlbase.DescriptorVersion, error, ) { desc := &sqlbase.Descriptor{} descKey := sqlbase.MakeDescMetadataKey(tableID) var tableDesc *sqlbase.TableDescriptor for r := retry.Start(retryOpts); r.Next(); { // Get the current version of the table descriptor non-transactionally. // // TODO(pmattis): Do an inconsistent read here? if err := s.db.GetProto(descKey, desc); err != nil { return 0, err } tableDesc = desc.GetTable() if tableDesc == nil { return 0, errors.Errorf("ID %d is not a table", tableID) } // Check to see if there are any leases that still exist on the previous // version of the descriptor. now := s.clock.Now() count, err := s.countLeases(tableDesc.ID, tableDesc.Version-1, now.GoTime()) if err != nil { return 0, err } if count == 0 { break } log.Infof(context.TODO(), "publish (count leases): descID=%d name=%s version=%d count=%d", tableDesc.ID, tableDesc.Name, tableDesc.Version-1, count) } return tableDesc.Version, nil }
// GetZoneConfig returns the zone config for the object with 'id'. func GetZoneConfig(cfg config.SystemConfig, id uint32) (config.ZoneConfig, bool, error) { // Look in the zones table. if zoneVal := cfg.GetValue(sqlbase.MakeZoneKey(sqlbase.ID(id))); zoneVal != nil { var zone config.ZoneConfig // We're done. return zone, true, zoneVal.GetProto(&zone) } // No zone config for this ID. We need to figure out if it's a database // or table. Lookup its descriptor. if descVal := cfg.GetValue(sqlbase.MakeDescMetadataKey(sqlbase.ID(id))); descVal != nil { // Determine whether this is a database or table. var desc sqlbase.Descriptor if err := descVal.GetProto(&desc); err != nil { return config.ZoneConfig{}, false, err } if tableDesc := desc.GetTable(); tableDesc != nil { // This is a table descriptor. Lookup its parent database zone config. return GetZoneConfig(cfg, uint32(tableDesc.ParentID)) } } // Retrieve the default zone config, but only as long as that wasn't the ID // we were trying to retrieve (avoid infinite recursion). if id != keys.RootNamespaceID { return GetZoneConfig(cfg, keys.RootNamespaceID) } // No descriptor or not a table. return config.ZoneConfig{}, false, nil }
func getTableDescriptor(db *client.DB, database string, table string) *sqlbase.TableDescriptor { dbNameKey := sqlbase.MakeNameMetadataKey(keys.RootNamespaceID, database) gr, err := db.Get(dbNameKey) if err != nil { panic(err) } if !gr.Exists() { panic("database missing") } dbDescID := sqlbase.ID(gr.ValueInt()) tableNameKey := sqlbase.MakeNameMetadataKey(dbDescID, table) gr, err = db.Get(tableNameKey) if err != nil { panic(err) } if !gr.Exists() { panic("table missing") } descKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(gr.ValueInt())) desc := &sqlbase.Descriptor{} if err := db.GetProto(descKey, desc); err != nil { panic("proto missing") } return desc.GetTable() }
// RenameDatabase renames the database. // Privileges: security.RootUser user. // Notes: postgres requires superuser, db owner, or "CREATEDB". // mysql >= 5.1.23 does not allow database renames. func (p *planner) RenameDatabase(n *parser.RenameDatabase) (planNode, error) { if n.Name == "" || n.NewName == "" { return nil, errEmptyDatabaseName } if p.session.User != security.RootUser { return nil, fmt.Errorf("only %s is allowed to rename databases", security.RootUser) } dbDesc, err := p.getDatabaseDesc(string(n.Name)) if err != nil { return nil, err } if dbDesc == nil { return nil, databaseDoesNotExistError(string(n.Name)) } if n.Name == n.NewName { // Noop. return &emptyNode{}, nil } // Now update the nameMetadataKey and the descriptor. descKey := sqlbase.MakeDescMetadataKey(dbDesc.GetID()) dbDesc.SetName(string(n.NewName)) if err := dbDesc.Validate(); err != nil { return nil, err } newKey := databaseKey{string(n.NewName)}.Key() oldKey := databaseKey{string(n.Name)}.Key() descID := dbDesc.GetID() descDesc := sqlbase.WrapDescriptor(dbDesc) b := client.Batch{} b.CPut(newKey, descID, nil) b.Put(descKey, descDesc) b.Del(oldKey) if err := p.txn.Run(&b); err != nil { if _, ok := err.(*roachpb.ConditionFailedError); ok { return nil, fmt.Errorf("the new database name %q already exists", string(n.NewName)) } return nil, err } p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, newKey, descID); err != nil { return err } if err := expectDescriptor(systemConfig, descKey, descDesc); err != nil { return err } return expectDeleted(systemConfig, oldKey) }) return &emptyNode{}, nil }
// RenameIndex renames the index. // Privileges: CREATE on table. // notes: postgres requires CREATE on the table. // mysql requires ALTER, CREATE, INSERT on the table. func (p *planner) RenameIndex(n *parser.RenameIndex) (planNode, error) { tn, err := n.Index.Table.NormalizeWithDatabaseName(p.session.Database) if err != nil { return nil, err } tableDesc, err := p.mustGetTableDesc(tn) if err != nil { return nil, err } normIdxName := sqlbase.NormalizeName(n.Index.Index) status, i, err := tableDesc.FindIndexByNormalizedName(normIdxName) if err != nil { if n.IfExists { // Noop. return &emptyNode{}, nil } // Index does not exist, but we want it to: error out. return nil, err } if err := p.checkPrivilege(tableDesc, privilege.CREATE); err != nil { return nil, err } if n.NewName == "" { return nil, errEmptyIndexName } normNewIdxName := sqlbase.NormalizeName(n.NewName) if normIdxName == normNewIdxName { // Noop. return &emptyNode{}, nil } if _, _, err := tableDesc.FindIndexByNormalizedName(normNewIdxName); err == nil { return nil, fmt.Errorf("index name %q already exists", n.NewName) } if status == sqlbase.DescriptorActive { tableDesc.Indexes[i].Name = normNewIdxName } else { tableDesc.Mutations[i].GetIndex().Name = normNewIdxName } if err := tableDesc.SetUpVersion(); err != nil { return nil, err } descKey := sqlbase.MakeDescMetadataKey(tableDesc.GetID()) if err := tableDesc.Validate(p.txn); err != nil { return nil, err } if err := p.txn.Put(descKey, sqlbase.WrapDescriptor(tableDesc)); err != nil { return nil, err } p.notifySchemaChange(tableDesc.ID, sqlbase.InvalidMutationID) return &emptyNode{}, nil }
// getKeysForTableDescriptor retrieves the KV keys corresponding // to the zone, name and descriptor of a table. func getKeysForTableDescriptor( tableDesc *sqlbase.TableDescriptor, ) (zoneKey roachpb.Key, nameKey roachpb.Key, descKey roachpb.Key) { zoneKey = sqlbase.MakeZoneKey(tableDesc.ID) nameKey = sqlbase.MakeNameMetadataKey(tableDesc.ParentID, tableDesc.GetName()) descKey = sqlbase.MakeDescMetadataKey(tableDesc.ID) return }
func getKeysForDatabaseDescriptor( dbDesc *sqlbase.DatabaseDescriptor, ) (zoneKey roachpb.Key, nameKey roachpb.Key, descKey roachpb.Key) { zoneKey = sqlbase.MakeZoneKey(dbDesc.ID) nameKey = sqlbase.MakeNameMetadataKey(keys.RootNamespaceID, dbDesc.GetName()) descKey = sqlbase.MakeDescMetadataKey(dbDesc.ID) return }
// GetTableDesc returns the table descriptor for the table with 'id'. // Returns nil if the descriptor is not present, or is present but is not a // table. func GetTableDesc(cfg config.SystemConfig, id sqlbase.ID) (*sqlbase.TableDescriptor, error) { if descVal := cfg.GetValue(sqlbase.MakeDescMetadataKey(id)); descVal != nil { desc := &sqlbase.Descriptor{} if err := descVal.GetProto(desc); err != nil { return nil, err } return desc.GetTable(), nil } return nil, nil }
// createDescriptor implements the DescriptorAccessor interface. func (p *planner) createDescriptor(plainKey sqlbase.DescriptorKey, descriptor sqlbase.DescriptorProto, ifNotExists bool) (bool, error) { idKey := plainKey.Key() // Check whether idKey exists. gr, err := p.txn.Get(idKey) if err != nil { return false, err } if gr.Exists() { if ifNotExists { // Noop. return false, nil } // Key exists, but we don't want it to: error out. return false, fmt.Errorf("%s %q already exists", descriptor.TypeName(), plainKey.Name()) } // Increment unique descriptor counter. if ir, err := p.txn.Inc(keys.DescIDGenerator, 1); err == nil { descriptor.SetID(sqlbase.ID(ir.ValueInt() - 1)) } else { return false, err } // TODO(pmattis): The error currently returned below is likely going to be // difficult to interpret. // // TODO(pmattis): Need to handle if-not-exists here as well. // // TODO(pmattis): This is writing the namespace and descriptor table entries, // but not going through the normal INSERT logic and not performing a precise // mimicry. In particular, we're only writing a single key per table, while // perfect mimicry would involve writing a sentinel key for each row as well. descKey := sqlbase.MakeDescMetadataKey(descriptor.GetID()) b := client.Batch{} descID := descriptor.GetID() descDesc := sqlbase.WrapDescriptor(descriptor) if log.V(2) { log.Infof("CPut %s -> %d", idKey, descID) log.Infof("CPut %s -> %s", descKey, descDesc) } b.CPut(idKey, descID, nil) b.CPut(descKey, descDesc, nil) p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, idKey, descID); err != nil { return err } return expectDescriptor(systemConfig, descKey, descDesc) }) return true, p.txn.Run(&b) }
// ReleaseLease the table lease if it is the one registered with // the table descriptor. func (sc *SchemaChanger) ReleaseLease(lease sqlbase.TableDescriptor_SchemaChangeLease) error { err := sc.db.Txn(func(txn *client.Txn) error { tableDesc, err := sc.findTableWithLease(txn, lease) if err != nil { return err } tableDesc.Lease = nil txn.SetSystemConfigTrigger() return txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc)) }) return err }
// getTableDescFromID retrieves the table descriptor for the table // ID passed in using an existing txn. Teturns an error if the // descriptor doesn't exist or if it exists and is not a table. func getTableDescFromID(txn *client.Txn, id sqlbase.ID) (*sqlbase.TableDescriptor, error) { desc := &sqlbase.Descriptor{} descKey := sqlbase.MakeDescMetadataKey(id) if err := txn.GetProto(descKey, desc); err != nil { return nil, err } table := desc.GetTable() if table == nil { return nil, errDescriptorNotFound } return table, nil }
func isDeleted(tableID sqlbase.ID, cfg config.SystemConfig) bool { descKey := sqlbase.MakeDescMetadataKey(tableID) val := cfg.GetValue(descKey) if val == nil { return false } var descriptor sqlbase.Descriptor if err := val.GetProto(&descriptor); err != nil { panic("unable to unmarshal table descriptor") } table := descriptor.GetTable() return table.Deleted() }
func restoreTable( ctx context.Context, sst engine.RocksDBSstFileReader, txn *client.Txn, table *sqlbase.TableDescriptor, overwrite bool, ) error { log.Infof(ctx, "Restoring Table %q", table.Name) tableStartKey := roachpb.Key(sqlbase.MakeIndexKeyPrefix(table, table.PrimaryIndex.ID)) tableEndKey := tableStartKey.PrefixEnd() existingDesc, err := txn.Get(sqlbase.MakeDescMetadataKey(table.GetID())) if err != nil { return err } existingData, err := txn.Scan(tableStartKey, tableEndKey, 1) if err != nil { return err } if existingDesc.Value != nil || len(existingData) > 0 { if overwrite { // We're about to Put the descriptor, so don't bother deleting it. if err := txn.DelRange(tableStartKey, tableEndKey); err != nil { return err } } else { return errors.Errorf("table %q already exists", table.Name) } } tableDescKey := sqlbase.MakeDescMetadataKey(table.GetID()) if err := txn.Put(tableDescKey, sqlbase.WrapDescriptor(table)); err != nil { return err } return Import(ctx, sst, txn, engine.MVCCKey{Key: tableStartKey}, engine.MVCCKey{Key: tableEndKey}) }
// TestStoreRangeSplitAtTablePrefix verifies a range can be split at // UserTableDataMin and still gossip the SystemConfig properly. func TestStoreRangeSplitAtTablePrefix(t *testing.T) { defer leaktest.AfterTest(t)() sCtx := storage.TestStoreContext() sCtx.TestingKnobs.DisableSplitQueue = true store, stopper, _ := createTestStoreWithContext(t, sCtx) defer stopper.Stop() key := keys.MakeRowSentinelKey(append([]byte(nil), keys.UserTableDataMin...)) args := adminSplitArgs(key, key) if _, pErr := client.SendWrapped(rg1(store), nil, &args); pErr != nil { t.Fatalf("%q: split unexpected error: %s", key, pErr) } var desc sqlbase.TableDescriptor descBytes, err := protoutil.Marshal(&desc) 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 := sqlbase.MakeDescMetadataKey(sqlbase.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: } }
// ExtendLease for the current leaser. func (sc *SchemaChanger) ExtendLease( existingLease sqlbase.TableDescriptor_SchemaChangeLease, ) (sqlbase.TableDescriptor_SchemaChangeLease, error) { var lease sqlbase.TableDescriptor_SchemaChangeLease err := sc.db.Txn(func(txn *client.Txn) error { tableDesc, err := sc.findTableWithLease(txn, existingLease) if err != nil { return err } lease = sc.createSchemaChangeLease() tableDesc.Lease = &lease txn.SetSystemConfigTrigger() return txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc)) }) return lease, err }
func (p *planner) changePrivileges( targets parser.TargetList, grantees parser.NameList, changePrivilege func(*sqlbase.PrivilegeDescriptor, string), ) (planNode, error) { descriptors, err := p.getDescriptorsFromTargetList(targets) if err != nil { return nil, err } for _, descriptor := range descriptors { if err := p.checkPrivilege(descriptor, privilege.GRANT); err != nil { return nil, err } privileges := descriptor.GetPrivileges() for _, grantee := range grantees { changePrivilege(privileges, string(grantee)) } switch d := descriptor.(type) { case *sqlbase.DatabaseDescriptor: if err := d.Validate(); err != nil { return nil, err } case *sqlbase.TableDescriptor: if err := d.Validate(p.txn); err != nil { return nil, err } if err := d.SetUpVersion(); err != nil { return nil, err } p.notifySchemaChange(d.ID, sqlbase.InvalidMutationID) } } // Now update the descriptors transactionally. b := p.txn.NewBatch() for _, descriptor := range descriptors { descKey := sqlbase.MakeDescMetadataKey(descriptor.GetID()) b.Put(descKey, sqlbase.WrapDescriptor(descriptor)) } if err := p.txn.Run(b); err != nil { return nil, err } return &emptyNode{}, nil }
// isRenamed tests if a descriptor is updated by gossip to the specified name // and version. func isRenamed( tableID sqlbase.ID, expectedName string, expectedVersion sqlbase.DescriptorVersion, cfg config.SystemConfig, ) bool { descKey := sqlbase.MakeDescMetadataKey(tableID) val := cfg.GetValue(descKey) if val == nil { return false } var descriptor sqlbase.Descriptor if err := val.GetProto(&descriptor); err != nil { panic("unable to unmarshal table descriptor") } table := descriptor.GetTable() return table.Name == expectedName && table.Version == expectedVersion }
// getDescriptor implements the DescriptorAccessor interface. func (p *planner) getDescriptor(plainKey sqlbase.DescriptorKey, descriptor sqlbase.DescriptorProto, ) (bool, error) { gr, err := p.txn.Get(plainKey.Key()) if err != nil { return false, err } if !gr.Exists() { return false, nil } descKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(gr.ValueInt())) desc := &sqlbase.Descriptor{} if err := p.txn.GetProto(descKey, desc); err != nil { return false, err } switch t := descriptor.(type) { case *sqlbase.TableDescriptor: table := desc.GetTable() table.MaybeUpgradeFormatVersion() // TODO(dan): Write the upgraded TableDescriptor back to kv. This will break // the ability to use a previous version of cockroach with the on-disk data, // but it's worth it to avoid having to do the upgrade every time the // descriptor is fetched. Our current test for this enforces compatibility // backward and forward, so that'll have to be extended before this is done. if table == nil { return false, errors.Errorf("%q is not a table", plainKey.Name()) } if err := table.Validate(p.txn); err != nil { return false, err } *t = *table case *sqlbase.DatabaseDescriptor: database := desc.GetDatabase() if database == nil { return false, errors.Errorf("%q is not a database", plainKey.Name()) } if err := database.Validate(); err != nil { return false, err } *t = *database } return true, nil }
// renameDatabase implements the DatabaseAccessor interface. func (p *planner) renameDatabase(oldDesc *sqlbase.DatabaseDescriptor, newName string) error { onAlreadyExists := func() error { return fmt.Errorf("the new database name %q already exists", newName) } if isVirtualDatabase(newName) { return onAlreadyExists() } oldName := oldDesc.Name oldDesc.SetName(newName) if err := oldDesc.Validate(); err != nil { return err } oldKey := databaseKey{oldName}.Key() newKey := databaseKey{newName}.Key() descID := oldDesc.GetID() descKey := sqlbase.MakeDescMetadataKey(descID) descDesc := sqlbase.WrapDescriptor(oldDesc) b := &client.Batch{} b.CPut(newKey, descID, nil) b.Put(descKey, descDesc) b.Del(oldKey) if err := p.txn.Run(b); err != nil { if _, ok := err.(*roachpb.ConditionFailedError); ok { return onAlreadyExists() } return err } p.setTestingVerifyMetadata(func(systemConfig config.SystemConfig) error { if err := expectDescriptorID(systemConfig, newKey, descID); err != nil { return err } if err := expectDescriptor(systemConfig, descKey, descDesc); err != nil { return err } return expectDeleted(systemConfig, oldKey) }) return nil }
// TestAddingFKs checks the behavior of a table in the non-public `ADD` state. // Being non-public, it should not be visible to clients, and is therefore // assumed to be empty (e.g. by foreign key checks), since no one could have // written to it yet. func TestAddingFKs(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.products (id INT PRIMARY KEY); INSERT INTO t.products VALUES (1), (2); CREATE TABLE t.orders (id INT PRIMARY KEY, product INT REFERENCES t.products, INDEX (product)); `); err != nil { t.Fatal(err) } // Step the referencing table back to the ADD state. ordersDesc := sqlbase.GetTableDescriptor(kvDB, "t", "orders") ordersDesc.State = sqlbase.TableDescriptor_ADD ordersDesc.Version++ if err := kvDB.Put( sqlbase.MakeDescMetadataKey(ordersDesc.ID), sqlbase.WrapDescriptor(ordersDesc), ); err != nil { t.Fatal(err) } // Generally a referenced table needs to lookup referencing tables to check // FKs during delete operations, but referencing tables in the ADD state are // given special treatment. if _, err := sqlDB.Exec(`DELETE FROM t.products`); err != nil { t.Fatal(err) } // Client should not see the orders table. if _, err := sqlDB.Exec( `SELECT * FROM t.orders`, ); !testutils.IsError(err, "table is being added") { t.Fatal(err) } }
// ExtendLease for the current leaser. This needs to be called often while // doing a schema change to prevent more than one node attempting to apply a // schema change (which is still safe, but unwise). func (sc *SchemaChanger) ExtendLease( existingLease sqlbase.TableDescriptor_SchemaChangeLease, ) (sqlbase.TableDescriptor_SchemaChangeLease, error) { // Check if there is still time on this lease. minDesiredExpiration := timeutil.Now().Add(MinSchemaChangeLeaseDuration) if time.Unix(0, existingLease.ExpirationTime).After(minDesiredExpiration) { return existingLease, nil } // Update lease. var lease sqlbase.TableDescriptor_SchemaChangeLease err := sc.db.Txn(func(txn *client.Txn) error { tableDesc, err := sc.findTableWithLease(txn, existingLease) if err != nil { return err } lease = sc.createSchemaChangeLease() tableDesc.Lease = &lease txn.SetSystemConfigTrigger() return txn.Put(sqlbase.MakeDescMetadataKey(tableDesc.ID), sqlbase.WrapDescriptor(tableDesc)) }) return lease, err }
// getDescriptor implements the DescriptorAccessor interface. func (p *planner) getDescriptor(plainKey sqlbase.DescriptorKey, descriptor sqlbase.DescriptorProto, ) (bool, error) { gr, err := p.txn.Get(plainKey.Key()) if err != nil { return false, err } if !gr.Exists() { return false, nil } descKey := sqlbase.MakeDescMetadataKey(sqlbase.ID(gr.ValueInt())) desc := &sqlbase.Descriptor{} if err := p.txn.GetProto(descKey, desc); err != nil { return false, err } switch t := descriptor.(type) { case *sqlbase.TableDescriptor: table := desc.GetTable() if table == nil { return false, util.Errorf("%q is not a table", plainKey.Name()) } *t = *table case *sqlbase.DatabaseDescriptor: database := desc.GetDatabase() if database == nil { return false, util.Errorf("%q is not a database", plainKey.Name()) } *t = *database } if err := descriptor.Validate(); err != nil { return false, err } return true, nil }
// Publish updates a table descriptor. It also maintains the invariant that // there are at most two versions of the descriptor out in the wild at any time // by first waiting for all nodes to be on the current (pre-update) version of // the table desc. // The update closure is called after the wait, and it provides the new version // of the descriptor to be written. In a multi-step schema operation, this // update should perform a single step. // The closure may be called multiple times if retries occur; make sure it does // not have side effects. // Returns the updated version of the descriptor. func (s LeaseStore) Publish( tableID sqlbase.ID, update func(*sqlbase.TableDescriptor) error, logEvent func(*client.Txn) error, ) (*sqlbase.Descriptor, error) { errLeaseVersionChanged := errors.New("lease version changed") // Retry while getting errLeaseVersionChanged. for r := retry.Start(base.DefaultRetryOptions()); r.Next(); { // Wait until there are no unexpired leases on the previous version // of the table. expectedVersion, err := s.waitForOneVersion(tableID, base.DefaultRetryOptions()) if err != nil { return nil, err } desc := &sqlbase.Descriptor{} // There should be only one version of the descriptor, but it's // a race now to update to the next version. err = s.db.Txn(context.TODO(), func(txn *client.Txn) error { descKey := sqlbase.MakeDescMetadataKey(tableID) // Re-read the current version of the table descriptor, this time // transactionally. if err := txn.GetProto(descKey, desc); err != nil { return err } tableDesc := desc.GetTable() if tableDesc == nil { return errors.Errorf("ID %d is not a table", tableID) } if expectedVersion != tableDesc.Version { // The version changed out from under us. Someone else must be // performing a schema change operation. if log.V(3) { log.Infof(context.TODO(), "publish (version changed): %d != %d", expectedVersion, tableDesc.Version) } return errLeaseVersionChanged } // Run the update closure. if err := update(tableDesc); err != nil { return err } // Bump the version and modification time. tableDesc.Version++ now := s.clock.Now() tableDesc.ModificationTime = now if log.V(3) { log.Infof(context.TODO(), "publish: descID=%d (%s) version=%d mtime=%s", tableDesc.ID, tableDesc.Name, tableDesc.Version, now.GoTime()) } if err := tableDesc.ValidateTable(); err != nil { return err } // Write the updated descriptor. txn.SetSystemConfigTrigger() b := txn.NewBatch() b.Put(descKey, desc) if logEvent != nil { // If an event log is required for this update, ensure that the // descriptor change occurs first in the transaction. This is // necessary to ensure that the System configuration change is // gossiped. See the documentation for // transaction.SetSystemConfigTrigger() for more information. if err := txn.Run(b); err != nil { return err } if err := logEvent(txn); err != nil { return err } return txn.Commit() } // More efficient batching can be used if no event log message // is required. return txn.CommitInBatch(b) }) switch err { case nil, errDidntUpdateDescriptor: return desc, nil case errLeaseVersionChanged: // will loop around to retry default: return nil, err } } panic("not reached") }
func TestDatabaseDescriptor(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() 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 := sqlbase.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 := sqlbase.MakeDescMetadataKey(sqlbase.ID(expectedCounter)) dbDesc := &sqlbase.Descriptor{ Union: &sqlbase.Descriptor_Database{ Database: &sqlbase.DatabaseDescriptor{ Name: "sentinel", ID: sqlbase.ID(expectedCounter), Privileges: &sqlbase.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 %v", 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().SystemDescriptorCount(); 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") } }