github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sqlbase/metadata.go (about) 1 // Copyright 2015 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 sqlbase 12 13 import ( 14 "context" 15 "fmt" 16 "sort" 17 18 "github.com/cockroachdb/cockroach/pkg/clusterversion" 19 "github.com/cockroachdb/cockroach/pkg/config/zonepb" 20 "github.com/cockroachdb/cockroach/pkg/keys" 21 "github.com/cockroachdb/cockroach/pkg/roachpb" 22 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 23 "github.com/cockroachdb/cockroach/pkg/util/log" 24 "github.com/cockroachdb/cockroach/pkg/util/protoutil" 25 ) 26 27 var _ DescriptorProto = &DatabaseDescriptor{} 28 var _ DescriptorProto = &TableDescriptor{} 29 var _ DescriptorProto = &TypeDescriptor{} 30 var _ DescriptorProto = &SchemaDescriptor{} 31 32 // DescriptorKey is the interface implemented by both 33 // databaseKey and tableKey. It is used to easily get the 34 // descriptor key and plain name. 35 type DescriptorKey interface { 36 Key(codec keys.SQLCodec) roachpb.Key 37 Name() string 38 } 39 40 // DescriptorProto is the interface implemented by all Descriptors. 41 // TODO(marc): this is getting rather large. 42 type DescriptorProto interface { 43 protoutil.Message 44 GetPrivileges() *PrivilegeDescriptor 45 GetID() ID 46 SetID(ID) 47 TypeName() string 48 GetName() string 49 SetName(string) 50 GetAuditMode() TableDescriptor_AuditMode 51 } 52 53 // WrapDescriptor fills in a Descriptor. 54 func WrapDescriptor(descriptor DescriptorProto) *Descriptor { 55 desc := &Descriptor{} 56 switch t := descriptor.(type) { 57 case *MutableTableDescriptor: 58 desc.Union = &Descriptor_Table{Table: &t.TableDescriptor} 59 case *TableDescriptor: 60 desc.Union = &Descriptor_Table{Table: t} 61 case *DatabaseDescriptor: 62 desc.Union = &Descriptor_Database{Database: t} 63 case *MutableTypeDescriptor: 64 desc.Union = &Descriptor_Type{Type: &t.TypeDescriptor} 65 case *TypeDescriptor: 66 desc.Union = &Descriptor_Type{Type: t} 67 case *SchemaDescriptor: 68 desc.Union = &Descriptor_Schema{Schema: t} 69 default: 70 panic(fmt.Sprintf("unknown descriptor type: %s", descriptor.TypeName())) 71 } 72 return desc 73 } 74 75 // MetadataSchema is used to construct the initial sql schema for a new 76 // CockroachDB cluster being bootstrapped. Tables and databases must be 77 // installed on the underlying persistent storage before a cockroach store can 78 // start running correctly, thus requiring this special initialization. 79 type MetadataSchema struct { 80 codec keys.SQLCodec 81 descs []metadataDescriptor 82 otherSplitIDs []uint32 83 otherKV []roachpb.KeyValue 84 } 85 86 type metadataDescriptor struct { 87 parentID ID 88 desc DescriptorProto 89 } 90 91 // MakeMetadataSchema constructs a new MetadataSchema value which constructs 92 // the "system" database. Default zone configurations are required to create 93 // a MetadataSchema for the system tenant, but do not need to be supplied for 94 // any other tenant. 95 func MakeMetadataSchema( 96 codec keys.SQLCodec, 97 defaultZoneConfig *zonepb.ZoneConfig, 98 defaultSystemZoneConfig *zonepb.ZoneConfig, 99 ) MetadataSchema { 100 ms := MetadataSchema{codec: codec} 101 addSystemDatabaseToSchema(&ms, defaultZoneConfig, defaultSystemZoneConfig) 102 return ms 103 } 104 105 // AddDescriptor adds a new non-config descriptor to the system schema. 106 func (ms *MetadataSchema) AddDescriptor(parentID ID, desc DescriptorProto) { 107 if id := desc.GetID(); id > keys.MaxReservedDescID { 108 panic(fmt.Sprintf("invalid reserved table ID: %d > %d", id, keys.MaxReservedDescID)) 109 } 110 for _, d := range ms.descs { 111 if d.desc.GetID() == desc.GetID() { 112 log.Errorf(context.TODO(), "adding descriptor with duplicate ID: %v", desc) 113 return 114 } 115 } 116 ms.descs = append(ms.descs, metadataDescriptor{parentID, desc}) 117 } 118 119 // AddSplitIDs adds some "table ids" to the MetadataSchema such that 120 // corresponding keys are returned as split points by GetInitialValues(). 121 // AddDescriptor() has the same effect for the table descriptors that are passed 122 // to it, but we also have a couple of "fake tables" that don't have descriptors 123 // but need splits just the same. 124 func (ms *MetadataSchema) AddSplitIDs(id ...uint32) { 125 ms.otherSplitIDs = append(ms.otherSplitIDs, id...) 126 } 127 128 // SystemDescriptorCount returns the number of descriptors that will be created by 129 // this schema. This value is needed to automate certain tests. 130 func (ms MetadataSchema) SystemDescriptorCount() int { 131 return len(ms.descs) 132 } 133 134 // GetInitialValues returns the set of initial K/V values which should be added to 135 // a bootstrapping cluster in order to create the tables contained 136 // in the schema. Also returns a list of split points (a split for each SQL 137 // table descriptor part of the initial values). Both returned sets are sorted. 138 func (ms MetadataSchema) GetInitialValues() ([]roachpb.KeyValue, []roachpb.RKey) { 139 var ret []roachpb.KeyValue 140 var splits []roachpb.RKey 141 142 // Save the ID generator value, which will generate descriptor IDs for user 143 // objects. 144 value := roachpb.Value{} 145 value.SetInt(int64(keys.MinUserDescID)) 146 ret = append(ret, roachpb.KeyValue{ 147 Key: ms.codec.DescIDSequenceKey(), 148 Value: value, 149 }) 150 151 // addDescriptor generates the needed KeyValue objects to install a 152 // descriptor on a new cluster. 153 addDescriptor := func(parentID ID, desc DescriptorProto) { 154 // Create name metadata key. 155 value := roachpb.Value{} 156 value.SetInt(int64(desc.GetID())) 157 if parentID != keys.RootNamespaceID { 158 ret = append(ret, roachpb.KeyValue{ 159 Key: NewPublicTableKey(parentID, desc.GetName()).Key(ms.codec), 160 Value: value, 161 }) 162 } else { 163 // Initializing a database. Databases must be initialized with 164 // the public schema, as all tables are scoped under the public schema. 165 publicSchemaValue := roachpb.Value{} 166 publicSchemaValue.SetInt(int64(keys.PublicSchemaID)) 167 ret = append( 168 ret, 169 roachpb.KeyValue{ 170 Key: NewDatabaseKey(desc.GetName()).Key(ms.codec), 171 Value: value, 172 }, 173 roachpb.KeyValue{ 174 Key: NewPublicSchemaKey(desc.GetID()).Key(ms.codec), 175 Value: publicSchemaValue, 176 }) 177 } 178 179 // Create descriptor metadata key. 180 value = roachpb.Value{} 181 wrappedDesc := WrapDescriptor(desc) 182 if err := value.SetProto(wrappedDesc); err != nil { 183 log.Fatalf(context.TODO(), "could not marshal %v", desc) 184 } 185 ret = append(ret, roachpb.KeyValue{ 186 Key: MakeDescMetadataKey(ms.codec, desc.GetID()), 187 Value: value, 188 }) 189 if desc.GetID() > keys.MaxSystemConfigDescID { 190 splits = append(splits, roachpb.RKey(ms.codec.TablePrefix(uint32(desc.GetID())))) 191 } 192 } 193 194 // Generate initial values for system databases and tables, which have 195 // static descriptors that were generated elsewhere. 196 for _, sysObj := range ms.descs { 197 addDescriptor(sysObj.parentID, sysObj.desc) 198 } 199 200 for _, id := range ms.otherSplitIDs { 201 splits = append(splits, roachpb.RKey(ms.codec.TablePrefix(id))) 202 } 203 204 // Other key/value generation that doesn't fit into databases and 205 // tables. This can be used to add initial entries to a table. 206 ret = append(ret, ms.otherKV...) 207 208 // Sort returned key values; this is valuable because it matches the way the 209 // objects would be sorted if read from the engine. 210 sort.Sort(roachpb.KeyValueByKey(ret)) 211 sort.Slice(splits, func(i, j int) bool { 212 return splits[i].Less(splits[j]) 213 }) 214 215 return ret, splits 216 } 217 218 // DescriptorIDs returns the descriptor IDs present in the metadata schema in 219 // sorted order. 220 func (ms MetadataSchema) DescriptorIDs() IDs { 221 descriptorIDs := IDs{} 222 for _, md := range ms.descs { 223 descriptorIDs = append(descriptorIDs, md.desc.GetID()) 224 } 225 sort.Sort(descriptorIDs) 226 return descriptorIDs 227 } 228 229 // systemTableIDCache is used to accelerate name lookups on table descriptors. 230 // It relies on the fact that table IDs under MaxReservedDescID are fixed. 231 // 232 // Mapping: [systemTenant][tableName] => tableID 233 var systemTableIDCache = func() [2]map[string]ID { 234 cacheForTenant := func(systemTenant bool) map[string]ID { 235 cache := make(map[string]ID) 236 237 codec := keys.SystemSQLCodec 238 if !systemTenant { 239 codec = keys.MakeSQLCodec(roachpb.MinTenantID) 240 } 241 242 ms := MetadataSchema{codec: codec} 243 addSystemDescriptorsToSchema(&ms) 244 for _, d := range ms.descs { 245 t, ok := d.desc.(*TableDescriptor) 246 if !ok || t.ParentID != SystemDB.ID || t.ID > keys.MaxReservedDescID { 247 // We only cache table descriptors under 'system' with a 248 // reserved table ID. 249 continue 250 } 251 cache[t.Name] = t.ID 252 } 253 254 // This special case exists so that we resolve "namespace" to the new 255 // namespace table ID (30) in 20.1, while the Name in the "namespace" 256 // descriptor is still set to "namespace2" during the 20.1 cycle. We 257 // couldn't set the new namespace table's Name to "namespace" in 20.1, 258 // because it had to co-exist with the old namespace table, whose name 259 // must *remain* "namespace" - and you can't have duplicate descriptor 260 // Name fields. 261 // 262 // This can be removed in 20.2, when we add a migration to change the 263 // new namespace table's Name to "namespace" again. 264 // TODO(solon): remove this in 20.2. 265 cache[NamespaceTableName] = keys.NamespaceTableID 266 267 return cache 268 } 269 270 var cache [2]map[string]ID 271 for _, b := range []bool{false, true} { 272 cache[boolToInt(b)] = cacheForTenant(b) 273 } 274 return cache 275 }() 276 277 func boolToInt(b bool) int { 278 if b { 279 return 1 280 } 281 return 0 282 } 283 284 // LookupSystemTableDescriptorID uses the lookup cache above 285 // to bypass a KV lookup when resolving the name of system tables. 286 func LookupSystemTableDescriptorID( 287 ctx context.Context, settings *cluster.Settings, codec keys.SQLCodec, dbID ID, tableName string, 288 ) ID { 289 if dbID != SystemDB.ID { 290 return InvalidID 291 } 292 293 if settings != nil && 294 !settings.Version.IsActive(ctx, clusterversion.VersionNamespaceTableWithSchemas) && 295 tableName == NamespaceTableName { 296 return DeprecatedNamespaceTable.ID 297 } 298 systemTenant := boolToInt(codec.ForSystemTenant()) 299 dbID, ok := systemTableIDCache[systemTenant][tableName] 300 if !ok { 301 return InvalidID 302 } 303 return dbID 304 }