github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/catalog/database/database.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 database primarily provides the incoherent database cache and
    12  // related interfaces.
    13  //
    14  // TODO(ajwerner): Lease database descriptors like all other schema objects and
    15  // eliminate this package.
    16  package database
    17  
    18  import (
    19  	"context"
    20  	"sync"
    21  
    22  	"github.com/cockroachdb/cockroach/pkg/config"
    23  	"github.com/cockroachdb/cockroach/pkg/keys"
    24  	"github.com/cockroachdb/cockroach/pkg/kv"
    25  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv"
    27  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    28  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    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  )
    33  
    34  // Cache holds a cache from database name to database ID. It is
    35  // populated as database IDs are requested and a new cache is created whenever
    36  // the system config changes. As such, no attempt is made to limit its size
    37  // which is naturally limited by the number of database descriptors in the
    38  // system the periodic reset whenever the system config is gossiped.
    39  type Cache struct {
    40  	// databases is really a map of string -> sqlbase.ID
    41  	databases sync.Map
    42  
    43  	// codec is used to encode and decode sql keys.
    44  	codec keys.SQLCodec
    45  
    46  	// systemConfig holds a copy of the latest system config since the last
    47  	// call to resetForBatch.
    48  	systemConfig *config.SystemConfig
    49  }
    50  
    51  // NewCache constructs a new Cache.
    52  func NewCache(codec keys.SQLCodec, cfg *config.SystemConfig) *Cache {
    53  	return &Cache{
    54  		codec:        codec,
    55  		systemConfig: cfg,
    56  	}
    57  }
    58  
    59  func (dc *Cache) getID(name string) sqlbase.ID {
    60  	val, ok := dc.databases.Load(name)
    61  	if !ok {
    62  		return sqlbase.InvalidID
    63  	}
    64  	return val.(sqlbase.ID)
    65  }
    66  
    67  func (dc *Cache) setID(name string, id sqlbase.ID) {
    68  	dc.databases.Store(name, id)
    69  }
    70  
    71  // getCachedDatabaseDesc looks up the database descriptor from the descriptor cache,
    72  // given its name. Returns nil and no error if the name is not present in the
    73  // cache.
    74  func (dc *Cache) getCachedDatabaseDesc(name string) (*sqlbase.DatabaseDescriptor, error) {
    75  	dbID, err := dc.GetCachedDatabaseID(name)
    76  	if dbID == sqlbase.InvalidID || err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	return dc.getCachedDatabaseDescByID(dbID)
    81  }
    82  
    83  // getCachedDatabaseDescByID looks up the database descriptor from the descriptor cache,
    84  // given its ID.
    85  func (dc *Cache) getCachedDatabaseDescByID(id sqlbase.ID) (*sqlbase.DatabaseDescriptor, error) {
    86  	if id == sqlbase.SystemDB.ID {
    87  		// We can't return a direct reference to SystemDB, because the
    88  		// caller expects a private object that can be modified in-place.
    89  		sysDB := sqlbase.MakeSystemDatabaseDesc()
    90  		return &sysDB, nil
    91  	}
    92  
    93  	descKey := sqlbase.MakeDescMetadataKey(dc.codec, id)
    94  	descVal := dc.systemConfig.GetValue(descKey)
    95  	if descVal == nil {
    96  		return nil, nil
    97  	}
    98  
    99  	desc := &sqlbase.Descriptor{}
   100  	if err := descVal.GetProto(desc); err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	database := desc.GetDatabase()
   105  	if database == nil {
   106  		return nil, pgerror.Newf(pgcode.WrongObjectType, "[%d] is not a database", id)
   107  	}
   108  
   109  	return database, database.Validate()
   110  }
   111  
   112  // GetDatabaseDesc returns the database descriptor given its name
   113  // if it exists in the cache, otherwise falls back to KV operations.
   114  func (dc *Cache) GetDatabaseDesc(
   115  	ctx context.Context,
   116  	txnRunner func(context.Context, func(context.Context, *kv.Txn) error) error,
   117  	name string,
   118  	required bool,
   119  ) (*sqlbase.DatabaseDescriptor, error) {
   120  	// Lookup the database in the cache first, falling back to the KV store if it
   121  	// isn't present. The cache might cause the usage of a recently renamed
   122  	// database, but that's a race that could occur anyways.
   123  	// The cache lookup may fail.
   124  	desc, err := dc.getCachedDatabaseDesc(name)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	if desc == nil {
   129  		if err := txnRunner(ctx, func(ctx context.Context, txn *kv.Txn) error {
   130  			// Run the descriptor read as high-priority, thereby pushing any intents out
   131  			// of its way. We don't want schema changes to prevent database lookup;
   132  			// we'd rather force them to refresh. Also this prevents deadlocks in cases
   133  			// where the name resolution is triggered by the transaction doing the
   134  			// schema change itself.
   135  			if err := txn.SetUserPriority(roachpb.MaxUserPriority); err != nil {
   136  				return err
   137  			}
   138  			a := catalogkv.UncachedPhysicalAccessor{}
   139  			desc, err = a.GetDatabaseDesc(ctx, txn, dc.codec, name,
   140  				tree.DatabaseLookupFlags{Required: required})
   141  			return err
   142  		}); err != nil {
   143  			return nil, err
   144  		}
   145  	}
   146  	if desc != nil {
   147  		dc.setID(name, desc.ID)
   148  	}
   149  	return desc, err
   150  }
   151  
   152  // GetDatabaseDescByID returns the database descriptor given its ID
   153  // if it exists in the cache, otherwise falls back to KV operations.
   154  func (dc *Cache) GetDatabaseDescByID(
   155  	ctx context.Context, txn *kv.Txn, id sqlbase.ID,
   156  ) (*sqlbase.DatabaseDescriptor, error) {
   157  	desc, err := dc.getCachedDatabaseDescByID(id)
   158  	if desc == nil || err != nil {
   159  		if err != nil {
   160  			log.VEventf(ctx, 3, "error getting database descriptor from cache: %s", err)
   161  		}
   162  		desc, err = catalogkv.MustGetDatabaseDescByID(ctx, txn, dc.codec, id)
   163  	}
   164  	return desc, err
   165  }
   166  
   167  // GetDatabaseID returns the ID of a database given its name. It
   168  // uses the descriptor cache if possible, otherwise falls back to KV
   169  // operations.
   170  func (dc *Cache) GetDatabaseID(
   171  	ctx context.Context,
   172  	txnRunner func(context.Context, func(context.Context, *kv.Txn) error) error,
   173  	name string,
   174  	required bool,
   175  ) (sqlbase.ID, error) {
   176  	dbID, err := dc.GetCachedDatabaseID(name)
   177  	if err != nil {
   178  		return dbID, err
   179  	}
   180  	if dbID == sqlbase.InvalidID {
   181  		if err := txnRunner(ctx, func(ctx context.Context, txn *kv.Txn) error {
   182  			// Run the namespace read as high-priority, thereby pushing any intents out
   183  			// of its way. We don't want schema changes to prevent database acquisitions;
   184  			// we'd rather force them to refresh. Also this prevents deadlocks in cases
   185  			// where the name resolution is triggered by the transaction doing the
   186  			// schema change itself.
   187  			if err := txn.SetUserPriority(roachpb.MaxUserPriority); err != nil {
   188  				return err
   189  			}
   190  			var err error
   191  			dbID, err = catalogkv.GetDatabaseID(ctx, txn, dc.codec, name, required)
   192  			return err
   193  		}); err != nil {
   194  			return sqlbase.InvalidID, err
   195  		}
   196  	}
   197  	dc.setID(name, dbID)
   198  	return dbID, nil
   199  }
   200  
   201  // GetCachedDatabaseID returns the ID of a database given its name
   202  // from the cache. This method never goes to the store to resolve
   203  // the name to id mapping. Returns InvalidID if the name to id mapping or
   204  // the database descriptor are not in the cache.
   205  func (dc *Cache) GetCachedDatabaseID(name string) (sqlbase.ID, error) {
   206  	if id := dc.getID(name); id != sqlbase.InvalidID {
   207  		return id, nil
   208  	}
   209  
   210  	if name == sqlbase.SystemDB.Name {
   211  		return sqlbase.SystemDB.ID, nil
   212  	}
   213  
   214  	var nameKey sqlbase.DescriptorKey = sqlbase.NewDatabaseKey(name)
   215  	nameVal := dc.systemConfig.GetValue(nameKey.Key(dc.codec))
   216  	if nameVal == nil {
   217  		// Try the deprecated system.namespace before returning InvalidID.
   218  		// TODO(solon): This can be removed in 20.2.
   219  		nameKey = sqlbase.NewDeprecatedDatabaseKey(name)
   220  		nameVal = dc.systemConfig.GetValue(nameKey.Key(dc.codec))
   221  		if nameVal == nil {
   222  			return sqlbase.InvalidID, nil
   223  		}
   224  	}
   225  
   226  	id, err := nameVal.GetInt()
   227  	return sqlbase.ID(id), err
   228  }
   229  
   230  // Codec returns the cache's codec.
   231  func (dc *Cache) Codec() keys.SQLCodec {
   232  	return dc.codec
   233  }