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 }