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  }