// GetInitialValues returns the set of initial K/V values which should be added to // a bootstrapping CockroachDB cluster in order to create the tables contained // in the schema. func (ms MetadataSchema) GetInitialValues() []roachpb.KeyValue { var ret []roachpb.KeyValue // Save the ID generator value, which will generate descriptor IDs for user // objects. value := roachpb.Value{} value.SetInt(int64(keys.MaxReservedDescID + 1)) ret = append(ret, roachpb.KeyValue{ Key: keys.DescIDGenerator, Value: value, }) // addDescriptor generates the needed KeyValue objects to install a // descriptor on a new cluster. addDescriptor := func(parentID ID, desc descriptorProto) { // Create name metadata key. value := roachpb.Value{} value.SetInt(int64(desc.GetID())) ret = append(ret, roachpb.KeyValue{ Key: MakeNameMetadataKey(parentID, desc.GetName()), Value: value, }) // Create descriptor metadata key. value = roachpb.Value{} wrappedDesc := wrapDescriptor(desc) if err := value.SetProto(wrappedDesc); err != nil { log.Fatalf("could not marshal %v", desc) } ret = append(ret, roachpb.KeyValue{ Key: MakeDescMetadataKey(desc.GetID()), Value: value, }) } // Generate initial values for system databases and tables, which have // static descriptors that were generated elsewhere. for _, sysObj := range ms.descs { addDescriptor(sysObj.parentID, sysObj.desc) } for _, tbl := range ms.tables { dbID := ID(keys.SystemDatabaseID) desc := createTableDescriptor(tbl.id, dbID, tbl.definition, tbl.privileges) addDescriptor(dbID, &desc) } // Other key/value generation that doesn't fit into databases and // tables. This can be used to add initial entries to a table. ret = append(ret, ms.otherKV...) // Sort returned key values; this is valuable because it matches the way the // objects would be sorted if read from the engine. sort.Sort(roachpb.KeyValueByKey(ret)) return ret }
func TestComputeSplits(t *testing.T) { defer leaktest.AfterTest(t)() const ( start = keys.MaxReservedDescID + 1 reservedStart = keys.MaxSystemConfigDescID + 1 ) schema := sqlbase.MakeMetadataSchema() // Real SQL system tables only. baseSql := schema.GetInitialValues() // Real SQL system tables plus some user stuff. userSql := append(schema.GetInitialValues(), descriptor(start), descriptor(start+1), descriptor(start+5)) // Real SQL system with reserved non-system tables. schema.AddTable(reservedStart+1, "CREATE TABLE system.test1 (i INT PRIMARY KEY)") schema.AddTable(reservedStart+2, "CREATE TABLE system.test2 (i INT PRIMARY KEY)") reservedSql := schema.GetInitialValues() // Real SQL system with reserved non-system and user database. allSql := append(schema.GetInitialValues(), descriptor(start), descriptor(start+1), descriptor(start+5)) sort.Sort(roachpb.KeyValueByKey(allSql)) allUserSplits := []uint32{start, start + 1, start + 2, start + 3, start + 4, start + 5} var allReservedSplits []uint32 for i := 0; i < schema.TableCount(); i++ { allReservedSplits = append(allReservedSplits, reservedStart+uint32(i)) } allSplits := append(allReservedSplits, allUserSplits...) testCases := []struct { values []roachpb.KeyValue start, end roachpb.RKey // Use ints in the testcase definitions, more readable. splits []uint32 }{ // No data. {nil, roachpb.RKeyMin, roachpb.RKeyMax, nil}, {nil, keys.MakeTablePrefix(start), roachpb.RKeyMax, nil}, {nil, keys.MakeTablePrefix(start), keys.MakeTablePrefix(start + 10), nil}, {nil, roachpb.RKeyMin, keys.MakeTablePrefix(start + 10), nil}, // No user data. {baseSql, roachpb.RKeyMin, roachpb.RKeyMax, allReservedSplits}, {baseSql, keys.MakeTablePrefix(start), roachpb.RKeyMax, nil}, {baseSql, keys.MakeTablePrefix(start), keys.MakeTablePrefix(start + 10), nil}, {baseSql, roachpb.RKeyMin, keys.MakeTablePrefix(start + 10), allReservedSplits}, // User descriptors. {userSql, keys.MakeTablePrefix(start - 1), roachpb.RKeyMax, allUserSplits}, {userSql, keys.MakeTablePrefix(start), roachpb.RKeyMax, allUserSplits[1:]}, {userSql, keys.MakeTablePrefix(start), keys.MakeTablePrefix(start + 10), allUserSplits[1:]}, {userSql, keys.MakeTablePrefix(start - 1), keys.MakeTablePrefix(start + 10), allUserSplits}, {userSql, keys.MakeTablePrefix(start + 4), keys.MakeTablePrefix(start + 10), allUserSplits[5:]}, {userSql, keys.MakeTablePrefix(start + 5), keys.MakeTablePrefix(start + 10), nil}, {userSql, keys.MakeTablePrefix(start + 6), keys.MakeTablePrefix(start + 10), nil}, {userSql, testutils.MakeKey(keys.MakeTablePrefix(start), roachpb.RKey("foo")), keys.MakeTablePrefix(start + 10), allUserSplits[1:]}, {userSql, testutils.MakeKey(keys.MakeTablePrefix(start), roachpb.RKey("foo")), keys.MakeTablePrefix(start + 5), allUserSplits[1:5]}, {userSql, testutils.MakeKey(keys.MakeTablePrefix(start), roachpb.RKey("foo")), testutils.MakeKey(keys.MakeTablePrefix(start+5), roachpb.RKey("bar")), allUserSplits[1:5]}, {userSql, testutils.MakeKey(keys.MakeTablePrefix(start), roachpb.RKey("foo")), testutils.MakeKey(keys.MakeTablePrefix(start), roachpb.RKey("morefoo")), nil}, // Reserved descriptors. {reservedSql, roachpb.RKeyMin, roachpb.RKeyMax, allReservedSplits}, {reservedSql, keys.MakeTablePrefix(reservedStart), roachpb.RKeyMax, allReservedSplits[1:]}, {reservedSql, keys.MakeTablePrefix(start), roachpb.RKeyMax, nil}, {reservedSql, keys.MakeTablePrefix(reservedStart), keys.MakeTablePrefix(start + 10), allReservedSplits[1:]}, {reservedSql, roachpb.RKeyMin, keys.MakeTablePrefix(reservedStart + 2), allReservedSplits[:2]}, {reservedSql, roachpb.RKeyMin, keys.MakeTablePrefix(reservedStart + 10), allReservedSplits}, {reservedSql, keys.MakeTablePrefix(reservedStart), keys.MakeTablePrefix(reservedStart + 2), allReservedSplits[1:2]}, {reservedSql, testutils.MakeKey(keys.MakeTablePrefix(reservedStart), roachpb.RKey("foo")), testutils.MakeKey(keys.MakeTablePrefix(start+10), roachpb.RKey("foo")), allReservedSplits[1:]}, // Reserved/User mix. {allSql, roachpb.RKeyMin, roachpb.RKeyMax, allSplits}, {allSql, keys.MakeTablePrefix(reservedStart + 1), roachpb.RKeyMax, allSplits[2:]}, {allSql, keys.MakeTablePrefix(start), roachpb.RKeyMax, allUserSplits[1:]}, {allSql, keys.MakeTablePrefix(reservedStart), keys.MakeTablePrefix(start + 10), allSplits[1:]}, {allSql, roachpb.RKeyMin, keys.MakeTablePrefix(start + 2), allSplits[:6]}, {allSql, testutils.MakeKey(keys.MakeTablePrefix(reservedStart), roachpb.RKey("foo")), testutils.MakeKey(keys.MakeTablePrefix(start+5), roachpb.RKey("foo")), allSplits[1:9]}, } cfg := config.SystemConfig{} for tcNum, tc := range testCases { cfg.Values = tc.values splits := cfg.ComputeSplitKeys(tc.start, tc.end) if len(splits) == 0 && len(tc.splits) == 0 { continue } // Convert ints to actual keys. expected := []roachpb.RKey{} for _, s := range tc.splits { expected = append(expected, keys.MakeRowSentinelKey(keys.MakeTablePrefix(s))) } if !reflect.DeepEqual(splits, expected) { t.Errorf("#%d: bad splits:\ngot: %v\nexpected: %v", tcNum, splits, expected) } } }
// GetInitialValues returns the set of initial K/V values which should be added to // a bootstrapping CockroachDB cluster in order to create the tables contained // in the schema. func (ms MetadataSchema) GetInitialValues() []roachpb.KeyValue { var ret []roachpb.KeyValue // Save the ID generator value, which will generate descriptor IDs for user // objects. value := roachpb.Value{} value.SetInt(int64(keys.MaxReservedDescID + 1)) ret = append(ret, roachpb.KeyValue{ Key: keys.DescIDGenerator, Value: value, }) // addDescriptor generates the needed KeyValue objects to install a // descriptor on a new cluster. addDescriptor := func(parentID ID, desc descriptorProto) { // Create name metadata key. value := roachpb.Value{} value.SetInt(int64(desc.GetID())) ret = append(ret, roachpb.KeyValue{ Key: MakeNameMetadataKey(parentID, desc.GetName()), Value: value, }) // Create descriptor metadata key. value = roachpb.Value{} wrappedDesc := wrapDescriptor(desc) if err := value.SetProto(wrappedDesc); err != nil { log.Fatalf("could not marshal %v", desc) } ret = append(ret, roachpb.KeyValue{ Key: MakeDescMetadataKey(desc.GetID()), Value: value, }) } // Generate initial values for system databases and tables, which have // static descriptors that were generated elsewhere. for _, sysObj := range ms.systemObjects { addDescriptor(sysObj.parentID, sysObj.desc) } // Descriptor IDs for non-system databases and objects will be generated // sequentially within the non-system reserved range. initialDescID := keys.MaxSystemDescID + 1 nextID := func() ID { next := initialDescID initialDescID++ return ID(next) } // Generate initial values for non-system metadata tables, which do not need // well-known IDs. for _, db := range ms.databases { dbID := nextID() addDescriptor(keys.RootNamespaceID, &DatabaseDescriptor{ Name: db.name, ID: dbID, Privileges: db.privileges, }) for _, tbl := range db.tables { desc := createTableDescriptor(nextID(), dbID, tbl.definition, tbl.privileges) addDescriptor(dbID, &desc) } } // Sort returned key values; this is valuable because it matches the way the // objects would be sorted if read from the engine. sort.Sort(roachpb.KeyValueByKey(ret)) return ret }