本文整理汇总了Golang中github.com/cockroachdb/cockroach/sql.MakeDescMetadataKey函数的典型用法代码示例。如果您正苦于以下问题:Golang MakeDescMetadataKey函数的具体用法?Golang MakeDescMetadataKey怎么用?Golang MakeDescMetadataKey使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了MakeDescMetadataKey函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: TestInsert
func TestInsert(t *testing.T) {
defer leaktest.AfterTest(t)
s, sqlDB, kvDB := setup(t)
defer cleanup(s, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.kv (
k CHAR PRIMARY KEY,
v CHAR,
CONSTRAINT a INDEX (k, v),
CONSTRAINT b UNIQUE (v)
);
INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd');
`); err != nil {
t.Fatal(err)
}
// The first `MaxReservedDescID` (plus 0) are set aside.
nameKey := sql.MakeNameMetadataKey(sql.MaxReservedDescID+1, "kv")
gr, err := kvDB.Get(nameKey)
if err != nil {
t.Fatal(err)
}
if !gr.Exists() {
t.Fatalf("TableDescriptor %q does not exist", nameKey)
}
descKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt()))
desc := sql.TableDescriptor{}
if err := kvDB.GetProto(descKey, &desc); err != nil {
t.Fatal(err)
}
var tablePrefix []byte
tablePrefix = append(tablePrefix, keys.TableDataPrefix...)
tablePrefix = encoding.EncodeUvarint(tablePrefix, uint64(desc.ID))
tableStartKey := proto.Key(tablePrefix)
tableEndKey := tableStartKey.PrefixEnd()
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 12; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
// Insert that will fail after the index `a` is written.
if _, err := sqlDB.Exec(`INSERT INTO t.kv VALUES ('d', 'd')`); !testutils.IsError(err, "duplicate key value .* violates unique constraint") {
t.Fatalf("unexpected error %s", err)
}
// Verify nothing was written.
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 12; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
}
开发者ID:nkhuyu,项目名称:cockroach,代码行数:59,代码来源:insert_test.go
示例2: TestDelete
func TestDelete(t *testing.T) {
defer leaktest.AfterTest(t)
s, sqlDB, kvDB := setup(t)
defer cleanup(s, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.kv (
k CHAR PRIMARY KEY,
v CHAR,
CONSTRAINT a UNIQUE (v)
);
INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd');
`); err != nil {
t.Fatal(err)
}
// The first `MaxReservedDescID` (plus 0) are set aside.
nameKey := sql.MakeNameMetadataKey(sql.MaxReservedDescID+1, "kv")
gr, err := kvDB.Get(nameKey)
if err != nil {
t.Fatal(err)
}
if !gr.Exists() {
t.Fatalf("TableDescriptor %q does not exist", nameKey)
}
descKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt()))
desc := sql.TableDescriptor{}
if err := kvDB.GetProto(descKey, &desc); err != nil {
t.Fatal(err)
}
var tablePrefix []byte
tablePrefix = append(tablePrefix, keys.TableDataPrefix...)
tablePrefix = encoding.EncodeUvarint(tablePrefix, uint64(desc.ID))
tableStartKey := proto.Key(tablePrefix)
tableEndKey := tableStartKey.PrefixEnd()
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 9; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if _, err := sqlDB.Exec(`DELETE FROM t.kv`); err != nil {
t.Fatal(err)
}
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 0; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
}
开发者ID:nkhuyu,项目名称:cockroach,代码行数:56,代码来源:delete_test.go
示例3: TestStoreRangeSplitAtTablePrefix
// TestStoreRangeSplitAtTablePrefix verifies a range can be split at
// UserTableDataMin and still gossip the SystemConfig properly.
func TestStoreRangeSplitAtTablePrefix(t *testing.T) {
defer leaktest.AfterTest(t)
defer config.TestingDisableTableSplits()()
store, stopper := createTestStore(t)
defer stopper.Stop()
key := keys.MakeNonColumnKey(append([]byte(nil), keys.UserTableDataMin...))
args := adminSplitArgs(key, key)
_, err := client.SendWrapped(rg1(store), nil, &args)
if err != nil {
t.Fatalf("%q: split unexpected error: %s", key, err)
}
desc := &sql.TableDescriptor{}
descBytes, err := desc.Marshal()
if err != nil {
t.Fatal(err)
}
// Update SystemConfig to trigger gossip.
if err := store.DB().Txn(func(txn *client.Txn) error {
txn.SetSystemConfigTrigger()
// We don't care about the values, just the keys.
k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + 1))
return txn.Put(k, desc)
}); err != nil {
t.Fatal(err)
}
successChan := make(chan struct{}, 1)
store.Gossip().RegisterCallback(gossip.KeySystemConfig, func(_ string, content roachpb.Value) {
contentBytes, err := content.GetBytes()
if err != nil {
t.Fatal(err)
}
if bytes.Contains(contentBytes, descBytes) {
select {
case successChan <- struct{}{}:
default:
}
}
})
select {
case <-time.After(time.Second):
t.Errorf("expected a schema gossip containing %q, but did not see one", descBytes)
case <-successChan:
}
}
开发者ID:aresLove,项目名称:cockroach,代码行数:51,代码来源:client_split_test.go
示例4: TestStoreRangeSplitAtTablePrefix
// TestStoreRangeSplitAtTablePrefix verifies a range can be split
// at TableDataPrefix and still gossip the SystemConfig properly.
func TestStoreRangeSplitAtTablePrefix(t *testing.T) {
defer leaktest.AfterTest(t)
store, stopper := createTestStore(t)
defer stopper.Stop()
key := keys.TableDataPrefix
args := adminSplitArgs(key, key)
_, err := client.SendWrapped(rg1(store), nil, &args)
if err != nil {
t.Fatalf("%q: split unexpected error: %s", key, err)
}
// Update SystemConfig to trigger gossip.
if err := store.DB().Txn(func(txn *client.Txn) error {
txn.SetSystemDBTrigger()
k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + 1))
return txn.Put(k, 10)
}); err != nil {
t.Fatal(err)
}
}
开发者ID:nporsche,项目名称:cockroach,代码行数:23,代码来源:client_split_test.go
示例5: TestSystemDBGossip
func TestSystemDBGossip(t *testing.T) {
defer leaktest.AfterTest(t)
s := StartTestServer(t)
defer s.Stop()
resultChan := make(chan roachpb.Value)
var count int32
db := s.db
key := sql.MakeDescMetadataKey(keys.MaxReservedDescID)
valAt := func(i int) *sql.DatabaseDescriptor {
return &sql.DatabaseDescriptor{Name: "foo", ID: sql.ID(i)}
}
// Register a callback for gossip updates.
s.Gossip().RegisterCallback(gossip.KeySystemConfig, func(_ string, content roachpb.Value) {
newCount := atomic.AddInt32(&count, 1)
if newCount != 2 {
// RegisterCallback calls us right away with the contents,
// so ignore the very first call.
// We also only want the first value of all our writes.
return
}
resultChan <- content
})
// The span only gets gossiped when it first shows up, or when
// the EndTransaction trigger is set.
// Try a plain KV write first.
if err := db.Put(key, valAt(0)); err != nil {
t.Fatal(err)
}
// Now do it as part of a transaction, but without the trigger set.
if err := db.Txn(func(txn *client.Txn) error {
return txn.Put(key, valAt(1))
}); err != nil {
t.Fatal(err)
}
// This time mark the transaction as having a SystemDB trigger.
if err := db.Txn(func(txn *client.Txn) error {
txn.SetSystemDBTrigger()
return txn.Put(key, valAt(2))
}); err != nil {
t.Fatal(err)
}
// Wait for the callback.
var systemConfig config.SystemConfig
select {
case content := <-resultChan:
if err := content.GetProto(&systemConfig); err != nil {
t.Fatal(err)
}
case <-time.After(500 * time.Millisecond):
t.Fatal("did not receive gossip callback")
}
// Now check the gossip callback.
var val *roachpb.Value
for _, kv := range systemConfig.Values {
if bytes.Equal(key, kv.Key) {
val = &kv.Value
break
}
}
if val == nil {
t.Fatal("key not found in gossiped info")
}
// Make sure the returned value is valAt(2).
var got sql.DatabaseDescriptor
if err := val.GetProto(&got); err != nil {
t.Fatal(err)
}
if got.ID != 2 {
t.Fatalf("mismatch: expected %+v, got %+v", valAt(2), got)
}
}
开发者ID:mbertschler,项目名称:cockroach,代码行数:80,代码来源:server_test.go
示例6: TestStoreRangeSystemSplits
// TestStoreRangeSystemSplits verifies that splits are based on the contents of
// the SystemConfig span.
func TestStoreRangeSystemSplits(t *testing.T) {
defer leaktest.AfterTest(t)()
store, stopper, _ := createTestStore(t)
defer stopper.Stop()
schema := sql.MakeMetadataSchema()
initialSystemValues := schema.GetInitialValues()
var userTableMax int
// 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 pErr := store.DB().Txn(func(txn *client.Txn) *roachpb.Error {
prefix := keys.MakeTablePrefix(keys.DescriptorTableID)
txn.SetSystemConfigTrigger()
for i, kv := range initialSystemValues {
if !bytes.HasPrefix(kv.Key, prefix) {
continue
}
bytes, err := kv.Value.GetBytes()
if err != nil {
log.Info(err)
continue
}
if pErr := txn.Put(kv.Key, bytes); pErr != nil {
return pErr
}
descID := keys.MaxReservedDescID + i + 1
userTableMax = i + 1
// We don't care about the values, just the keys.
k := sql.MakeDescMetadataKey(sql.ID(descID))
if pErr := txn.Put(k, bytes); pErr != nil {
return pErr
}
}
return nil
}); pErr != nil {
t.Fatal(pErr)
}
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+2)
// We can't simply set numReservedTables to schema.TableCount(), because
// some system tables are created at cluster bootstrap time. So, before the
// cluster bootstrap, TableCount() will return a value that's too low.
numReservedTables := schema.MaxTableID() - keys.MaxSystemConfigDescID
for i := 1; i <= int(numReservedTables); i++ {
expKeys = append(expKeys,
testutils.MakeKey(keys.Meta2Prefix,
keys.MakeTablePrefix(keys.MaxSystemConfigDescID+uint32(i))),
)
}
for i := 1; i <= maxTableID; i++ {
expKeys = append(expKeys,
testutils.MakeKey(keys.Meta2Prefix, keys.MakeTablePrefix(keys.MaxReservedDescID+uint32(i))),
)
}
expKeys = append(expKeys, testutils.MakeKey(keys.Meta2Prefix, roachpb.RKeyMax))
util.SucceedsSoonDepth(1, t, func() error {
rows, pErr := store.DB().Scan(keys.Meta2Prefix, keys.MetaMax, 0)
if pErr != nil {
return pErr.GoError()
}
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(userTableMax)
numTotalValues := keys.MaxSystemConfigDescID + 5
// Write another, disjoint descriptor for a user table.
if pErr := store.DB().Txn(func(txn *client.Txn) *roachpb.Error {
txn.SetSystemConfigTrigger()
// 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{})
}); pErr != nil {
t.Fatal(pErr)
}
//.........这里部分代码省略.........
开发者ID:chzyer-dev,项目名称:cockroach,代码行数:101,代码来源:client_split_test.go
示例7: TestCommandsWithPendingMutations
func TestCommandsWithPendingMutations(t *testing.T) {
defer leaktest.AfterTest(t)
// The descriptor changes made must have an immediate effect
// so disable leases on tables.
defer csql.TestDisableTableLeases()()
// Disable external processing of mutations.
defer csql.TestDisableAsyncSchemaChangeExec()()
server, sqlDB, kvDB := setup(t)
defer cleanup(server, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (a CHAR PRIMARY KEY, b CHAR, c CHAR, INDEX foo (c));
`); err != nil {
t.Fatal(err)
}
// Read table descriptor
nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test")
gr, err := kvDB.Get(nameKey)
if err != nil {
t.Fatal(err)
}
if !gr.Exists() {
t.Fatalf("Name entry %q does not exist", nameKey)
}
descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt()))
desc := &csql.Descriptor{}
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
mt := mutationTest{
T: t,
kvDB: kvDB,
sqlDB: sqlDB,
descKey: descKey,
desc: desc,
}
// Test CREATE INDEX in the presence of mutations.
// Add index DROP mutation "foo""
mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP})
if _, err := sqlDB.Exec(`CREATE INDEX foo ON t.test (c)`); !testutils.IsError(err, `index "foo" being dropped, try again later`) {
t.Fatal(err)
}
// Make "foo" live.
mt.makeMutationsActive()
// "foo" is being added.
mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD})
if _, err := sqlDB.Exec(`CREATE INDEX foo ON t.test (c)`); !testutils.IsError(err, `duplicate index name: "foo"`) {
t.Fatal(err)
}
// Make "foo" live.
mt.makeMutationsActive()
// Add column DROP mutation "b"
mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP})
if _, err := sqlDB.Exec(`CREATE INDEX bar ON t.test (b)`); !testutils.IsError(err, `index "bar" contains unknown column "b"`) {
t.Fatal(err)
}
// Make "b" live.
mt.makeMutationsActive()
// "b" is being added.
mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD})
// An index referencing a column mutation that is being added
// is allowed to be added.
if _, err := sqlDB.Exec(`CREATE INDEX bar ON t.test (b)`); err != nil {
t.Fatal(err)
}
// Make "b" live.
mt.makeMutationsActive()
// Test DROP INDEX in the presence of mutations.
// Add index DROP mutation "foo""
mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP})
// Noop.
if _, err := sqlDB.Exec(`DROP INDEX [email protected]`); err != nil {
t.Fatal(err)
}
// Make "foo" live.
mt.makeMutationsActive()
// "foo" is being added.
mt.writeIndexMutation("foo", csql.DescriptorMutation{Direction: csql.DescriptorMutation_ADD})
if _, err := sqlDB.Exec(`DROP INDEX [email protected]`); !testutils.IsError(err, `index "foo" in the middle of being added, try again later`) {
t.Fatal(err)
}
// Make "foo" live.
mt.makeMutationsActive()
// Test ALTER TABLE ADD/DROP column in the presence of mutations.
// Add column DROP mutation "b"
mt.writeColumnMutation("b", csql.DescriptorMutation{Direction: csql.DescriptorMutation_DROP})
if _, err := sqlDB.Exec(`ALTER TABLE t.test ADD b CHAR`); !testutils.IsError(err, `column "b" being dropped, try again later`) {
t.Fatal(err)
}
// Noop.
if _, err := sqlDB.Exec(`ALTER TABLE t.test DROP b`); err != nil {
//.........这里部分代码省略.........
开发者ID:billhongs,项目名称:cockroach,代码行数:101,代码来源:descriptor_mutation_test.go
示例8: TestStoreRangeSystemSplits
// 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()
// 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 _, kv := range sql.GetInitialSystemValues() {
if err := txn.Put(kv.Key, kv.Value.GetRawBytes()); err != nil {
return err
}
}
for i := 1; i <= 5; i++ {
// We don't care about the values, just the keys.
k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + i))
v, err := txn.Get(k)
if err != nil {
return err
}
if err := txn.Put(k, v.ValueBytes()); err != nil {
return err
}
}
return nil
}); err != nil {
t.Fatal(err)
}
expKeys := []roachpb.Key{}
for i := 1; i <= 5; i++ {
expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix,
keys.MakeTablePrefix(uint32(keys.MaxReservedDescID+i))))
}
expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, roachpb.RKeyMax))
if err := util.IsTrueWithin(func() bool {
rows, err := store.DB().Scan(keys.Meta2Prefix, keys.MetaMax, 0)
if err != nil {
t.Fatalf("failed to scan meta2 keys: %s", err)
}
var keys []roachpb.Key
for _, r := range rows {
keys = append(keys, r.Key)
}
return reflect.DeepEqual(keys, expKeys)
}, 5*time.Second); err != nil {
t.Errorf("expected splits not found: %s", err)
}
// Write more descriptors for user tables.
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 ID.
// We don't care about the values, just the keys.
k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + 10))
v, err := txn.Get(k)
if err != nil {
return err
}
return txn.Put(k, v.ValueBytes())
}); err != nil {
t.Fatal(err)
}
expKeys = []roachpb.Key{}
for i := 1; i <= 10; i++ {
expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix,
keys.MakeTablePrefix(uint32(keys.MaxReservedDescID+i))))
}
expKeys = append(expKeys, keys.MakeKey(keys.Meta2Prefix, roachpb.RKeyMax))
if err := util.IsTrueWithin(func() bool {
rows, err := store.DB().Scan(keys.Meta2Prefix, keys.MetaMax, 0)
if err != nil {
t.Fatalf("failed to scan meta2 keys: %s", err)
}
var keys []roachpb.Key
for _, r := range rows {
keys = append(keys, r.Key)
}
return reflect.DeepEqual(keys, expKeys)
}, 5*time.Second); err != nil {
t.Errorf("expected splits not found: %s", err)
}
}
开发者ID:nporsche,项目名称:cockroach,代码行数:94,代码来源:client_split_test.go
示例9: TestStoreRangeSystemSplits
// 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)
}
开发者ID:kaustubhkurve,项目名称:cockroach,代码行数:85,代码来源:client_split_test.go
示例10: TestRaceWithBackfill
// Test schema change backfills are not affected by various operations
// that run simultaneously.
func TestRaceWithBackfill(t *testing.T) {
defer leaktest.AfterTest(t)()
server, sqlDB, kvDB := setup(t)
defer cleanup(server, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (k INT PRIMARY KEY, v INT);
`); err != nil {
t.Fatal(err)
}
// Bulk insert.
max_value := 2000
insert := fmt.Sprintf(`INSERT INTO t.test VALUES (%d, %d)`, 0, max_value)
for i := 1; i <= max_value; i++ {
insert += fmt.Sprintf(` ,(%d, %d)`, i, max_value-i)
}
if _, err := sqlDB.Exec(insert); err != nil {
t.Fatal(err)
}
// Read table descriptor for version.
nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test")
gr, pErr := kvDB.Get(nameKey)
if pErr != nil {
t.Fatal(pErr)
}
if !gr.Exists() {
t.Fatalf("Name entry %q does not exist", nameKey)
}
descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt()))
desc := &csql.Descriptor{}
if pErr := kvDB.GetProto(descKey, desc); pErr != nil {
t.Fatal(pErr)
}
version := desc.GetTable().Version
// Run the schema changes in a separate goroutine.
var wg sync.WaitGroup
wg.Add(1)
go func() {
start := timeutil.Now()
// Start schema change that eventually runs a number of backfills.
if _, err := sqlDB.Exec(`
BEGIN;
ALTER TABLE t.test ADD COLUMN x DECIMAL DEFAULT (DECIMAL '1.4');
CREATE UNIQUE INDEX foo ON t.test (v);
END;
`); err != nil {
t.Error(err)
}
t.Logf("schema changes took %v", time.Since(start))
wg.Done()
}()
// Wait until the backfills for the schema changes above have
// started.
util.SucceedsSoon(t, func() error {
if pErr := kvDB.GetProto(descKey, desc); pErr != nil {
t.Fatal(pErr)
}
if desc.GetTable().Version == version+2 {
// Version upgrade has happened, backfills can proceed.
return nil
}
return errors.New("version not updated")
})
// TODO(vivek): uncomment these inserts when #5817 is fixed.
// Insert some new rows in the table while the backfills are running.
//num_values := 5
//for i := 0; i < num_values; i++ {
// t.Logf("inserting a new value into the table")
// if _, err := sqlDB.Exec(`INSERT INTO t.test VALUES($1, $2)`, max_value+i+1, max_value+i+1); err != nil {
// t.Fatal(err)
// }
//}
// Renaming an index in the middle of the backfills will not affect
// the backfills because the above schema changes have the schema change
// lease on the table. All future schema changes have to wait in line for
// the lease.
if _, err := sqlDB.Exec(`
ALTER INDEX [email protected] RENAME TO bar;
`); err != nil {
t.Fatal(err)
}
// Wait until schema changes have completed.
wg.Wait()
// Verify that the index over v is consistent.
rows, err := sqlDB.Query(`SELECT v from [email protected]`)
if err != nil {
t.Fatal(err)
}
//.........这里部分代码省略.........
开发者ID:petermattis,项目名称:cockroach,代码行数:101,代码来源:schema_changer_test.go
示例11: TestDropDatabase
func TestDropDatabase(t *testing.T) {
defer leaktest.AfterTest(t)
s, sqlDB, kvDB := setup(t)
defer cleanup(s, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR);
INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd');
`); err != nil {
t.Fatal(err)
}
dbNameKey := sql.MakeNameMetadataKey(sql.RootNamespaceID, "t")
r, err := kvDB.Get(dbNameKey)
if err != nil {
t.Fatal(err)
}
if !r.Exists() {
t.Fatalf(`database "t" does not exist`)
}
dbDescKey := sql.MakeDescMetadataKey(sql.ID(r.ValueInt()))
dbDesc := sql.DatabaseDescriptor{}
if err := kvDB.GetProto(dbDescKey, &dbDesc); err != nil {
t.Fatal(err)
}
tbNameKey := sql.MakeNameMetadataKey(dbDesc.ID, "kv")
gr, err := kvDB.Get(tbNameKey)
if err != nil {
t.Fatal(err)
}
if !gr.Exists() {
t.Fatalf(`table "kv" does not exist`)
}
tbDescKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt()))
tbDesc := sql.TableDescriptor{}
if err := kvDB.GetProto(tbDescKey, &tbDesc); err != nil {
t.Fatal(err)
}
var tablePrefix []byte
tablePrefix = append(tablePrefix, keys.TableDataPrefix...)
tablePrefix = encoding.EncodeUvarint(tablePrefix, uint64(tbDesc.ID))
tableStartKey := proto.Key(tablePrefix)
tableEndKey := tableStartKey.PrefixEnd()
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 6; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if _, err := sqlDB.Exec(`DROP DATABASE t`); err != nil {
t.Fatal(err)
}
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 0; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if gr, err := kvDB.Get(tbDescKey); err != nil {
t.Fatal(err)
} else if gr.Exists() {
t.Fatalf("table descriptor still exists after database is dropped")
}
if gr, err := kvDB.Get(tbNameKey); err != nil {
t.Fatal(err)
} else if gr.Exists() {
t.Fatalf("table descriptor key still exists after database is dropped")
}
if gr, err := kvDB.Get(dbDescKey); err != nil {
t.Fatal(err)
} else if gr.Exists() {
t.Fatalf("database descriptor still exists after database is dropped")
}
if gr, err := kvDB.Get(dbNameKey); err != nil {
t.Fatal(err)
} else if gr.Exists() {
t.Fatalf("database descriptor key still exists after database is dropped")
}
}
开发者ID:nkhuyu,项目名称:cockroach,代码行数:87,代码来源:drop_test.go
示例12: TestRenameTable
// TestRenameTable tests the table descriptor changes during
// a rename operation.
func TestRenameTable(t *testing.T) {
defer leaktest.AfterTest(t)
defer config.TestingDisableTableSplits()()
s, sqlDB, kvDB := setup(t)
defer cleanup(s, sqlDB)
counter := int64(keys.MaxReservedDescID + 1)
// Table creation should fail, and nothing should have been written.
oldDBID := sql.ID(counter)
if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil {
t.Fatal(err)
}
counter++
// Create table in 'test'.
tableCounter := counter
oldName := "foo"
if _, err := sqlDB.Exec(`CREATE TABLE test.foo (k INT PRIMARY KEY, v int)`); err != nil {
t.Fatal(err)
}
counter++
// Check the table descriptor.
desc := &sql.Descriptor{}
tableDescKey := sql.MakeDescMetadataKey(sql.ID(tableCounter))
if err := kvDB.GetProto(tableDescKey, desc); err != nil {
t.Fatal(err)
}
tableDesc := desc.GetTable()
if tableDesc.Name != oldName {
t.Fatalf("Wrong table name, expected %s, got: %+v", oldName, tableDesc)
}
if tableDesc.ParentID != oldDBID {
t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", oldDBID, tableDesc)
}
// Create database test2.
newDBID := sql.ID(counter)
if _, err := sqlDB.Exec(`CREATE DATABASE test2`); err != nil {
t.Fatal(err)
}
counter++
// Move table to test2 and change its name as well.
newName := "bar"
if _, err := sqlDB.Exec(`ALTER TABLE test.foo RENAME TO test2.bar`); err != nil {
t.Fatal(err)
}
// Check the table descriptor again.
if err := kvDB.GetProto(tableDescKey, desc); err != nil {
t.Fatal(err)
}
tableDesc = desc.GetTable()
if tableDesc.Name != newName {
t.Fatalf("Wrong table name, expected %s, got: %+v", newName, tableDesc)
}
if tableDesc.ParentID != newDBID {
t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", newDBID, tableDesc)
}
}
开发者ID:kaustubhkurve,项目名称:cockroach,代码行数:64,代码来源:rename_test.go
示例13: TestSchemaChangeProcess
func TestSchemaChangeProcess(t *testing.T) {
defer leaktest.AfterTest(t)
// The descriptor changes made must have an immediate effect
// so disable leases on tables.
defer csql.TestDisableTableLeases()()
// Disable external processing of mutations.
defer csql.TestDisableAsyncSchemaChangeExec()()
server, sqlDB, kvDB := setup(t)
defer cleanup(server, sqlDB)
var id = csql.ID(keys.MaxReservedDescID + 2)
var node = roachpb.NodeID(2)
db := server.DB()
leaseMgr := csql.NewLeaseManager(0, *db, hlc.NewClock(hlc.UnixNano))
changer := csql.NewSchemaChangerForTesting(id, 0, node, *db, leaseMgr)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR, INDEX foo(v));
INSERT INTO t.test VALUES ('a', 'b'), ('c', 'd');
`); err != nil {
t.Fatal(err)
}
// Read table descriptor for version.
nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test")
gr, err := kvDB.Get(nameKey)
if err != nil {
t.Fatal(err)
}
if !gr.Exists() {
t.Fatalf("Name entry %q does not exist", nameKey)
}
descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt()))
desc := &csql.Descriptor{}
// Check that MaybeIncrementVersion doesn't increment the version
// when the up_version bit is not set.
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
expectedVersion := desc.GetTable().Version
if err := changer.MaybeIncrementVersion(); err != nil {
t.Fatal(err)
}
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
newVersion := desc.GetTable().Version
if newVersion != expectedVersion {
t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion)
}
isDone, err := changer.IsDone()
if err != nil {
t.Fatal(err)
}
if !isDone {
t.Fatalf("table expected to not have an outstanding schema change: %v", desc.GetTable())
}
// Check that MaybeIncrementVersion increments the version
// correctly.
expectedVersion++
desc.GetTable().UpVersion = true
if err := kvDB.Put(descKey, desc); err != nil {
t.Fatal(err)
}
isDone, err = changer.IsDone()
if err != nil {
t.Fatal(err)
}
if isDone {
t.Fatalf("table expected to have an outstanding schema change: %v", desc.GetTable())
}
if err := changer.MaybeIncrementVersion(); err != nil {
t.Fatal(err)
}
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
newVersion = desc.GetTable().Version
if newVersion != expectedVersion {
t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion)
}
isDone, err = changer.IsDone()
if err != nil {
t.Fatal(err)
}
if !isDone {
t.Fatalf("table expected to not have an outstanding schema change: %v", desc.GetTable())
}
// Check that RunStateMachineBeforeBackfill doesn't do anything
// if there are no mutations queued.
if err := changer.RunStateMachineBeforeBackfill(); err != nil {
t.Fatal(err)
}
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
//.........这里部分代码省略.........
开发者ID:kkpapa,项目名称:cockroach,代码行数:101,代码来源:schema_changer_test.go
示例14: TestAsyncSchemaChanger
func TestAsyncSchemaChanger(t *testing.T) {
defer leaktest.AfterTest(t)
// Disable synchronous schema change execution so
// the asynchronous schema changer executes all
// schema changes.
defer csql.TestDisableSyncSchemaChangeExec()()
// The descriptor changes made must have an immediate effect
// so disable leases on tables.
defer csql.TestDisableTableLeases()()
server, sqlDB, kvDB := setup(t)
defer cleanup(server, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.test (k CHAR PRIMARY KEY, v CHAR);
INSERT INTO t.test VALUES ('a', 'b'), ('c', 'd');
`); err != nil {
t.Fatal(err)
}
// Read table descriptor for version.
nameKey := csql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "test")
gr, err := kvDB.Get(nameKey)
if err != nil {
t.Fatal(err)
}
if !gr.Exists() {
t.Fatalf("Name entry %q does not exist", nameKey)
}
descKey := csql.MakeDescMetadataKey(csql.ID(gr.ValueInt()))
desc := &csql.Descriptor{}
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
// A long running schema change operation runs through
// a state machine that increments the version by 3.
expectedVersion := desc.GetTable().Version + 3
// Run some schema change
if _, err := sqlDB.Exec(`
CREATE INDEX foo ON t.test (v)
`); err != nil {
t.Fatal(err)
}
retryOpts := retry.Options{
InitialBackoff: 20 * time.Millisecond,
MaxBackoff: 200 * time.Millisecond,
Multiplier: 2,
}
// Wait until index is created.
for r := retry.Start(retryOpts); r.Next(); {
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
if len(desc.GetTable().Indexes) == 1 {
break
}
}
// Ensure that the indexes have been created.
mTest := mutationTest{
T: t,
kvDB: kvDB,
sqlDB: sqlDB,
descKey: descKey,
desc: desc,
}
indexQuery := `SELECT * FROM [email protected]`
_ = mTest.checkQueryResponse(indexQuery, [][]string{{"b"}, {"d"}})
// Ensure that the version has been incremented.
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
newVersion := desc.GetTable().Version
if newVersion != expectedVersion {
t.Fatalf("bad version; e = %d, v = %d", expectedVersion, newVersion)
}
// Apply a schema change that only sets the UpVersion bit.
expectedVersion = newVersion + 1
if _, err := sqlDB.Exec(`
ALTER INDEX [email protected] RENAME TO ufo
`); err != nil {
t.Fatal(err)
}
for r := retry.Start(retryOpts); r.Next(); {
// Ensure that the version gets incremented.
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
name := desc.GetTable().Indexes[0].Name
if name != "ufo" {
t.Fatalf("bad index name %s", name)
}
newVersion = desc.GetTable().Version
//.........这里部分代码省略.........
开发者ID:kkpapa,项目名称:cockroach,代码行数:101,代码来源:schema_changer_test.go
示例15: TestDropDatabase
func TestDropDatabase(t *testing.T) {
defer leaktest.AfterTest(t)()
s, sqlDB, kvDB := setup(t)
defer cleanup(s, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR);
INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd');
`); err != nil {
t.Fatal(err)
}
dbNameKey := sql.MakeNameMetadataKey(keys.RootNamespaceID, "t")
r, pErr := kvDB.Get(dbNameKey)
if pErr != nil {
t.Fatal(pErr)
}
if !r.Exists() {
t.Fatalf(`database "t" does not exist`)
}
dbDescKey := sql.MakeDescMetadataKey(sql.ID(r.ValueInt()))
desc := &sql.Descriptor{}
if pErr := kvDB.GetProto(dbDescKey, desc); pErr != nil {
t.Fatal(pErr)
}
dbDesc := desc.GetDatabase()
tbNameKey := sql.MakeNameMetadataKey(dbDesc.ID, "kv")
gr, pErr := kvDB.Get(tbNameKey)
if pErr != nil {
t.Fatal(pErr)
}
if !gr.Exists() {
t.Fatalf(`table "kv" does not exist`)
}
tbDescKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt()))
if pErr := kvDB.GetProto(tbDescKey, desc); pErr != nil {
t.Fatal(pErr)
}
tbDesc := desc.GetTable()
// Add a zone config for both the table and database.
cfg := config.DefaultZoneConfig()
buf, err := proto.Marshal(&cfg)
if err != nil {
t.Fatal(err)
}
if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, tbDesc.ID, buf); err != nil {
t.Fatal(err)
}
if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, dbDesc.ID, buf); err != nil {
t.Fatal(err)
}
tbZoneKey := sql.MakeZoneKey(tbDesc.ID)
dbZoneKey := sql.MakeZoneKey(dbDesc.ID)
if gr, err := kvDB.Get(tbZoneKey); err != nil {
t.Fatal(err)
} else if !gr.Exists() {
t.Fatalf("table zone config entry not found")
}
if gr, err := kvDB.Get(dbZoneKey); err != nil {
t.Fatal(err)
} else if !gr.Exists() {
t.Fatalf("database zone config entry not found")
}
tablePrefix := keys.MakeTablePrefix(uint32(tbDesc.ID))
tableStartKey := roachpb.Key(tablePrefix)
tableEndKey := tableStartKey.PrefixEnd()
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 6; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if _, err := sqlDB.Exec(`DROP DATABASE t`); err != nil {
t.Fatal(err)
}
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 0; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if gr, err := kvDB.Get(tbDescKey); err != nil {
t.Fatal(err)
} else if gr.Exists() {
t.Fatalf("table descriptor still exists after database is dropped")
}
if gr, err := kvDB.Get(tbNameKey); err != nil {
t.Fatal(err)
} else if gr.Exists() {
t.Fatalf("table descriptor key still exists after database is dropped")
}
if gr, err := kvDB.Get(dbDescKey); err != nil {
//.........这里部分代码省略.........
开发者ID:petermattis,项目名称:cockroach,代码行数:101,代码来源:drop_test.go
示例16: TestDropIndex
func TestDropIndex(t *testing.T) {
defer leaktest.AfterTest(t)()
s, sqlDB, kvDB := setup(t)
defer cleanup(s, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR);
CREATE INDEX foo on t.kv (v);
INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd');
`); err != nil {
t.Fatal(err)
}
nameKey := sql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "kv")
gr, pErr := kvDB.Get(nameKey)
if pErr != nil {
t.Fatal(pErr)
}
if !gr.Exists() {
t.Fatalf("Name entry %q does not exist", nameKey)
}
descKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt()))
desc := &sql.Descriptor{}
if pErr := kvDB.GetProto(descKey, desc); pErr != nil {
t.Fatal(pErr)
}
tableDesc := desc.GetTable()
status, i, err := tableDesc.FindIndexByName("foo")
if err != nil {
t.Fatal(err)
}
if status != sql.DescriptorActive {
t.Fatal("Index 'foo' is not active.")
}
indexPrefix := sql.MakeIndexKeyPrefix(tableDesc.ID, tableDesc.Indexes[i].ID)
indexStartKey := roachpb.Key(indexPrefix)
indexEndKey := indexStartKey.PrefixEnd()
if kvs, err := kvDB.Scan(indexStartKey, indexEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 3; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if _, err := sqlDB.Exec(`DROP INDEX [email protected]`); err != nil {
t.Fatal(err)
}
if kvs, err := kvDB.Scan(indexStartKey, indexEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 0; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if err := kvDB.GetProto(descKey, desc); err != nil {
t.Fatal(err)
}
tableDesc = desc.GetTable()
if _, _, err := tableDesc.FindIndexByName("foo"); err == nil {
t.Fatalf("table descriptor still contains index after index is dropped")
}
if err != nil {
t.Fatal(err)
}
}
开发者ID:petermattis,项目名称:cockroach,代码行数:69,代码来源:drop_test.go
示例17: TestDropTable
func TestDropTable(t *testing.T) {
defer leaktest.AfterTest(t)
s, sqlDB, kvDB := setup(t)
defer cleanup(s, sqlDB)
if _, err := sqlDB.Exec(`
CREATE DATABASE t;
CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR);
INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd');
`); err != nil {
t.Fatal(err)
}
nameKey := sql.MakeNameMetadataKey(keys.MaxReservedDescID+1, "kv")
gr, err := kvDB.Get(nameKey)
if err != nil {
t.Fatal(err)
}
if !gr.Exists() {
t.Fatalf("Name entry %q does not exist", nameKey)
}
descKey := sql.MakeDescMetadataKey(sql.ID(gr.ValueInt()))
desc := sql.TableDescriptor{}
if err := kvDB.GetProto(descKey, &desc); err != nil {
t.Fatal(err)
}
// Add a zone config for the table.
buf, err := gogoproto.Marshal(config.DefaultZoneConfig)
if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, desc.ID, buf); err != nil {
t.Fatal(err)
}
zoneKey := sql.MakeZoneKey(desc.ID)
if gr, err := kvDB.Get(zoneKey); err != nil {
t.Fatal(err)
} else if !gr.Exists() {
t.Fatalf("zone config entry not found")
}
var tablePrefix []byte
tablePrefix = append(tablePrefix, keys.TableDataPrefix...)
tablePrefix = encoding.EncodeUvarint(tablePrefix, uint64(desc.ID))
tableStartKey := proto.Key(tablePrefix)
tableEndKey := tableStartKey.PrefixEnd()
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 6; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if _, err := sqlDB.Exec(`DROP TABLE t.kv`); err != nil {
t.Fatal(err)
}
if kvs, err := kvDB.Scan(tableStartKey, tableEndKey, 0); err != nil {
t.Fatal(err)
} else if l := 0; len(kvs) != l {
t.Fatalf("expected %d key value pairs, but got %d", l, len(kvs))
}
if gr, err := kvDB.Get(descKey); err != nil {
t.Fatal(err)
|
请发表评论