github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/catalog/descs/collection.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 // Package descs provides abstractions for dealing with sets of descriptors. 12 // It is utilized during schema changes and by catalog.Accessor implementations. 13 package descs 14 15 import ( 16 "context" 17 "fmt" 18 "sort" 19 "strings" 20 "sync" 21 22 "github.com/cockroachdb/cockroach/pkg/keys" 23 "github.com/cockroachdb/cockroach/pkg/kv" 24 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 25 "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv" 26 "github.com/cockroachdb/cockroach/pkg/sql/catalog/database" 27 "github.com/cockroachdb/cockroach/pkg/sql/catalog/lease" 28 "github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver" 29 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 30 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 31 "github.com/cockroachdb/cockroach/pkg/util/log" 32 "github.com/cockroachdb/errors" 33 ) 34 35 // UncommittedDatabase is a database that has been created/dropped 36 // within the current transaction using the Collection. A rename 37 // is a drop of the old name and creation of the new name. 38 type UncommittedDatabase struct { 39 name string 40 id sqlbase.ID 41 dropped bool 42 } 43 44 // UncommittedTable is a table that has been created/dropped within the 45 // current transaction. 46 type UncommittedTable struct { 47 *sqlbase.MutableTableDescriptor 48 *sqlbase.ImmutableTableDescriptor 49 } 50 51 // MakeCollection constructs a Collection. 52 func MakeCollection( 53 leaseMgr *lease.Manager, 54 settings *cluster.Settings, 55 dbCache *database.Cache, 56 dbCacheSubscriber DatabaseCacheSubscriber, 57 ) Collection { 58 return Collection{ 59 leaseMgr: leaseMgr, 60 settings: settings, 61 databaseCache: dbCache, 62 dbCacheSubscriber: dbCacheSubscriber, 63 } 64 } 65 66 // NewCollection constructs a new *Collection. 67 func NewCollection(leaseMgr *lease.Manager, settings *cluster.Settings) *Collection { 68 tc := MakeCollection(leaseMgr, settings, nil, nil) 69 return &tc 70 } 71 72 // Collection is a collection of tables held by a single session that 73 // serves SQL requests, or a background job using a table descriptor. The 74 // collection is cleared using ReleaseAll() which is called at the 75 // end of each transaction on the session, or on hitting conditions such 76 // as errors, or retries that result in transaction timestamp changes. 77 type Collection struct { 78 // leaseMgr manages acquiring and releasing per-table leases. 79 leaseMgr *lease.Manager 80 // A collection of table descriptor valid for the timestamp. 81 // They are released once the transaction using them is complete. 82 // If the transaction gets pushed and the timestamp changes, 83 // the tables are released. 84 leasedTables []*sqlbase.ImmutableTableDescriptor 85 // Tables modified by the uncommitted transaction affiliated 86 // with this Collection. This allows a transaction to see 87 // its own modifications while bypassing the table lease mechanism. 88 // The table lease mechanism will have its own transaction to read 89 // the table and will hang waiting for the uncommitted changes to 90 // the table. These table descriptors are local to this 91 // Collection and invisible to other transactions. A dropped 92 // table is marked dropped. 93 uncommittedTables []UncommittedTable 94 95 // databaseCache is used as a cache for database names. 96 // This field is nil when the field is initialized for an internalPlanner. 97 // TODO(andrei): get rid of it and replace it with a leasing system for 98 // database descriptors. 99 databaseCache *database.Cache 100 101 // schemaCache maps {databaseID, schemaName} -> (schemaID, if exists, otherwise nil). 102 // TODO(sqlexec): replace with leasing system with custom schemas. 103 // This is currently never cleared, because there should only be unique schemas 104 // being added for each Collection as only temporary schemas can be 105 // made, and you cannot read from other schema caches. 106 schemaCache sync.Map 107 108 // DatabaseCacheSubscriber is used to block until the node's database cache has been 109 // updated when ReleaseAll is called. 110 dbCacheSubscriber DatabaseCacheSubscriber 111 112 // Same as uncommittedTables applying to databases modified within 113 // an uncommitted transaction. 114 uncommittedDatabases []UncommittedDatabase 115 116 // allDescriptors is a slice of all available descriptors. The descriptors 117 // are cached to avoid repeated lookups by users like virtual tables. The 118 // cache is purged whenever events would cause a scan of all descriptors to 119 // return different values, such as when the txn timestamp changes or when 120 // new descriptors are written in the txn. 121 allDescriptors []sqlbase.DescriptorProto 122 123 // allDatabaseDescriptors is a slice of all available database descriptors. 124 // These are purged at the same time as allDescriptors. 125 allDatabaseDescriptors []*sqlbase.DatabaseDescriptor 126 127 // allSchemasForDatabase maps databaseID -> schemaID -> schemaName. 128 // For each databaseID, all schemas visible under the database can be 129 // observed. 130 // These are purged at the same time as allDescriptors. 131 allSchemasForDatabase map[sqlbase.ID]map[sqlbase.ID]string 132 133 // settings are required to correctly resolve system.namespace accesses in 134 // mixed version (19.2/20.1) clusters. 135 // TODO(solon): This field could maybe be removed in 20.2. 136 settings *cluster.Settings 137 } 138 139 // isSupportedSchemaName returns whether this schema name is supported. 140 // TODO(sqlexec): this should be deleted when we use custom schemas. 141 // However, this introduces an extra lookup for cases where `<database>.<table>` 142 // is looked up. 143 // See #44733. 144 func isSupportedSchemaName(n tree.Name) bool { 145 return n == tree.PublicSchemaName || strings.HasPrefix(string(n), "pg_temp") 146 } 147 148 // GetMutableTableDescriptor returns a mutable table descriptor. 149 // 150 // If flags.required is false, GetMutableTableDescriptor() will gracefully 151 // return a nil descriptor and no error if the table does not exist. 152 // 153 func (tc *Collection) GetMutableTableDescriptor( 154 ctx context.Context, txn *kv.Txn, tn *tree.TableName, flags tree.ObjectLookupFlags, 155 ) (*sqlbase.MutableTableDescriptor, error) { 156 if log.V(2) { 157 log.Infof(ctx, "reading mutable descriptor on table '%s'", tn) 158 } 159 160 if !isSupportedSchemaName(tn.SchemaName) { 161 return nil, nil 162 } 163 164 refuseFurtherLookup, dbID, err := tc.GetUncommittedDatabaseID(tn.Catalog(), flags.Required) 165 if refuseFurtherLookup || err != nil { 166 return nil, err 167 } 168 169 if dbID == sqlbase.InvalidID && tc.DatabaseCache() != nil { 170 // Resolve the database from the database cache when the transaction 171 // hasn't modified the database. 172 dbID, err = tc.DatabaseCache().GetDatabaseID(ctx, tc.leaseMgr.DB().Txn, tn.Catalog(), flags.Required) 173 if err != nil || dbID == sqlbase.InvalidID { 174 // dbID can still be invalid if required is false and the database is not found. 175 return nil, err 176 } 177 } 178 179 // The following checks only work if the dbID is not invalid. 180 if dbID != sqlbase.InvalidID { 181 // Resolve the schema to the ID of the schema. 182 foundSchema, schemaID, err := tc.ResolveSchemaID(ctx, txn, dbID, tn.Schema()) 183 if err != nil || !foundSchema { 184 return nil, err 185 } 186 187 if refuseFurtherLookup, table, err := tc.getUncommittedTable( 188 dbID, 189 schemaID, 190 tn, 191 flags.Required, 192 ); refuseFurtherLookup || err != nil { 193 return nil, err 194 } else if mut := table.MutableTableDescriptor; mut != nil { 195 log.VEventf(ctx, 2, "found uncommitted table %d", mut.ID) 196 return mut, nil 197 } 198 } 199 200 phyAccessor := catalogkv.UncachedPhysicalAccessor{} 201 obj, err := phyAccessor.GetObjectDesc( 202 ctx, 203 txn, 204 tc.settings, 205 tc.codec(), 206 tn.Catalog(), 207 tn.Schema(), 208 tn.Table(), 209 flags, 210 ) 211 if obj == nil { 212 return nil, err 213 } 214 mutDesc, ok := obj.(*sqlbase.MutableTableDescriptor) 215 if !ok { 216 return nil, err 217 } 218 return mutDesc, nil 219 } 220 221 // ResolveSchemaID attempts to lookup the schema from the schemaCache if it exists, 222 // otherwise falling back to a database lookup. 223 func (tc *Collection) ResolveSchemaID( 224 ctx context.Context, txn *kv.Txn, dbID sqlbase.ID, schemaName string, 225 ) (bool, sqlbase.ID, error) { 226 // Fast path public schema, as it is always found. 227 if schemaName == tree.PublicSchema { 228 return true, keys.PublicSchemaID, nil 229 } 230 231 type schemaCacheKey struct { 232 dbID sqlbase.ID 233 schemaName string 234 } 235 236 key := schemaCacheKey{dbID: dbID, schemaName: schemaName} 237 // First lookup the cache. 238 if val, ok := tc.schemaCache.Load(key); ok { 239 return true, val.(sqlbase.ID), nil 240 } 241 242 // Next, try lookup the result from KV, storing and returning the value. 243 exists, schemaID, err := catalogkv.ResolveSchemaID(ctx, txn, tc.codec(), dbID, schemaName) 244 if err != nil || !exists { 245 return exists, schemaID, err 246 } 247 tc.schemaCache.Store(key, schemaID) 248 return exists, schemaID, err 249 } 250 251 // GetTableVersion returns a table descriptor with a version suitable for 252 // the transaction: table.ModificationTime <= txn.Timestamp < expirationTime. 253 // The table must be released by calling tc.ReleaseAll(). 254 // 255 // If flags.required is false, GetTableVersion() will gracefully 256 // return a nil descriptor and no error if the table does not exist. 257 // 258 // It might also add a transaction deadline to the transaction that is 259 // enforced at the KV layer to ensure that the transaction doesn't violate 260 // the validity window of the table descriptor version returned. 261 // 262 func (tc *Collection) GetTableVersion( 263 ctx context.Context, txn *kv.Txn, tn *tree.TableName, flags tree.ObjectLookupFlags, 264 ) (*sqlbase.ImmutableTableDescriptor, error) { 265 if log.V(2) { 266 log.Infof(ctx, "planner acquiring lease on table '%s'", tn) 267 } 268 269 if !isSupportedSchemaName(tn.SchemaName) { 270 return nil, nil 271 } 272 273 readTableFromStore := func() (*sqlbase.ImmutableTableDescriptor, error) { 274 phyAccessor := catalogkv.UncachedPhysicalAccessor{} 275 obj, err := phyAccessor.GetObjectDesc( 276 ctx, 277 txn, 278 tc.settings, 279 tc.codec(), 280 tn.Catalog(), 281 tn.Schema(), 282 tn.Table(), 283 flags, 284 ) 285 if obj == nil { 286 return nil, err 287 } 288 tbl, ok := obj.(*sqlbase.ImmutableTableDescriptor) 289 if !ok { 290 return nil, err 291 } 292 return tbl, err 293 } 294 295 refuseFurtherLookup, dbID, err := tc.GetUncommittedDatabaseID(tn.Catalog(), flags.Required) 296 if refuseFurtherLookup || err != nil { 297 return nil, err 298 } 299 300 if dbID == sqlbase.InvalidID && tc.DatabaseCache() != nil { 301 // Resolve the database from the database cache when the transaction 302 // hasn't modified the database. 303 dbID, err = tc.DatabaseCache().GetDatabaseID(ctx, tc.leaseMgr.DB().Txn, tn.Catalog(), flags.Required) 304 if err != nil || dbID == sqlbase.InvalidID { 305 // dbID can still be invalid if required is false and the database is not found. 306 return nil, err 307 } 308 } 309 310 // If at this point we have an InvalidID, we should immediately try read from store. 311 if dbID == sqlbase.InvalidID { 312 return readTableFromStore() 313 } 314 315 // Resolve the schema to the ID of the schema. 316 foundSchema, schemaID, err := tc.ResolveSchemaID(ctx, txn, dbID, tn.Schema()) 317 if err != nil || !foundSchema { 318 return nil, err 319 } 320 321 // TODO(vivek): Ideally we'd avoid caching for only the 322 // system.descriptor and system.lease tables, because they are 323 // used for acquiring leases, creating a chicken&egg problem. 324 // But doing so turned problematic and the tests pass only by also 325 // disabling caching of system.eventlog, system.rangelog, and 326 // system.users. For now we're sticking to disabling caching of 327 // all system descriptors except the role-members-table. 328 avoidCache := flags.AvoidCached || lease.TestingTableLeasesAreDisabled() || 329 (tn.Catalog() == sqlbase.SystemDB.Name && tn.ObjectName.String() != sqlbase.RoleMembersTable.Name) 330 331 if refuseFurtherLookup, table, err := tc.getUncommittedTable( 332 dbID, 333 schemaID, 334 tn, 335 flags.Required, 336 ); refuseFurtherLookup || err != nil { 337 return nil, err 338 } else if immut := table.ImmutableTableDescriptor; immut != nil { 339 // If not forcing to resolve using KV, tables being added aren't visible. 340 if immut.Adding() && !avoidCache { 341 if !flags.Required { 342 return nil, nil 343 } 344 return nil, sqlbase.FilterTableState(immut.TableDesc()) 345 } 346 347 log.VEventf(ctx, 2, "found uncommitted table %d", immut.ID) 348 return immut, nil 349 } 350 351 if avoidCache { 352 return readTableFromStore() 353 } 354 355 // First, look to see if we already have the table. 356 // This ensures that, once a SQL transaction resolved name N to id X, it will 357 // continue to use N to refer to X even if N is renamed during the 358 // transaction. 359 for _, table := range tc.leasedTables { 360 if lease.NameMatchesTable(&table.TableDescriptor, dbID, schemaID, tn.Table()) { 361 log.VEventf(ctx, 2, "found table in table collection for table '%s'", tn) 362 return table, nil 363 } 364 } 365 366 readTimestamp := txn.ReadTimestamp() 367 table, expiration, err := tc.leaseMgr.AcquireByName(ctx, readTimestamp, dbID, schemaID, tn.Table()) 368 if err != nil { 369 // Read the descriptor from the store in the face of some specific errors 370 // because of a known limitation of AcquireByName. See the known 371 // limitations of AcquireByName for details. 372 if sqlbase.HasInactiveTableError(err) || 373 errors.Is(err, sqlbase.ErrDescriptorNotFound) { 374 return readTableFromStore() 375 } 376 // Lease acquisition failed with some other error. This we don't 377 // know how to deal with, so propagate the error. 378 return nil, err 379 } 380 381 if expiration.LessEq(readTimestamp) { 382 log.Fatalf(ctx, "bad table for T=%s, expiration=%s", readTimestamp, expiration) 383 } 384 385 tc.leasedTables = append(tc.leasedTables, table) 386 log.VEventf(ctx, 2, "added table '%s' to table collection", tn) 387 388 // If the table we just acquired expires before the txn's deadline, reduce 389 // the deadline. We use ReadTimestamp() that doesn't return the commit timestamp, 390 // so we need to set a deadline on the transaction to prevent it from committing 391 // beyond the table version expiration time. 392 txn.UpdateDeadlineMaybe(ctx, expiration) 393 return table, nil 394 } 395 396 // GetTableVersionByID is a by-ID variant of GetTableVersion (i.e. uses same cache). 397 func (tc *Collection) GetTableVersionByID( 398 ctx context.Context, txn *kv.Txn, tableID sqlbase.ID, flags tree.ObjectLookupFlags, 399 ) (*sqlbase.ImmutableTableDescriptor, error) { 400 log.VEventf(ctx, 2, "planner getting table on table ID %d", tableID) 401 402 if flags.AvoidCached || lease.TestingTableLeasesAreDisabled() { 403 table, err := sqlbase.GetTableDescFromID(ctx, txn, tc.codec(), tableID) 404 if err != nil { 405 return nil, err 406 } 407 if err := sqlbase.FilterTableState(table); err != nil { 408 return nil, err 409 } 410 return sqlbase.NewImmutableTableDescriptor(*table), nil 411 } 412 413 for _, table := range tc.uncommittedTables { 414 if immut := table.ImmutableTableDescriptor; immut.ID == tableID { 415 log.VEventf(ctx, 2, "found uncommitted table %d", tableID) 416 if immut.Dropped() { 417 return nil, sqlbase.NewUndefinedRelationError( 418 tree.NewUnqualifiedTableName(tree.Name(fmt.Sprintf("<id=%d>", tableID))), 419 ) 420 } 421 return immut, nil 422 } 423 } 424 425 // First, look to see if we already have the table -- including those 426 // via `GetTableVersion`. 427 for _, table := range tc.leasedTables { 428 if table.ID == tableID { 429 log.VEventf(ctx, 2, "found table %d in table cache", tableID) 430 return table, nil 431 } 432 } 433 434 readTimestamp := txn.ReadTimestamp() 435 table, expiration, err := tc.leaseMgr.Acquire(ctx, readTimestamp, tableID) 436 if err != nil { 437 if errors.Is(err, sqlbase.ErrDescriptorNotFound) { 438 // Transform the descriptor error into an error that references the 439 // table's ID. 440 return nil, sqlbase.NewUndefinedRelationError( 441 &tree.TableRef{TableID: int64(tableID)}) 442 } 443 return nil, err 444 } 445 446 if expiration.LessEq(readTimestamp) { 447 log.Fatalf(ctx, "bad table for T=%s, expiration=%s", readTimestamp, expiration) 448 } 449 450 tc.leasedTables = append(tc.leasedTables, table) 451 log.VEventf(ctx, 2, "added table '%s' to table collection", table.Name) 452 453 // If the table we just acquired expires before the txn's deadline, reduce 454 // the deadline. We use ReadTimestamp() that doesn't return the commit timestamp, 455 // so we need to set a deadline on the transaction to prevent it from committing 456 // beyond the table version expiration time. 457 txn.UpdateDeadlineMaybe(ctx, expiration) 458 return table, nil 459 } 460 461 // GetMutableTableVersionByID is a variant of sqlbase.GetTableDescFromID which returns a mutable 462 // table descriptor of the table modified in the same transaction. 463 func (tc *Collection) GetMutableTableVersionByID( 464 ctx context.Context, tableID sqlbase.ID, txn *kv.Txn, 465 ) (*sqlbase.MutableTableDescriptor, error) { 466 log.VEventf(ctx, 2, "planner getting mutable table on table ID %d", tableID) 467 468 if table := tc.GetUncommittedTableByID(tableID).MutableTableDescriptor; table != nil { 469 log.VEventf(ctx, 2, "found uncommitted table %d", tableID) 470 return table, nil 471 } 472 return sqlbase.GetMutableTableDescFromID(ctx, txn, tc.codec(), tableID) 473 } 474 475 // ReleaseTableLeases releases the leases for the tables with ids in 476 // the passed slice. Errors are logged but ignored. 477 func (tc *Collection) ReleaseTableLeases(ctx context.Context, tables []lease.IDVersion) { 478 // Sort the tables and leases to make it easy to find the leases to release. 479 leasedTables := tc.leasedTables 480 sort.Slice(tables, func(i, j int) bool { 481 return tables[i].ID < tables[j].ID 482 }) 483 sort.Slice(leasedTables, func(i, j int) bool { 484 return leasedTables[i].ID < leasedTables[j].ID 485 }) 486 487 filteredLeases := leasedTables[:0] // will store the remaining leases 488 tablesToConsider := tables 489 shouldRelease := func(id sqlbase.ID) (found bool) { 490 for len(tablesToConsider) > 0 && tablesToConsider[0].ID < id { 491 tablesToConsider = tablesToConsider[1:] 492 } 493 return len(tablesToConsider) > 0 && tablesToConsider[0].ID == id 494 } 495 for _, l := range leasedTables { 496 if !shouldRelease(l.ID) { 497 filteredLeases = append(filteredLeases, l) 498 } else if err := tc.leaseMgr.Release(l); err != nil { 499 log.Warningf(ctx, "%v", err) 500 } 501 } 502 tc.leasedTables = filteredLeases 503 } 504 505 // ReleaseLeases releases the leases for the tables with ids in 506 // the passed slice. Errors are logged but ignored. 507 func (tc *Collection) ReleaseLeases(ctx context.Context) { 508 if len(tc.leasedTables) > 0 { 509 log.VEventf(ctx, 2, "releasing %d tables", len(tc.leasedTables)) 510 for _, table := range tc.leasedTables { 511 if err := tc.leaseMgr.Release(table); err != nil { 512 log.Warningf(ctx, "%v", err) 513 } 514 } 515 tc.leasedTables = tc.leasedTables[:0] 516 } 517 } 518 519 // ReleaseAll releases all state currently held by the Collection. 520 // ReleaseAll calls ReleaseLeases. 521 func (tc *Collection) ReleaseAll(ctx context.Context) { 522 tc.ReleaseLeases(ctx) 523 tc.uncommittedTables = nil 524 tc.uncommittedDatabases = nil 525 tc.releaseAllDescriptors() 526 } 527 528 // WaitForCacheToDropDatabases waits until the database cache has been updated 529 // to properly reflect all dropped databases, so that future commands on the 530 // same gateway node observe the dropped databases. 531 func (tc *Collection) WaitForCacheToDropDatabases(ctx context.Context) { 532 for _, uc := range tc.uncommittedDatabases { 533 if !uc.dropped { 534 continue 535 } 536 // Wait until the database cache has been updated to properly 537 // reflect a dropped database, so that future commands on the 538 // same gateway node observe the dropped database. 539 tc.dbCacheSubscriber.WaitForCacheState( 540 func(dc *database.Cache) bool { 541 // Resolve the database name from the database cache. 542 dbID, err := dc.GetCachedDatabaseID(uc.name) 543 if err != nil || dbID == sqlbase.InvalidID { 544 // dbID can still be 0 if required is false and 545 // the database is not found. Swallowing error here 546 // because it was felt there was no value in returning 547 // it to a higher layer only to be swallow there. This 548 // entire codepath is only called from one place so 549 // it's better to swallow it here. 550 return true 551 } 552 553 // If the database name still exists but it now references another 554 // db with a more recent id, we're good - it means that the database 555 // name has been reused. 556 return dbID > uc.id 557 }) 558 } 559 } 560 561 // HasUncommittedTables returns true if the Collection contains uncommitted 562 // tables. 563 func (tc *Collection) HasUncommittedTables() bool { 564 return len(tc.uncommittedTables) > 0 565 } 566 567 // AddUncommittedTable adds desc to the Collection. 568 func (tc *Collection) AddUncommittedTable(desc sqlbase.MutableTableDescriptor) error { 569 if desc.Version != desc.ClusterVersion.Version+1 { 570 return errors.Errorf( 571 "descriptor version %d not incremented from cluster version %d", 572 desc.Version, desc.ClusterVersion.Version) 573 } 574 tbl := UncommittedTable{ 575 MutableTableDescriptor: &desc, 576 ImmutableTableDescriptor: sqlbase.NewImmutableTableDescriptor(desc.TableDescriptor), 577 } 578 for i, table := range tc.uncommittedTables { 579 if table.MutableTableDescriptor.ID == desc.ID { 580 tc.uncommittedTables[i] = tbl 581 return nil 582 } 583 } 584 tc.uncommittedTables = append(tc.uncommittedTables, tbl) 585 tc.releaseAllDescriptors() 586 return nil 587 } 588 589 // GetTablesWithNewVersion returns all the idVersion pairs that have undergone a 590 // schema change. Returns nil for no schema changes. The version returned for 591 // each schema change is ClusterVersion - 1, because that's the one that will be 592 // used when checking for table descriptor two version invariance. 593 // Also returns strings representing the new <name, version> pairs 594 func (tc *Collection) GetTablesWithNewVersion() []lease.IDVersion { 595 var tables []lease.IDVersion 596 for _, table := range tc.uncommittedTables { 597 if mut := table.MutableTableDescriptor; !mut.IsNewTable() { 598 tables = append(tables, lease.NewIDVersionPrev(&mut.ClusterVersion)) 599 } 600 } 601 return tables 602 } 603 604 // GetTableDescsWithNewVersion is like GetTablesWithNewVersion but returns descriptors. 605 func (tc *Collection) GetTableDescsWithNewVersion() ( 606 newTables []*sqlbase.ImmutableTableDescriptor, 607 ) { 608 for _, table := range tc.uncommittedTables { 609 if mut := table.MutableTableDescriptor; mut.IsNewTable() { 610 newTables = append(newTables, table.ImmutableTableDescriptor) 611 } 612 } 613 return newTables 614 } 615 616 // DBAction is an operation to an uncommitted database. 617 type DBAction bool 618 619 const ( 620 // DBCreated notes that the database has been created. 621 DBCreated DBAction = false 622 // DBDropped notes that the database has been dropped. 623 DBDropped DBAction = true 624 ) 625 626 // AddUncommittedDatabase stages the database action for the relevant database. 627 func (tc *Collection) AddUncommittedDatabase(name string, id sqlbase.ID, action DBAction) { 628 db := UncommittedDatabase{name: name, id: id, dropped: action == DBDropped} 629 tc.uncommittedDatabases = append(tc.uncommittedDatabases, db) 630 tc.releaseAllDescriptors() 631 } 632 633 // GetUncommittedDatabaseID returns a database ID for the requested tablename 634 // if the requested tablename is for a database modified within the transaction 635 // affiliated with the LeaseCollection. 636 func (tc *Collection) GetUncommittedDatabaseID( 637 requestedDbName string, required bool, 638 ) (c bool, res sqlbase.ID, err error) { 639 // Walk latest to earliest so that a DROP DATABASE followed by a 640 // CREATE DATABASE with the same name will result in the CREATE DATABASE 641 // being seen. 642 for i := len(tc.uncommittedDatabases) - 1; i >= 0; i-- { 643 db := tc.uncommittedDatabases[i] 644 if requestedDbName == db.name { 645 if db.dropped { 646 if required { 647 return true, sqlbase.InvalidID, sqlbase.NewUndefinedDatabaseError(requestedDbName) 648 } 649 return true, sqlbase.InvalidID, nil 650 } 651 return false, db.id, nil 652 } 653 } 654 return false, sqlbase.InvalidID, nil 655 } 656 657 // getUncommittedTable returns a table for the requested tablename 658 // if the requested tablename is for a table modified within the transaction 659 // affiliated with the LeaseCollection. 660 // 661 // The first return value "refuseFurtherLookup" is true when there is 662 // a known deletion of that table, so it would be invalid to miss the 663 // cache and go to KV (where the descriptor prior to the DROP may 664 // still exist). 665 func (tc *Collection) getUncommittedTable( 666 dbID sqlbase.ID, schemaID sqlbase.ID, tn *tree.TableName, required bool, 667 ) (refuseFurtherLookup bool, table UncommittedTable, err error) { 668 // Walk latest to earliest so that a DROP TABLE followed by a CREATE TABLE 669 // with the same name will result in the CREATE TABLE being seen. 670 for i := len(tc.uncommittedTables) - 1; i >= 0; i-- { 671 table := tc.uncommittedTables[i] 672 mutTbl := table.MutableTableDescriptor 673 // If a table has gotten renamed we'd like to disallow using the old names. 674 // The renames could have happened in another transaction but it's still okay 675 // to disallow the use of the old name in this transaction because the other 676 // transaction has already committed and this transaction is seeing the 677 // effect of it. 678 for _, drain := range mutTbl.DrainingNames { 679 if drain.Name == string(tn.ObjectName) && 680 drain.ParentID == dbID && 681 drain.ParentSchemaID == schemaID { 682 // Table name has gone away. 683 if required { 684 // If it's required here, say it doesn't exist. 685 err = sqlbase.NewUndefinedRelationError(tn) 686 } 687 // The table collection knows better; the caller has to avoid 688 // going to KV in any case: refuseFurtherLookup = true 689 return true, UncommittedTable{}, err 690 } 691 } 692 693 // Do we know about a table with this name? 694 if lease.NameMatchesTable( 695 &mutTbl.TableDescriptor, 696 dbID, 697 schemaID, 698 tn.Table(), 699 ) { 700 // Right state? 701 if err = sqlbase.FilterTableState(mutTbl.TableDesc()); err != nil && !sqlbase.HasAddingTableError(err) { 702 if !required { 703 // If it's not required here, we simply say we don't have it. 704 err = nil 705 } 706 // The table collection knows better; the caller has to avoid 707 // going to KV in any case: refuseFurtherLookup = true 708 return true, UncommittedTable{}, err 709 } 710 711 // Got a table. 712 return false, table, nil 713 } 714 } 715 return false, UncommittedTable{}, nil 716 } 717 718 // GetUncommittedTableByID returns an uncommitted table by its ID. 719 func (tc *Collection) GetUncommittedTableByID(id sqlbase.ID) UncommittedTable { 720 // Walk latest to earliest so that a DROP TABLE followed by a CREATE TABLE 721 // with the same name will result in the CREATE TABLE being seen. 722 for i := len(tc.uncommittedTables) - 1; i >= 0; i-- { 723 table := tc.uncommittedTables[i] 724 if table.MutableTableDescriptor.ID == id { 725 return table 726 } 727 } 728 return UncommittedTable{} 729 } 730 731 // GetAllDescriptors returns all descriptors visible by the transaction, 732 // first checking the Collection's cached descriptors for validity 733 // before defaulting to a key-value scan, if necessary. 734 func (tc *Collection) GetAllDescriptors( 735 ctx context.Context, txn *kv.Txn, 736 ) ([]sqlbase.DescriptorProto, error) { 737 if tc.allDescriptors == nil { 738 descs, err := catalogkv.GetAllDescriptors(ctx, txn, tc.codec()) 739 if err != nil { 740 return nil, err 741 } 742 743 // There could be tables with user defined types that need hydrating, 744 // so collect the needed information to set up metadata in those types. 745 dbDescs := make(map[sqlbase.ID]*sqlbase.DatabaseDescriptor) 746 typDescs := make(map[sqlbase.ID]*sqlbase.TypeDescriptor) 747 for i := range descs { 748 desc := descs[i] 749 switch t := desc.(type) { 750 case *sqlbase.DatabaseDescriptor: 751 dbDescs[t.ID] = t 752 case *sqlbase.TypeDescriptor: 753 typDescs[t.ID] = t 754 } 755 } 756 // If we found any type descriptors, that means that some of the tables we 757 // scanned might have types that need hydrating. 758 if len(typDescs) > 0 { 759 // Since we just scanned all the descriptors, we already have everything 760 // we need to hydrate our types. Set up an accessor for the type hydration 761 // method to look into the scanned set of descriptors. 762 typeLookup := func(id sqlbase.ID) (*tree.TypeName, *sqlbase.TypeDescriptor, error) { 763 typDesc := typDescs[id] 764 dbDesc := dbDescs[typDesc.ParentID] 765 schemaName, err := resolver.ResolveSchemaNameByID(ctx, txn, tc.codec(), dbDesc.ID, typDesc.ParentSchemaID) 766 if err != nil { 767 return nil, nil, err 768 } 769 name := tree.MakeNewQualifiedTypeName(dbDesc.Name, schemaName, typDesc.Name) 770 return &name, typDesc, nil 771 } 772 // Now hydrate all table descriptors. 773 for i := range descs { 774 desc := descs[i] 775 if tbl, ok := desc.(*sqlbase.TableDescriptor); ok { 776 if err := sqlbase.HydrateTypesInTableDescriptor(tbl, typeLookup); err != nil { 777 // If we ran into an error hydrating the types, that means that we 778 // have some sort of corrupted descriptor state. Rather than disable 779 // uses of GetAllDescriptors, just log the error. 780 log.Errorf(ctx, "%s", err.Error()) 781 } 782 } 783 } 784 } 785 786 tc.allDescriptors = descs 787 } 788 return tc.allDescriptors, nil 789 } 790 791 // GetAllDatabaseDescriptors returns all database descriptors visible by the 792 // transaction, first checking the Collection's cached descriptors for 793 // validity before scanning system.namespace and looking up the descriptors 794 // in the database cache, if necessary. 795 func (tc *Collection) GetAllDatabaseDescriptors( 796 ctx context.Context, txn *kv.Txn, 797 ) ([]*sqlbase.DatabaseDescriptor, error) { 798 if tc.allDatabaseDescriptors == nil { 799 dbDescIDs, err := catalogkv.GetAllDatabaseDescriptorIDs(ctx, txn, tc.codec()) 800 if err != nil { 801 return nil, err 802 } 803 dbDescs, err := catalogkv.GetDatabaseDescriptorsFromIDs(ctx, txn, tc.codec(), dbDescIDs) 804 if err != nil { 805 return nil, err 806 } 807 tc.allDatabaseDescriptors = dbDescs 808 } 809 return tc.allDatabaseDescriptors, nil 810 } 811 812 // GetSchemasForDatabase returns the schemas for a given database 813 // visible by the transaction. This uses the schema cache locally 814 // if possible, or else performs a scan on kv. 815 func (tc *Collection) GetSchemasForDatabase( 816 ctx context.Context, txn *kv.Txn, dbID sqlbase.ID, 817 ) (map[sqlbase.ID]string, error) { 818 if tc.allSchemasForDatabase == nil { 819 tc.allSchemasForDatabase = make(map[sqlbase.ID]map[sqlbase.ID]string) 820 } 821 if _, ok := tc.allSchemasForDatabase[dbID]; !ok { 822 var err error 823 tc.allSchemasForDatabase[dbID], err = resolver.GetForDatabase(ctx, txn, tc.codec(), dbID) 824 if err != nil { 825 return nil, err 826 } 827 } 828 return tc.allSchemasForDatabase[dbID], nil 829 } 830 831 // releaseAllDescriptors releases the cached slice of all descriptors 832 // held by Collection. 833 func (tc *Collection) releaseAllDescriptors() { 834 tc.allDescriptors = nil 835 tc.allDatabaseDescriptors = nil 836 tc.allSchemasForDatabase = nil 837 } 838 839 // CopyModifiedObjects copies the modified schema to the table collection. Used 840 // when initializing an InternalExecutor. 841 func (tc *Collection) CopyModifiedObjects(to *Collection) { 842 if tc == nil { 843 return 844 } 845 to.uncommittedTables = tc.uncommittedTables 846 to.uncommittedDatabases = tc.uncommittedDatabases 847 // Do not copy the leased descriptors because we do not want 848 // the leased descriptors to be released by the "to" Collection. 849 // The "to" Collection can re-lease the same descriptors. 850 } 851 852 // ModifiedCollectionCopier is an interface used to copy modified schema elements 853 // to a new Collection. 854 type ModifiedCollectionCopier interface { 855 CopyModifiedObjects(to *Collection) 856 } 857 858 func (tc *Collection) codec() keys.SQLCodec { 859 return tc.leaseMgr.Codec() 860 } 861 862 // LeaseManager returns the lease.Manager. 863 func (tc *Collection) LeaseManager() *lease.Manager { 864 return tc.leaseMgr 865 } 866 867 // DatabaseCache returns the database.Cache. 868 func (tc *Collection) DatabaseCache() *database.Cache { 869 return tc.databaseCache 870 } 871 872 // ResetDatabaseCache resets the table collection's database.Cache. 873 func (tc *Collection) ResetDatabaseCache(dbCache *database.Cache) { 874 tc.databaseCache = dbCache 875 } 876 877 // MigrationSchemaChangeRequiredContext flags a schema change as necessary to 878 // run even in a mixed-version 19.2/20.1 state where schema changes are normally 879 // banned, because the schema change is being run in a startup migration. It's 880 // the caller's responsibility to ensure that the schema change job is safe to 881 // run in a mixed-version state. 882 // 883 // TODO (lucy): Remove this in 20.2. 884 func MigrationSchemaChangeRequiredContext(ctx context.Context) context.Context { 885 return context.WithValue(ctx, migrationSchemaChangeRequiredHint{}, migrationSchemaChangeRequiredHint{}) 886 } 887 888 // MigrationSchemaChangeRequiredFromContext returns true if the context 889 // indicates that a schema change should be run despite a mixed 19.2/20.1 890 // cluster version. 891 func MigrationSchemaChangeRequiredFromContext(ctx context.Context) bool { 892 return ctx.Value(migrationSchemaChangeRequiredHint{}) == nil 893 } 894 895 type migrationSchemaChangeRequiredHint struct{} 896 897 // ErrSchemaChangeDisallowedInMixedState signifies that an attempted schema 898 // change was disallowed from running in a mixed-version 899 var ErrSchemaChangeDisallowedInMixedState = errors.New("schema change cannot be initiated in this version until the version upgrade is finalized") 900 901 // DatabaseCacheSubscriber allows the connExecutor to wait for a callback. 902 type DatabaseCacheSubscriber interface { 903 // WaitForCacheState takes a callback depending on the cache state and blocks 904 // until the callback declares success. The callback is repeatedly called as 905 // the cache is updated. 906 WaitForCacheState(cond func(*database.Cache) bool) 907 }