You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
503 lines
12 KiB
503 lines
12 KiB
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package meta_test
|
|
|
|
import (
|
|
"context"
|
|
"math"
|
|
"strconv"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
. "github.com/pingcap/check"
|
|
"github.com/pingcap/parser/model"
|
|
"github.com/pingcap/tidb/meta"
|
|
"github.com/pingcap/tidb/store/mockstore"
|
|
"github.com/pingcap/tidb/util/testleak"
|
|
)
|
|
|
|
func TestT(t *testing.T) {
|
|
CustomVerboseFlag = true
|
|
TestingT(t)
|
|
}
|
|
|
|
var _ = Suite(&testSuite{})
|
|
|
|
type testSuite struct {
|
|
}
|
|
|
|
func (s *testSuite) TestMeta(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
store, err := mockstore.NewMockTikvStore()
|
|
c.Assert(err, IsNil)
|
|
defer store.Close()
|
|
|
|
txn, err := store.Begin()
|
|
c.Assert(err, IsNil)
|
|
defer txn.Rollback()
|
|
|
|
t := meta.NewMeta(txn)
|
|
|
|
n, err := t.GenGlobalID()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(1))
|
|
|
|
n, err = t.GetGlobalID()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(1))
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
ids, err := t.GenGlobalIDs(3)
|
|
c.Assert(err, IsNil)
|
|
anyMatch(c, ids, []int64{2, 3, 4}, []int64{6, 7, 8})
|
|
}()
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
ids, err := t.GenGlobalIDs(4)
|
|
c.Assert(err, IsNil)
|
|
anyMatch(c, ids, []int64{5, 6, 7, 8}, []int64{2, 3, 4, 5})
|
|
}()
|
|
wg.Wait()
|
|
|
|
n, err = t.GetSchemaVersion()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(0))
|
|
|
|
n, err = t.GenSchemaVersion()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(1))
|
|
|
|
n, err = t.GetSchemaVersion()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(1))
|
|
|
|
dbInfo := &model.DBInfo{
|
|
ID: 1,
|
|
Name: model.NewCIStr("a"),
|
|
}
|
|
err = t.CreateDatabase(dbInfo)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = t.CreateDatabase(dbInfo)
|
|
c.Assert(err, NotNil)
|
|
c.Assert(meta.ErrDBExists.Equal(err), IsTrue)
|
|
|
|
v, err := t.GetDatabase(1)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, DeepEquals, dbInfo)
|
|
|
|
dbInfo.Name = model.NewCIStr("aa")
|
|
err = t.UpdateDatabase(dbInfo)
|
|
c.Assert(err, IsNil)
|
|
|
|
v, err = t.GetDatabase(1)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, DeepEquals, dbInfo)
|
|
|
|
dbs, err := t.ListDatabases()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(dbs, DeepEquals, []*model.DBInfo{dbInfo})
|
|
|
|
tbInfo := &model.TableInfo{
|
|
ID: 1,
|
|
Name: model.NewCIStr("t"),
|
|
}
|
|
err = t.CreateTableOrView(1, tbInfo)
|
|
c.Assert(err, IsNil)
|
|
|
|
n, err = t.GenAutoTableID(1, 1, 10)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(10))
|
|
|
|
n, err = t.GetAutoTableID(1, 1)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(10))
|
|
|
|
err = t.CreateTableOrView(1, tbInfo)
|
|
c.Assert(err, NotNil)
|
|
c.Assert(meta.ErrTableExists.Equal(err), IsTrue)
|
|
|
|
tbInfo.Name = model.NewCIStr("tt")
|
|
err = t.UpdateTable(1, tbInfo)
|
|
c.Assert(err, IsNil)
|
|
|
|
table, err := t.GetTable(1, 1)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(table, DeepEquals, tbInfo)
|
|
|
|
table, err = t.GetTable(1, 2)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(table, IsNil)
|
|
|
|
tbInfo2 := &model.TableInfo{
|
|
ID: 2,
|
|
Name: model.NewCIStr("bb"),
|
|
}
|
|
err = t.CreateTableOrView(1, tbInfo2)
|
|
c.Assert(err, IsNil)
|
|
|
|
tables, err := t.ListTables(1)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tables, DeepEquals, []*model.TableInfo{tbInfo, tbInfo2})
|
|
// Generate an auto id.
|
|
n, err = t.GenAutoTableID(1, 2, 10)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(10))
|
|
// Make sure the auto id key-value entry is there.
|
|
n, err = t.GetAutoTableID(1, 2)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(10))
|
|
|
|
err = t.DropTableOrView(1, tbInfo2.ID, true)
|
|
c.Assert(err, IsNil)
|
|
// Make sure auto id key-value entry is gone.
|
|
n, err = t.GetAutoTableID(1, 2)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(0))
|
|
|
|
tables, err = t.ListTables(1)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tables, DeepEquals, []*model.TableInfo{tbInfo})
|
|
|
|
// Test case for drop a table without delete auto id key-value entry.
|
|
tid := int64(100)
|
|
tbInfo100 := &model.TableInfo{
|
|
ID: tid,
|
|
Name: model.NewCIStr("t_rename"),
|
|
}
|
|
// Create table.
|
|
err = t.CreateTableOrView(1, tbInfo100)
|
|
c.Assert(err, IsNil)
|
|
// Update auto ID.
|
|
currentDBID := int64(1)
|
|
n, err = t.GenAutoTableID(currentDBID, tid, 10)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(10))
|
|
// Fail to update auto ID.
|
|
// The table ID doesn't exist.
|
|
nonExistentID := int64(1234)
|
|
_, err = t.GenAutoTableID(currentDBID, nonExistentID, 10)
|
|
c.Assert(err, NotNil)
|
|
c.Assert(meta.ErrTableNotExists.Equal(err), IsTrue)
|
|
// Fail to update auto ID.
|
|
// The current database ID doesn't exist.
|
|
currentDBID = nonExistentID
|
|
_, err = t.GenAutoTableID(currentDBID, tid, 10)
|
|
c.Assert(err, NotNil)
|
|
c.Assert(meta.ErrDBNotExists.Equal(err), IsTrue)
|
|
// Test case for CreateTableAndSetAutoID.
|
|
tbInfo3 := &model.TableInfo{
|
|
ID: 3,
|
|
Name: model.NewCIStr("tbl3"),
|
|
}
|
|
err = t.CreateTableAndSetAutoID(1, tbInfo3, 123, 0)
|
|
c.Assert(err, IsNil)
|
|
id, err := t.GetAutoTableID(1, tbInfo3.ID)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(id, Equals, int64(123))
|
|
// Test case for GenAutoTableIDKeyValue.
|
|
key, val := t.GenAutoTableIDKeyValue(1, tbInfo3.ID, 1234)
|
|
c.Assert(val, DeepEquals, []byte(strconv.FormatInt(1234, 10)))
|
|
c.Assert(key, DeepEquals, []byte{0x6d, 0x44, 0x42, 0x3a, 0x31, 0x0, 0x0, 0x0, 0x0, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x54, 0x49, 0x44, 0x3a, 0x33, 0x0, 0x0, 0x0, 0xfc})
|
|
|
|
err = t.DropDatabase(1)
|
|
c.Assert(err, IsNil)
|
|
err = t.DropDatabase(currentDBID)
|
|
c.Assert(err, IsNil)
|
|
|
|
dbs, err = t.ListDatabases()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(dbs, HasLen, 0)
|
|
|
|
bootstrapVer, err := t.GetBootstrapVersion()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(bootstrapVer, Equals, int64(0))
|
|
|
|
err = t.FinishBootstrap(int64(1))
|
|
c.Assert(err, IsNil)
|
|
|
|
bootstrapVer, err = t.GetBootstrapVersion()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(bootstrapVer, Equals, int64(1))
|
|
|
|
// Test case for meta.FinishBootstrap with a version.
|
|
err = t.FinishBootstrap(int64(10))
|
|
c.Assert(err, IsNil)
|
|
bootstrapVer, err = t.GetBootstrapVersion()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(bootstrapVer, Equals, int64(10))
|
|
|
|
// Test case for SchemaDiff.
|
|
schemaDiff := &model.SchemaDiff{
|
|
Version: 100,
|
|
SchemaID: 1,
|
|
Type: model.ActionTruncateTable,
|
|
TableID: 2,
|
|
OldTableID: 3,
|
|
}
|
|
err = t.SetSchemaDiff(schemaDiff)
|
|
c.Assert(err, IsNil)
|
|
readDiff, err := t.GetSchemaDiff(schemaDiff.Version)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(readDiff, DeepEquals, schemaDiff)
|
|
|
|
err = txn.Commit(context.Background())
|
|
c.Assert(err, IsNil)
|
|
|
|
// Test for DDLJobHistoryKey.
|
|
key = meta.DDLJobHistoryKey(t, 888)
|
|
c.Assert(key, DeepEquals, []byte{0x6d, 0x44, 0x44, 0x4c, 0x4a, 0x6f, 0x62, 0x48, 0x69, 0xff, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x78, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf7})
|
|
}
|
|
|
|
func (s *testSuite) TestSnapshot(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
store, err := mockstore.NewMockTikvStore()
|
|
c.Assert(err, IsNil)
|
|
defer store.Close()
|
|
|
|
txn, _ := store.Begin()
|
|
m := meta.NewMeta(txn)
|
|
m.GenGlobalID()
|
|
n, _ := m.GetGlobalID()
|
|
c.Assert(n, Equals, int64(1))
|
|
txn.Commit(context.Background())
|
|
|
|
ver1, _ := store.CurrentVersion()
|
|
time.Sleep(time.Millisecond)
|
|
txn, _ = store.Begin()
|
|
m = meta.NewMeta(txn)
|
|
m.GenGlobalID()
|
|
n, _ = m.GetGlobalID()
|
|
c.Assert(n, Equals, int64(2))
|
|
txn.Commit(context.Background())
|
|
|
|
snapshot, _ := store.GetSnapshot(ver1)
|
|
snapMeta := meta.NewSnapshotMeta(snapshot)
|
|
n, _ = snapMeta.GetGlobalID()
|
|
c.Assert(n, Equals, int64(1))
|
|
_, err = snapMeta.GenGlobalID()
|
|
c.Assert(err, NotNil)
|
|
c.Assert(err.Error(), Equals, "[structure:8220]write on snapshot")
|
|
}
|
|
|
|
func (s *testSuite) TestDDL(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
store, err := mockstore.NewMockTikvStore()
|
|
c.Assert(err, IsNil)
|
|
defer store.Close()
|
|
|
|
txn, err := store.Begin()
|
|
c.Assert(err, IsNil)
|
|
|
|
defer txn.Rollback()
|
|
|
|
t := meta.NewMeta(txn)
|
|
|
|
job := &model.Job{ID: 1}
|
|
err = t.EnQueueDDLJob(job)
|
|
c.Assert(err, IsNil)
|
|
n, err := t.DDLJobQueueLen()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(n, Equals, int64(1))
|
|
|
|
v, err := t.GetDDLJobByIdx(0)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, DeepEquals, job)
|
|
v, err = t.GetDDLJobByIdx(1)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, IsNil)
|
|
job.ID = 2
|
|
err = t.UpdateDDLJob(0, job, true)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = t.UpdateDDLReorgStartHandle(job, 1)
|
|
c.Assert(err, IsNil)
|
|
|
|
i, j, k, err := t.GetDDLReorgHandle(job)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(i, Equals, int64(1))
|
|
c.Assert(j, Equals, int64(math.MaxInt64))
|
|
c.Assert(k, Equals, int64(0))
|
|
|
|
err = t.UpdateDDLReorgHandle(job, 1, 2, 3)
|
|
c.Assert(err, IsNil)
|
|
|
|
i, j, k, err = t.GetDDLReorgHandle(job)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(i, Equals, int64(1))
|
|
c.Assert(j, Equals, int64(2))
|
|
c.Assert(k, Equals, int64(3))
|
|
|
|
err = t.RemoveDDLReorgHandle(job)
|
|
c.Assert(err, IsNil)
|
|
|
|
i, j, k, err = t.GetDDLReorgHandle(job)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(i, Equals, int64(0))
|
|
// The default value for endHandle is MaxInt64, not 0.
|
|
c.Assert(j, Equals, int64(math.MaxInt64))
|
|
c.Assert(k, Equals, int64(0))
|
|
|
|
// Test GetDDLReorgHandle failed.
|
|
_, _, _, err = t.GetDDLReorgHandle(job)
|
|
c.Assert(err, IsNil)
|
|
|
|
v, err = t.DeQueueDDLJob()
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, DeepEquals, job)
|
|
|
|
err = t.AddHistoryDDLJob(job, true)
|
|
c.Assert(err, IsNil)
|
|
v, err = t.GetHistoryDDLJob(2)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, DeepEquals, job)
|
|
|
|
// Add multiple history jobs.
|
|
arg := "test arg"
|
|
historyJob1 := &model.Job{ID: 1234}
|
|
historyJob1.Args = append(job.Args, arg)
|
|
err = t.AddHistoryDDLJob(historyJob1, true)
|
|
c.Assert(err, IsNil)
|
|
historyJob2 := &model.Job{ID: 123}
|
|
historyJob2.Args = append(job.Args, arg)
|
|
err = t.AddHistoryDDLJob(historyJob2, false)
|
|
c.Assert(err, IsNil)
|
|
all, err := t.GetAllHistoryDDLJobs()
|
|
c.Assert(err, IsNil)
|
|
var lastID int64
|
|
for _, job := range all {
|
|
c.Assert(job.ID, Greater, lastID)
|
|
lastID = job.ID
|
|
arg1 := ""
|
|
job.DecodeArgs(&arg1)
|
|
if job.ID == historyJob1.ID {
|
|
c.Assert(*(job.Args[0].(*string)), Equals, historyJob1.Args[0])
|
|
} else {
|
|
c.Assert(job.Args, HasLen, 0)
|
|
}
|
|
}
|
|
|
|
// Test for get last N history ddl jobs.
|
|
historyJobs, err := t.GetLastNHistoryDDLJobs(2)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(len(historyJobs), Equals, 2)
|
|
c.Assert(historyJobs[0].ID == 1234, IsTrue)
|
|
c.Assert(historyJobs[1].ID == 123, IsTrue)
|
|
|
|
// Test GetAllDDLJobsInQueue.
|
|
err = t.EnQueueDDLJob(job)
|
|
c.Assert(err, IsNil)
|
|
job1 := &model.Job{ID: 2}
|
|
err = t.EnQueueDDLJob(job1)
|
|
c.Assert(err, IsNil)
|
|
jobs, err := t.GetAllDDLJobsInQueue()
|
|
c.Assert(err, IsNil)
|
|
expectJobs := []*model.Job{job, job1}
|
|
c.Assert(jobs, DeepEquals, expectJobs)
|
|
|
|
err = txn.Commit(context.Background())
|
|
c.Assert(err, IsNil)
|
|
|
|
// Test for add index job.
|
|
txn1, err := store.Begin()
|
|
c.Assert(err, IsNil)
|
|
defer txn1.Rollback()
|
|
|
|
m := meta.NewMeta(txn1, meta.AddIndexJobListKey)
|
|
err = m.EnQueueDDLJob(job)
|
|
c.Assert(err, IsNil)
|
|
job.ID = 123
|
|
err = m.UpdateDDLJob(0, job, true, meta.AddIndexJobListKey)
|
|
c.Assert(err, IsNil)
|
|
v, err = m.GetDDLJobByIdx(0, meta.AddIndexJobListKey)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, DeepEquals, job)
|
|
l, err := m.DDLJobQueueLen(meta.AddIndexJobListKey)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(l, Equals, int64(1))
|
|
jobs, err = m.GetAllDDLJobsInQueue(meta.AddIndexJobListKey)
|
|
c.Assert(err, IsNil)
|
|
expectJobs = []*model.Job{job}
|
|
c.Assert(jobs, DeepEquals, expectJobs)
|
|
|
|
err = txn1.Commit(context.Background())
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
func (s *testSuite) BenchmarkGenGlobalIDs(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
store, err := mockstore.NewMockTikvStore()
|
|
c.Assert(err, IsNil)
|
|
defer store.Close()
|
|
|
|
txn, err := store.Begin()
|
|
c.Assert(err, IsNil)
|
|
defer txn.Rollback()
|
|
|
|
t := meta.NewMeta(txn)
|
|
|
|
c.ResetTimer()
|
|
var ids []int64
|
|
for i := 0; i < c.N; i++ {
|
|
ids, _ = t.GenGlobalIDs(10)
|
|
}
|
|
c.Assert(ids, HasLen, 10)
|
|
c.Assert(ids[9], Equals, int64(c.N)*10)
|
|
}
|
|
|
|
func (s *testSuite) BenchmarkGenGlobalIDOneByOne(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
store, err := mockstore.NewMockTikvStore()
|
|
c.Assert(err, IsNil)
|
|
defer store.Close()
|
|
|
|
txn, err := store.Begin()
|
|
c.Assert(err, IsNil)
|
|
defer txn.Rollback()
|
|
|
|
t := meta.NewMeta(txn)
|
|
|
|
c.ResetTimer()
|
|
var id int64
|
|
for i := 0; i < c.N; i++ {
|
|
for j := 0; j < 10; j++ {
|
|
id, _ = t.GenGlobalID()
|
|
}
|
|
}
|
|
c.Assert(id, Equals, int64(c.N)*10)
|
|
}
|
|
|
|
func anyMatch(c *C, ids []int64, candidates ...[]int64) {
|
|
var match bool
|
|
OUTER:
|
|
for _, cand := range candidates {
|
|
if len(ids) != len(cand) {
|
|
continue
|
|
}
|
|
for i, v := range cand {
|
|
if ids[i] != v {
|
|
continue OUTER
|
|
}
|
|
}
|
|
match = true
|
|
break
|
|
}
|
|
c.Assert(match, IsTrue)
|
|
}
|
|
|