func TestObjectIDForKey(t *testing.T) { defer leaktest.AfterTest(t) testCases := []struct { key roachpb.RKey success bool id uint32 }{ // Before the structured span. {roachpb.RKeyMin, false, 0}, // Boundaries of structured span. {roachpb.RKeyMax, false, 0}, // Valid, even if there are things after the ID. {keys.MakeKey(keys.MakeTablePrefix(42), roachpb.RKey("\xff")), true, 42}, {keys.MakeTablePrefix(0), true, 0}, {keys.MakeTablePrefix(999), true, 999}, } for tcNum, tc := range testCases { id, success := config.ObjectIDForKey(tc.key) if success != tc.success { t.Errorf("#%d: expected success=%t", tcNum, tc.success) continue } if id != tc.id { t.Errorf("#%d: expected id=%d, got %d", tcNum, tc.id, id) } } }
// TestStoreZoneUpdateAndRangeSplit verifies that modifying the zone // configuration changes range max bytes and Range.maybeSplit() takes // max bytes into account when deciding whether to enqueue a range for // splitting. It further verifies that the range is in fact split on // exceeding zone's RangeMaxBytes. func TestStoreZoneUpdateAndRangeSplit(t *testing.T) { defer leaktest.AfterTest(t) t.Skip("#3762") store, stopper := createTestStore(t) config.TestingSetupZoneConfigHook(stopper) defer stopper.Stop() maxBytes := int64(1 << 16) // Set max bytes. descID := uint32(keys.MaxReservedDescID + 1) config.TestingSetZoneConfig(descID, &config.ZoneConfig{RangeMaxBytes: maxBytes}) // Trigger gossip callback. if err := store.Gossip().AddInfoProto(gossip.KeySystemConfig, &config.SystemConfig{}, 0); err != nil { t.Fatal(err) } // Wait for the range to be split along table boundaries. originalRange := store.LookupReplica(roachpb.RKey(keys.UserTableDataMin), nil) var rng *storage.Replica if err := util.IsTrueWithin(func() bool { rng = store.LookupReplica(keys.MakeTablePrefix(descID), nil) return rng.RangeID != originalRange.RangeID }, splitTimeout); err != nil { t.Fatalf("failed to notice range max bytes update: %s", err) } // Check range's max bytes settings. if rng.GetMaxBytes() != maxBytes { t.Fatalf("range max bytes mismatch, got: %d, expected: %d", rng.GetMaxBytes(), maxBytes) } // Make sure the second range goes to the end. if !roachpb.RKeyMax.Equal(rng.Desc().EndKey) { t.Fatalf("second range has split: %+v", rng.Desc()) } // Look in the range after prefix we're writing to. fillRange(store, rng.RangeID, keys.MakeTablePrefix(descID), maxBytes, t) // Verify that the range is in fact split (give it a few seconds for very // slow test machines). var newRng *storage.Replica util.SucceedsWithin(t, splitTimeout, func() error { newRng = store.LookupReplica(keys.MakeTablePrefix(descID+1), nil) if newRng.RangeID == rng.RangeID { return util.Errorf("range has not yet split") } return nil }) // Make sure the new range goes to the end. if !roachpb.RKeyMax.Equal(newRng.Desc().EndKey) { t.Fatalf("second range has split: %+v", rng.Desc()) } }
// TestStoreZoneUpdateAndRangeSplit verifies that modifying the zone // configuration changes range max bytes and Range.maybeSplit() takes // max bytes into account when deciding whether to enqueue a range for // splitting. It further verifies that the range is in fact split on // exceeding zone's RangeMaxBytes. func TestStoreZoneUpdateAndRangeSplit(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) config.TestingSetupZoneConfigHook(stopper) defer stopper.Stop() maxBytes := int64(1 << 16) // Set max bytes. config.TestingSetZoneConfig(1000, &config.ZoneConfig{RangeMaxBytes: maxBytes}) // Trigger gossip callback. if err := store.Gossip().AddInfoProto(gossip.KeySystemConfig, &config.SystemConfig{}, 0); err != nil { t.Fatal(err) } // Wait for the range to be split along table boundaries. originalRange := store.LookupReplica(roachpb.RKeyMin, nil) var rng *storage.Replica if err := util.IsTrueWithin(func() bool { rng = store.LookupReplica(keys.MakeTablePrefix(1000), nil) return rng.Desc().RangeID != originalRange.Desc().RangeID }, 50*time.Millisecond); err != nil { t.Fatalf("failed to notice range max bytes update: %s", err) } // Check range's max bytes settings. if rng.GetMaxBytes() != maxBytes { t.Fatalf("range max bytes mismatch, got: %d, expected: %d", rng.GetMaxBytes(), maxBytes) } // Make sure the second range goes to the end. if !roachpb.RKeyMax.Equal(rng.Desc().EndKey) { t.Fatalf("second range has split: %+v", rng.Desc()) } // Look in the range after prefix we're writing to. fillRange(store, rng.Desc().RangeID, keys.MakeTablePrefix(1000), maxBytes, t) // Verify that the range is in fact split (give it a second for very slow test machines). var newRng *storage.Replica if err := util.IsTrueWithin(func() bool { newRng = store.LookupReplica(keys.MakeTablePrefix(2000), nil) return newRng.Desc().RangeID != rng.Desc().RangeID }, time.Second); err != nil { t.Errorf("expected range to split within 1s") } // Make sure the new range goes to the end. if !roachpb.RKeyMax.Equal(newRng.Desc().EndKey) { t.Fatalf("second range has split: %+v", rng.Desc()) } }
// TestStoreZoneUpdateAndRangeSplit verifies that modifying the zone // configuration changes range max bytes and Range.maybeSplit() takes // max bytes into account when deciding whether to enqueue a range for // splitting. It further verifies that the range is in fact split on // exceeding zone's RangeMaxBytes. func TestStoreZoneUpdateAndRangeSplit(t *testing.T) { defer leaktest.AfterTest(t)() store, stopper, _ := createTestStore(t) config.TestingSetupZoneConfigHook(stopper) defer stopper.Stop() maxBytes := int64(1 << 16) // Set max bytes. descID := uint32(keys.MaxReservedDescID + 1) config.TestingSetZoneConfig(descID, &config.ZoneConfig{RangeMaxBytes: maxBytes}) // Trigger gossip callback. if err := store.Gossip().AddInfoProto(gossip.KeySystemConfig, &config.SystemConfig{}, 0); err != nil { t.Fatal(err) } tableBoundary := keys.MakeTablePrefix(descID) { var rng *storage.Replica // Wait for the range to be split along table boundaries. expectedRSpan := roachpb.RSpan{Key: roachpb.RKey(tableBoundary), EndKey: roachpb.RKeyMax} util.SucceedsSoon(t, func() error { rng = store.LookupReplica(tableBoundary, nil) if actualRSpan := rng.Desc().RSpan(); !actualRSpan.Equal(expectedRSpan) { return util.Errorf("expected range %s to span %s", rng, expectedRSpan) } return nil }) // Check range's max bytes settings. if actualMaxBytes := rng.GetMaxBytes(); actualMaxBytes != maxBytes { t.Fatalf("range %s max bytes mismatch, got: %d, expected: %d", rng, actualMaxBytes, maxBytes) } // Look in the range after prefix we're writing to. fillRange(store, rng.RangeID, tableBoundary, maxBytes, t) } // Verify that the range is in fact split. util.SucceedsSoon(t, func() error { rng := store.LookupReplica(keys.MakeTablePrefix(descID+1), nil) rngDesc := rng.Desc() rngStart, rngEnd := rngDesc.StartKey, rngDesc.EndKey if rngStart.Equal(tableBoundary) || !rngEnd.Equal(roachpb.RKeyMax) { return util.Errorf("range %s has not yet split", rng) } return nil }) }
// GetLargestObjectID returns the largest object ID found in the config. // This could be either a table or a database. func (s *SystemConfig) GetLargestObjectID() (uint32, error) { testingLock.Lock() hook := TestingLargestIDHook testingLock.Unlock() if hook != nil { return hook(), nil } if len(s.Values) == 0 { return 0, fmt.Errorf("empty system values in config") } // Search for the first key after the descriptor table. // We can't use GetValue as we don't mind if there is nothing after // the descriptor table. key := proto.Key(keys.MakeTablePrefix(keys.DescriptorTableID + 1)) index := sort.Search(len(s.Values), func(i int) bool { return !s.Values[i].Key.Less(key) }) if index == 0 { return 0, fmt.Errorf("descriptor table not found in system config of %d values", len(s.Values)) } // This is the last key of the descriptor table. key = s.Values[index-1].Key // Extract object ID from key. // TODO(marc): move sql/keys.go to keys (or similar) and use a DecodeDescMetadataKey. // We should also check proper encoding. descriptorPrefix := keys.MakeTablePrefix(keys.DescriptorTableID) remaining := bytes.TrimPrefix(key, descriptorPrefix) // TrimPrefix returns the bytes unchanged if the prefix does not match. if len(remaining) == len(key) { return 0, fmt.Errorf("descriptor table not found in system config of %d values", len(s.Values)) } // DescriptorTable.PrimaryIndex.ID remaining, _, err := encoding.DecodeUvarint(remaining) if err != nil { return 0, err } // descID _, id, err := encoding.DecodeUvarint(remaining) if err != nil { return 0, err } return uint32(id), nil }
func sqlKV(tableID uint32, indexID, descriptorID uint64) roachpb.KeyValue { k := keys.MakeTablePrefix(tableID) k = encoding.EncodeUvarintAscending(k, indexID) k = encoding.EncodeUvarintAscending(k, descriptorID) k = encoding.EncodeUvarintAscending(k, 12345) // Column ID, but could be anything. return kv(k, nil) }
// RefreshLeases starts a goroutine that refreshes the lease manager // leases for tables received in the latest system configuration via gossip. func (m *LeaseManager) RefreshLeases(s *stop.Stopper, db *client.DB, gossip *gossip.Gossip) { s.RunWorker(func() { descKeyPrefix := keys.MakeTablePrefix(uint32(sqlbase.DescriptorTable.ID)) gossipUpdateC := gossip.RegisterSystemConfigChannel() for { select { case <-gossipUpdateC: cfg, _ := gossip.GetSystemConfig() if m.testingKnobs.GossipUpdateEvent != nil { m.testingKnobs.GossipUpdateEvent(cfg) } // Read all tables and their versions if log.V(2) { log.Info("received a new config; will refresh leases") } // Loop through the configuration to find all the tables. for _, kv := range cfg.Values { if !bytes.HasPrefix(kv.Key, descKeyPrefix) { continue } // Attempt to unmarshal config into a table/database descriptor. var descriptor sqlbase.Descriptor if err := kv.Value.GetProto(&descriptor); err != nil { log.Warningf("%s: unable to unmarshal descriptor %v", kv.Key, kv.Value) continue } switch union := descriptor.Union.(type) { case *sqlbase.Descriptor_Table: table := union.Table if err := table.Validate(); err != nil { log.Errorf("%s: received invalid table descriptor: %v", kv.Key, table) continue } if log.V(2) { log.Infof("%s: refreshing lease table: %d (%s), version: %d", kv.Key, table.ID, table.Name, table.Version) } // Try to refresh the table lease to one >= this version. if t := m.findTableState(table.ID, false /* create */, nil); t != nil { if err := t.purgeOldLeases( db, table.Deleted(), table.Version, m.LeaseStore); err != nil { log.Warningf("error purging leases for table %d(%s): %s", table.ID, table.Name, err) } } case *sqlbase.Descriptor_Database: // Ignore. } } if m.testingKnobs.TestingLeasesRefreshedEvent != nil { m.testingKnobs.TestingLeasesRefreshedEvent(cfg) } case <-s.ShouldStop(): return } } }) }
// Truncate deletes all rows from a table. // Privileges: DROP on table. // Notes: postgres requires TRUNCATE. // mysql requires DROP (for mysql >= 5.1.16, DELETE before that). func (p *planner) Truncate(n *parser.Truncate) (planNode, *roachpb.Error) { b := client.Batch{} for _, tableQualifiedName := range n.Tables { tableDesc, pErr := p.getTableLease(tableQualifiedName) if pErr != nil { return nil, pErr } if err := p.checkPrivilege(&tableDesc, privilege.DROP); err != nil { return nil, roachpb.NewError(err) } tablePrefix := keys.MakeTablePrefix(uint32(tableDesc.ID)) // Delete rows and indexes starting with the table's prefix. tableStartKey := roachpb.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if log.V(2) { log.Infof("DelRange %s - %s", tableStartKey, tableEndKey) } b.DelRange(tableStartKey, tableEndKey, false) } if pErr := p.txn.Run(&b); pErr != nil { return nil, pErr } return &emptyNode{}, nil }
func (z *zeroSum) monkey(tableID uint32, d time.Duration) { r := newRand() zipf := z.accountDistribution(r) for { time.Sleep(time.Duration(rand.Float64() * float64(d))) key := keys.MakeTablePrefix(tableID) key = encoding.EncodeVarintAscending(key, int64(zipf.Uint64())) key = keys.MakeRowSentinelKey(key) switch r.Intn(2) { case 0: if err := z.split(z.randNode(r.Intn), key); err != nil { if strings.Contains(err.Error(), "range is already split at key") || strings.Contains(err.Error(), "conflict updating range descriptors") { continue } z.maybeLogError(err) } else { atomic.AddUint64(&z.stats.splits, 1) } case 1: if transferred, err := z.transferLease(z.randNode(r.Intn), r, key); err != nil { z.maybeLogError(err) } else if transferred { atomic.AddUint64(&z.stats.transfers, 1) } } } }
// TestStoreRangeSplitWithMaxBytesUpdate tests a scenario where a new // zone config that updates the max bytes is set and triggers a range // split. func TestStoreRangeSplitWithMaxBytesUpdate(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) config.TestingSetupZoneConfigHook(stopper) defer stopper.Stop() origRng := store.LookupReplica(roachpb.RKeyMin, nil) // Set max bytes. maxBytes := int64(1 << 16) config.TestingSetZoneConfig(1000, &config.ZoneConfig{RangeMaxBytes: maxBytes}) // Trigger gossip callback. if err := store.Gossip().AddInfoProto(gossip.KeySystemConfig, &config.SystemConfig{}, 0); err != nil { t.Fatal(err) } // Verify that the range is split and the new range has the correct max bytes. util.SucceedsWithin(t, time.Second, func() error { newRng := store.LookupReplica(keys.MakeTablePrefix(1000), nil) if newRng.Desc().RangeID == origRng.Desc().RangeID { return util.Errorf("expected new range created by split") } if newRng.GetMaxBytes() != maxBytes { return util.Errorf("expected %d max bytes for the new range, but got %d", maxBytes, newRng.GetMaxBytes()) } return nil }) }
// MakeZoneKey returns the key for 'id's entry in the system.zones table. func MakeZoneKey(id ID) roachpb.Key { k := keys.MakeTablePrefix(uint32(ZonesTable.ID)) k = encoding.EncodeUvarint(k, uint64(ZonesTable.PrimaryIndex.ID)) k = encoding.EncodeUvarint(k, uint64(id)) k = encoding.EncodeUvarint(k, uint64(ZonesTable.Columns[1].ID)) return k }
// MakeDescMetadataKey returns the key for the descriptor. func MakeDescMetadataKey(descID ID) roachpb.Key { k := keys.MakeTablePrefix(uint32(DescriptorTable.ID)) k = encoding.EncodeUvarint(k, uint64(DescriptorTable.PrimaryIndex.ID)) k = encoding.EncodeUvarint(k, uint64(descID)) k = encoding.EncodeUvarint(k, uint64(DescriptorTable.Columns[1].ID)) return k }
// Truncate deletes all rows from a table. // Privileges: DROP on table. // Notes: postgres requires TRUNCATE. // mysql requires DROP (for mysql >= 5.1.16, DELETE before that). func (p *planner) Truncate(n *parser.Truncate) (planNode, error) { b := client.Batch{} for _, tableQualifiedName := range n.Tables { tableDesc, err := p.getTableDesc(tableQualifiedName) if err != nil { return nil, err } if err := p.checkPrivilege(tableDesc, privilege.DROP); err != nil { return nil, err } tablePrefix := keys.MakeTablePrefix(uint32(tableDesc.ID)) // Delete rows and indexes starting with the table's prefix. tableStartKey := proto.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if log.V(2) { log.Infof("DelRange %s - %s", prettyKey(tableStartKey, 0), prettyKey(tableEndKey, 0)) } b.DelRange(tableStartKey, tableEndKey) } if err := p.txn.Run(&b); err != nil { return nil, err } return &valuesNode{}, nil }
// ComputeSplitKeys takes a start and end key and returns an array of keys // at which to split the span [start, end). // The only required splits are at each user table prefix. func (s SystemConfig) ComputeSplitKeys(startKey, endKey roachpb.RKey) []roachpb.RKey { testingLock.Lock() tableSplitsDisabled := testingDisableTableSplits testingLock.Unlock() if tableSplitsDisabled { return nil } tableStart := roachpb.RKey(keys.UserTableDataMin) if !tableStart.Less(endKey) { // This range is before the user tables span: no required splits. return nil } startID, ok := ObjectIDForKey(startKey) if !ok || startID <= keys.MaxReservedDescID { // The start key is either: // - not part of the structured data span // - part of the system span // In either case, start looking for splits at the first ID usable // by the user data span. startID = keys.MaxReservedDescID + 1 } else { // The start key is either already a split key, or after the split // key for its ID. We can skip straight to the next one. startID++ } // Find the largest object ID. // We can't keep splitting until we reach endKey as it could be roachpb.KeyMax. endID, err := s.GetLargestObjectID() if err != nil { log.Errorf("unable to determine largest object ID from system config: %s", err) return nil } // Build key prefixes for sequential table IDs until we reach endKey. var splitKeys []roachpb.RKey var key roachpb.RKey // endID could be smaller than startID if we don't have user tables. for id := startID; id <= endID; id++ { key = keys.MakeTablePrefix(id) // Skip if the range starts on a split key. if !startKey.Less(key) { continue } // Handle the case where EndKey is already a table prefix. if !key.Less(endKey) { break } splitKeys = append(splitKeys, key) } return splitKeys }
// RefreshLeases starts a goroutine that refreshes the lease manager // leases for tables received in the latest system configuration via gossip. func (m *LeaseManager) RefreshLeases(s *stop.Stopper, db *client.DB, gossip *gossip.Gossip) { s.RunWorker(func() { descKeyPrefix := keys.MakeTablePrefix(uint32(DescriptorTable.ID)) gossip.RegisterSystemConfigCallback(m.updateSystemConfig) for { select { case <-m.newConfig: // Read all tables and their versions cfg := m.getSystemConfig() if log.V(2) { log.Info("received a new config %v", cfg) } // Loop through the configuration to find all the tables. for _, kv := range cfg.Values { if kv.Value.Tag != roachpb.ValueType_BYTES { continue } if !bytes.HasPrefix(kv.Key, descKeyPrefix) { continue } // Attempt to unmarshal config into a table/database descriptor. var descriptor Descriptor if err := kv.Value.GetProto(&descriptor); err != nil { log.Warningf("unable to unmarshal descriptor %v", kv.Value) continue } switch union := descriptor.Union.(type) { case *Descriptor_Table: table := union.Table if err := table.Validate(); err != nil { log.Errorf("received invalid table descriptor: %v", table) continue } if log.V(2) { log.Infof("refreshing lease table: %d, version: %d", table.ID, table.Version) } // Try to refresh the table lease to one >= this version. if err := m.refreshLease(db, table.ID, table.Version); err != nil { log.Warning(err) } case *Descriptor_Database: // Ignore. } } case <-s.ShouldStop(): return } } }) }
// MakeNameMetadataKey returns the key for the name. Pass name == "" in order // to generate the prefix key to use to scan over all of the names for the // specified parentID. func MakeNameMetadataKey(parentID ID, name string) proto.Key { name = normalizeName(name) k := keys.MakeTablePrefix(uint32(NamespaceTable.ID)) k = encoding.EncodeUvarint(k, uint64(NamespaceTable.PrimaryIndex.ID)) k = encoding.EncodeUvarint(k, uint64(parentID)) if name != "" { k = encoding.EncodeBytes(k, []byte(name)) k = encoding.EncodeUvarint(k, uint64(NamespaceTable.Columns[2].ID)) } return k }
// checkTableSize checks that the number of key:value pairs stored // in the table equals e. func (mt mutationTest) checkTableSize(e int) { // Check that there are no hidden values tablePrefix := keys.MakeTablePrefix(uint32(mt.tableDesc.ID)) tableStartKey := roachpb.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if kvs, err := mt.kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil { mt.Error(err) } else if len(kvs) != e { mt.Errorf("expected %d key value pairs, but got %d", e, len(kvs)) } }
// MakeNameMetadataKey returns the key for the name. Pass name == "" in order // to generate the prefix key to use to scan over all of the names for the // specified parentID. func MakeNameMetadataKey(parentID ID, name string) roachpb.Key { name = NormalizeName(name) k := keys.MakeTablePrefix(uint32(namespaceTable.ID)) k = encoding.EncodeUvarintAscending(k, uint64(namespaceTable.PrimaryIndex.ID)) k = encoding.EncodeUvarintAscending(k, uint64(parentID)) if name != "" { k = encoding.EncodeBytesAscending(k, []byte(name)) k = keys.MakeColumnKey(k, uint32(namespaceTable.Columns[2].ID)) } return k }
// TestStoreSetRangesMaxBytes creates a set of ranges via splitting // and then sets the config zone to a custom max bytes value to // verify the ranges' max bytes are updated appropriately. func TestStoreSetRangesMaxBytes(t *testing.T) { defer leaktest.AfterTest(t) store, _, stopper := createTestStore(t) defer stopper.Stop() testData := []struct { rng *Replica expMaxBytes int64 }{ {store.LookupReplica(roachpb.KeyMin, nil), config.DefaultZoneConfig.RangeMaxBytes}, {splitTestRange(store, roachpb.KeyMin, keys.MakeTablePrefix(1000), t), 1 << 20}, {splitTestRange(store, keys.MakeTablePrefix(1000), keys.MakeTablePrefix(1001), t), config.DefaultZoneConfig.RangeMaxBytes}, {splitTestRange(store, keys.MakeTablePrefix(1001), keys.MakeTablePrefix(1002), t), 2 << 20}, } // Set zone configs. config.TestingSetZoneConfig(1000, &config.ZoneConfig{RangeMaxBytes: 1 << 20}) config.TestingSetZoneConfig(1002, &config.ZoneConfig{RangeMaxBytes: 2 << 20}) // Despite faking the zone configs, we still need to have a gossip entry. if err := store.Gossip().AddInfoProto(gossip.KeySystemConfig, &config.SystemConfig{}, 0); err != nil { t.Fatal(err) } if err := util.IsTrueWithin(func() bool { for _, test := range testData { if test.rng.GetMaxBytes() != test.expMaxBytes { return false } } return true }, 500*time.Millisecond); err != nil { t.Errorf("range max bytes values did not change as expected: %s", err) } }
// truncateTable truncates the data of a table. // It deletes a range of data for the table, which includes the PK and all // indexes. func truncateTable(tableDesc *sqlbase.TableDescriptor, txn *client.Txn) error { tablePrefix := keys.MakeTablePrefix(uint32(tableDesc.ID)) // Delete rows and indexes starting with the table's prefix. tableStartKey := roachpb.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() if log.V(2) { log.Infof("DelRange %s - %s", tableStartKey, tableEndKey) } b := client.Batch{} b.DelRange(tableStartKey, tableEndKey, false) return txn.Run(&b) }
// TestStoreRangeSplitInsideRow verifies an attempt to split a range inside of // a table row will cause a split at a boundary between rows. func TestStoreRangeSplitInsideRow(t *testing.T) { defer leaktest.AfterTest(t)() sCtx := storage.TestStoreContext() sCtx.TestingKnobs.DisableSplitQueue = true store, stopper, _ := createTestStoreWithContext(t, sCtx) defer stopper.Stop() // Manually create some the column keys corresponding to the table: // // CREATE TABLE t (id STRING PRIMARY KEY, col1 INT, col2 INT) tableKey := keys.MakeTablePrefix(keys.MaxReservedDescID + 1) rowKey := roachpb.Key(encoding.EncodeVarintAscending(append([]byte(nil), tableKey...), 1)) rowKey = encoding.EncodeStringAscending(encoding.EncodeVarintAscending(rowKey, 1), "a") col1Key := keys.MakeFamilyKey(append([]byte(nil), rowKey...), 1) col2Key := keys.MakeFamilyKey(append([]byte(nil), rowKey...), 2) // We don't care about the value, so just store any old thing. if err := store.DB().Put(col1Key, "column 1"); err != nil { t.Fatal(err) } if err := store.DB().Put(col2Key, "column 2"); err != nil { t.Fatal(err) } // Split between col1Key and col2Key by splitting before col2Key. args := adminSplitArgs(col2Key, col2Key) _, err := client.SendWrapped(rg1(store), nil, &args) if err != nil { t.Fatalf("%s: split unexpected error: %s", col1Key, err) } rng1 := store.LookupReplica(col1Key, nil) rng2 := store.LookupReplica(col2Key, nil) // Verify the two columns are still on the same range. if !reflect.DeepEqual(rng1, rng2) { t.Fatalf("%s: ranges differ: %+v vs %+v", roachpb.Key(col1Key), rng1, rng2) } // Verify we split on a row key. if startKey := rng1.Desc().StartKey; !startKey.Equal(rowKey) { t.Fatalf("%s: expected split on %s, but found %s", roachpb.Key(col1Key), roachpb.Key(rowKey), startKey) } // Verify the previous range was split on a row key. rng3 := store.LookupReplica(tableKey, nil) if endKey := rng3.Desc().EndKey; !endKey.Equal(rowKey) { t.Fatalf("%s: expected split on %s, but found %s", roachpb.Key(col1Key), roachpb.Key(rowKey), endKey) } }
func allSQLDescriptors(txn *client.Txn) ([]sqlbase.Descriptor, error) { startKey := roachpb.Key(keys.MakeTablePrefix(keys.DescriptorTableID)) endKey := startKey.PrefixEnd() // TODO(dan): Iterate with some batch size. rows, err := txn.Scan(startKey, endKey, 0) if err != nil { return nil, errors.Wrap(err, "unable to scan SQL descriptors") } sqlDescs := make([]sqlbase.Descriptor, len(rows)) for i, row := range rows { if err := row.ValueProto(&sqlDescs[i]); err != nil { return nil, errors.Wrapf(err, "%s: unable to unmarshal SQL descriptor", row.Key) } } return sqlDescs, nil }
// GetTableSpan gets the key span for a SQL table, including any indices. func (ie InternalExecutor) GetTableSpan(user string, txn *client.Txn, dbName, tableName string) (roachpb.Span, error) { // Lookup the table ID. p := makeInternalPlanner(txn, user) p.leaseMgr = ie.LeaseManager tn := parser.TableName{DatabaseName: parser.Name(dbName), TableName: parser.Name(tableName)} tableID, err := getTableID(p, &tn) if err != nil { return roachpb.Span{}, err } // Determine table data span. tablePrefix := keys.MakeTablePrefix(uint32(tableID)) tableStartKey := roachpb.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() return roachpb.Span{Key: tableStartKey, EndKey: tableEndKey}, nil }
// TestStoreRangeSplitAtIllegalKeys verifies a range cannot be split // at illegal keys. func TestStoreRangeSplitAtIllegalKeys(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) defer stopper.Stop() for _, key := range []roachpb.Key{ keys.Meta1Prefix, keys.MakeKey(keys.Meta1Prefix, []byte("a")), keys.MakeKey(keys.Meta1Prefix, roachpb.RKeyMax), keys.Meta2KeyMax, keys.MakeTablePrefix(10 /* system descriptor ID */), } { args := adminSplitArgs(roachpb.KeyMin, key) _, err := client.SendWrapped(rg1(store), nil, &args) if err == nil { t.Fatalf("%q: split succeeded unexpectedly", key) } } }
// TestStoreRangeSplitAtIllegalKeys verifies a range cannot be split // at illegal keys. func TestStoreRangeSplitAtIllegalKeys(t *testing.T) { defer leaktest.AfterTest(t)() store, stopper, _ := createTestStore(t) defer stopper.Stop() for _, key := range []roachpb.Key{ keys.Meta1Prefix, testutils.MakeKey(keys.Meta1Prefix, []byte("a")), testutils.MakeKey(keys.Meta1Prefix, roachpb.RKeyMax), keys.Meta2KeyMax, keys.MakeTablePrefix(10 /* system descriptor ID */), } { args := adminSplitArgs(roachpb.KeyMin, key) _, pErr := client.SendWrapped(rg1(store), nil, &args) if !testutils.IsPError(pErr, "cannot split") { t.Errorf("%q: unexpected split error %s", key, pErr) } } }
// TestStoreRangeSplitAtIllegalKeys verifies a range cannot be split // at illegal keys. func TestStoreRangeSplitAtIllegalKeys(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) defer stopper.Stop() for _, key := range []proto.Key{ keys.Meta1Prefix, keys.MakeKey(keys.Meta1Prefix, []byte("a")), keys.MakeKey(keys.Meta1Prefix, proto.KeyMax), keys.Meta2KeyMax, keys.MakeTablePrefix(10 /* system descriptor ID */), } { args := adminSplitArgs(proto.KeyMin, key, 1, store.StoreID()) _, err := store.ExecuteCmd(context.Background(), &args) if err == nil { t.Fatalf("%q: split succeeded unexpectedly", key) } } }
// GetTableSpan gets the key span for a SQL table, including any indices. func (ie InternalExecutor) GetTableSpan(user string, txn *client.Txn, dbName, tableName string) (roachpb.Span, error) { // Lookup the table ID. p := makePlanner() p.setTxn(txn) p.session.User = user p.leaseMgr = ie.LeaseManager qname := &parser.QualifiedName{Base: parser.Name(tableName)} if err := qname.NormalizeTableName(dbName); err != nil { return roachpb.Span{}, err } tableID, err := p.getTableID(qname) if err != nil { return roachpb.Span{}, err } // Determine table data span. tablePrefix := keys.MakeTablePrefix(uint32(tableID)) tableStartKey := roachpb.Key(tablePrefix) tableEndKey := tableStartKey.PrefixEnd() return roachpb.Span{Key: tableStartKey, EndKey: tableEndKey}, nil }
// TestSplitOnTableBoundaries verifies that ranges get split // as new tables get created. func TestSplitOnTableBoundaries(t *testing.T) { defer leaktest.AfterTest(t) s, sqlDB, kvDB := setupWithContext(t, getFastScanContext()) defer cleanup(s, sqlDB) num, err := getNumRanges(kvDB) if err != nil { t.Fatalf("failed to retrieve range list: %s", err) } if num != 1 { t.Fatalf("expected no splits, but found %d ranges", num) } if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } // We split up to the largest allocated descriptor ID, be it a table // or a database. util.SucceedsWithin(t, rangeSplitTimeout, func() error { num, err := getNumRanges(kvDB) if err != nil { return err } if e := 2; num != e { return util.Errorf("expected %d splits, found %d", e, num) } return nil }) // Verify the actual splits. objectID := uint32(keys.MaxReservedDescID + 1) splits := []roachpb.RKey{keys.MakeTablePrefix(objectID), roachpb.RKeyMax} ranges, err := getRangeKeys(kvDB) if err != nil { t.Fatal(err) } if !rangesMatchSplits(ranges, splits) { t.Fatalf("Found ranges: %v\nexpected: %v", ranges, splits) } // Let's create a table. if _, err := sqlDB.Exec(`CREATE TABLE test.test (k INT PRIMARY KEY, v INT)`); err != nil { t.Fatal(err) } util.SucceedsWithin(t, rangeSplitTimeout, func() error { num, err := getNumRanges(kvDB) if err != nil { return err } if e := 3; num != e { return util.Errorf("expected %d splits, found %d", e, num) } return nil }) // Verify the actual splits. splits = []roachpb.RKey{keys.MakeTablePrefix(objectID), keys.MakeTablePrefix(objectID + 1), roachpb.RKeyMax} ranges, err = getRangeKeys(kvDB) if err != nil { t.Fatal(err) } if !rangesMatchSplits(ranges, splits) { t.Fatalf("Found ranges: %v\nexpected: %v", ranges, splits) } }
// TestStoreRangeSystemSplits verifies that splits are based on the // contents of the SystemDB span. func TestStoreRangeSystemSplits(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) defer stopper.Stop() initialSystemValues := sql.MakeMetadataSchema().GetInitialValues() numInitialValues := len(initialSystemValues) // Write the initial sql values to the system DB as well // as the equivalent of table descriptors for X user tables. // This does two things: // - descriptor IDs are used to determine split keys // - the write triggers a SystemConfig update and gossip. // We should end up with splits at each user table prefix. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger() for i, kv := range initialSystemValues { bytes, err := kv.Value.GetBytes() if err != nil { log.Info(err) continue } if err := txn.Put(kv.Key, bytes); err != nil { return err } descID := keys.MaxReservedDescID + i + 1 // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(descID)) if err := txn.Put(k, bytes); err != nil { return err } } return nil }); err != nil { t.Fatal(err) } verifySplitsAtTablePrefixes := func(maxTableID int) { // We expect splits at each of the user tables, but not at the system // tables boundaries. expKeys := make([]roachpb.Key, 0, maxTableID+1) for i := 1; i <= maxTableID; i++ { expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, keys.MakeTablePrefix(keys.MaxReservedDescID+uint32(i))), ) } expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, roachpb.RKeyMax)) util.SucceedsWithinDepth(1, t, 5*time.Second, func() error { rows, err := store.DB().Scan(keys.Meta2Prefix, keys.MetaMax, 0) if err != nil { return err } keys := make([]roachpb.Key, 0, len(expKeys)) for _, r := range rows { keys = append(keys, r.Key) } if !reflect.DeepEqual(keys, expKeys) { return util.Errorf("expected split keys:\n%v\nbut found:\n%v", expKeys, keys) } return nil }) } verifySplitsAtTablePrefixes(len(initialSystemValues)) numTotalValues := numInitialValues + 5 // Write another, disjoint descriptor for a user table. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemDBTrigger() // This time, only write the last table descriptor. Splits // still occur for every intervening ID. // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + numTotalValues)) return txn.Put(k, &sql.TableDescriptor{}) }); err != nil { t.Fatal(err) } verifySplitsAtTablePrefixes(numTotalValues) }
// TestStoreRangeSplitStats starts by splitting the system keys from user-space // keys and verifying that the user space side of the split (which is empty), // has all zeros for stats. It then writes random data to the user space side, // splits it halfway and verifies the two splits have stats exactly equaling // the pre-split. func TestStoreRangeSplitStats(t *testing.T) { defer leaktest.AfterTest(t) store, stopper := createTestStore(t) defer stopper.Stop() // Split the range after the last table data key. keyPrefix := keys.MakeTablePrefix(keys.MaxReservedDescID + 1) keyPrefix = keys.MakeNonColumnKey(keyPrefix) args := adminSplitArgs(roachpb.KeyMin, keyPrefix) if _, err := client.SendWrapped(rg1(store), nil, &args); err != nil { t.Fatal(err) } // Verify empty range has empty stats. rng := store.LookupReplica(keyPrefix, nil) // NOTE that this value is expected to change over time, depending on what // we store in the sys-local keyspace. Update it accordingly for this test. if err := verifyRangeStats(store.Engine(), rng.Desc().RangeID, engine.MVCCStats{}); err != nil { t.Fatal(err) } // Write random data. src := rand.New(rand.NewSource(0)) for i := 0; i < 100; i++ { key := append([]byte(nil), keyPrefix...) key = append(key, randutil.RandBytes(src, int(src.Int31n(1<<7)))...) key = keys.MakeNonColumnKey(key) val := randutil.RandBytes(src, int(src.Int31n(1<<8))) pArgs := putArgs(key, val) if _, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rng.Desc().RangeID, }, &pArgs); err != nil { t.Fatal(err) } } // Get the range stats now that we have data. var ms engine.MVCCStats if err := engine.MVCCGetRangeStats(store.Engine(), rng.Desc().RangeID, &ms); err != nil { t.Fatal(err) } // Split the range at approximate halfway point ("Z" in string "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"). midKey := append([]byte(nil), keyPrefix...) midKey = append(midKey, []byte("Z")...) midKey = keys.MakeNonColumnKey(midKey) args = adminSplitArgs(keyPrefix, midKey) if _, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rng.Desc().RangeID, }, &args); err != nil { t.Fatal(err) } var msLeft, msRight engine.MVCCStats if err := engine.MVCCGetRangeStats(store.Engine(), rng.Desc().RangeID, &msLeft); err != nil { t.Fatal(err) } rngRight := store.LookupReplica(midKey, nil) if err := engine.MVCCGetRangeStats(store.Engine(), rngRight.Desc().RangeID, &msRight); err != nil { t.Fatal(err) } // The stats should be exactly equal when added. expMS := engine.MVCCStats{ LiveBytes: msLeft.LiveBytes + msRight.LiveBytes, KeyBytes: msLeft.KeyBytes + msRight.KeyBytes, ValBytes: msLeft.ValBytes + msRight.ValBytes, IntentBytes: msLeft.IntentBytes + msRight.IntentBytes, LiveCount: msLeft.LiveCount + msRight.LiveCount, KeyCount: msLeft.KeyCount + msRight.KeyCount, ValCount: msLeft.ValCount + msRight.ValCount, IntentCount: msLeft.IntentCount + msRight.IntentCount, } ms.SysBytes, ms.SysCount = 0, 0 if !reflect.DeepEqual(expMS, ms) { t.Errorf("expected left and right ranges to equal original: %+v + %+v != %+v", msLeft, msRight, ms) } }