github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/ddl/schema_test.go (about)

     1  // Copyright 2015 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package ddl
    15  
    16  import (
    17  	"time"
    18  
    19  	. "github.com/insionng/yougam/libraries/pingcap/check"
    20  	"github.com/insionng/yougam/libraries/pingcap/tidb/context"
    21  	"github.com/insionng/yougam/libraries/pingcap/tidb/infoschema"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/meta"
    24  	"github.com/insionng/yougam/libraries/pingcap/tidb/model"
    25  	"github.com/insionng/yougam/libraries/pingcap/tidb/terror"
    26  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/mock"
    27  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/testleak"
    28  )
    29  
    30  var _ = Suite(&testSchemaSuite{})
    31  
    32  type testSchemaSuite struct{}
    33  
    34  func testSchemaInfo(c *C, d *ddl, name string) *model.DBInfo {
    35  	var err error
    36  	dbInfo := &model.DBInfo{
    37  		Name: model.NewCIStr(name),
    38  	}
    39  
    40  	dbInfo.ID, err = d.genGlobalID()
    41  	c.Assert(err, IsNil)
    42  	return dbInfo
    43  }
    44  
    45  func testCreateSchema(c *C, ctx context.Context, d *ddl, dbInfo *model.DBInfo) *model.Job {
    46  	job := &model.Job{
    47  		SchemaID: dbInfo.ID,
    48  		Type:     model.ActionCreateSchema,
    49  		Args:     []interface{}{dbInfo},
    50  	}
    51  
    52  	err := d.doDDLJob(ctx, job)
    53  	c.Assert(err, IsNil)
    54  	return job
    55  }
    56  
    57  func testDropSchema(c *C, ctx context.Context, d *ddl, dbInfo *model.DBInfo) *model.Job {
    58  	job := &model.Job{
    59  		SchemaID: dbInfo.ID,
    60  		Type:     model.ActionDropSchema,
    61  	}
    62  
    63  	err := d.doDDLJob(ctx, job)
    64  	c.Assert(err, IsNil)
    65  	return job
    66  }
    67  
    68  func checkDrop(c *C, t *meta.Meta) bool {
    69  	bgJob, err := t.GetBgJob(0)
    70  	c.Assert(err, IsNil)
    71  	if bgJob == nil {
    72  		return true
    73  	}
    74  
    75  	time.Sleep(5 * time.Millisecond)
    76  	return false
    77  }
    78  
    79  func testCheckSchemaState(c *C, d *ddl, dbInfo *model.DBInfo, state model.SchemaState) {
    80  	isDropped := true
    81  
    82  	for {
    83  		kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
    84  			t := meta.NewMeta(txn)
    85  			info, err := t.GetDatabase(dbInfo.ID)
    86  			c.Assert(err, IsNil)
    87  
    88  			if state == model.StateNone {
    89  				isDropped = checkDrop(c, t)
    90  				if !isDropped {
    91  					return nil
    92  				}
    93  				c.Assert(info, IsNil)
    94  				return nil
    95  			}
    96  
    97  			c.Assert(info.Name, DeepEquals, dbInfo.Name)
    98  			c.Assert(info.State, Equals, state)
    99  			return nil
   100  		})
   101  
   102  		if isDropped {
   103  			break
   104  		}
   105  	}
   106  }
   107  
   108  func testCheckJobDone(c *C, d *ddl, job *model.Job, isAdd bool) {
   109  	kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
   110  		t := meta.NewMeta(txn)
   111  		historyJob, err := t.GetHistoryDDLJob(job.ID)
   112  		c.Assert(err, IsNil)
   113  		c.Assert(historyJob.State, Equals, model.JobDone)
   114  		if isAdd {
   115  			c.Assert(historyJob.SchemaState, Equals, model.StatePublic)
   116  		} else {
   117  			c.Assert(historyJob.SchemaState, Equals, model.StateNone)
   118  		}
   119  
   120  		return nil
   121  	})
   122  }
   123  
   124  func testCheckJobCancelled(c *C, d *ddl, job *model.Job) {
   125  	kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
   126  		t := meta.NewMeta(txn)
   127  		historyJob, err := t.GetHistoryDDLJob(job.ID)
   128  		c.Assert(err, IsNil)
   129  		c.Assert(historyJob.State, Equals, model.JobCancelled)
   130  		return nil
   131  	})
   132  }
   133  
   134  func (s *testSchemaSuite) TestSchema(c *C) {
   135  	defer testleak.AfterTest(c)()
   136  	store := testCreateStore(c, "test_schema")
   137  	defer store.Close()
   138  
   139  	lease := 100 * time.Millisecond
   140  
   141  	d1 := newDDL(store, nil, nil, lease)
   142  	defer d1.close()
   143  
   144  	ctx := mock.NewContext()
   145  
   146  	dbInfo := testSchemaInfo(c, d1, "test")
   147  	job := testCreateSchema(c, ctx, d1, dbInfo)
   148  
   149  	testCheckSchemaState(c, d1, dbInfo, model.StatePublic)
   150  	testCheckJobDone(c, d1, job, true)
   151  
   152  	job = testDropSchema(c, ctx, d1, dbInfo)
   153  	testCheckSchemaState(c, d1, dbInfo, model.StateNone)
   154  	testCheckJobDone(c, d1, job, false)
   155  
   156  	job = &model.Job{
   157  		SchemaID: dbInfo.ID,
   158  		Type:     model.ActionDropSchema,
   159  	}
   160  
   161  	err := d1.doDDLJob(ctx, job)
   162  	c.Assert(terror.ErrorEqual(err, infoschema.ErrDatabaseNotExists), IsTrue)
   163  }
   164  
   165  func (s *testSchemaSuite) TestSchemaWaitJob(c *C) {
   166  	defer testleak.AfterTest(c)()
   167  	store := testCreateStore(c, "test_schema_wait")
   168  	defer store.Close()
   169  
   170  	ctx := mock.NewContext()
   171  
   172  	lease := 50 * time.Millisecond
   173  
   174  	d1 := newDDL(store, nil, nil, lease)
   175  	defer d1.close()
   176  
   177  	testCheckOwner(c, d1, true, ddlJobFlag)
   178  
   179  	d2 := newDDL(store, nil, nil, lease)
   180  	defer d2.close()
   181  
   182  	// d2 must not be owner.
   183  	testCheckOwner(c, d2, false, ddlJobFlag)
   184  
   185  	dbInfo := testSchemaInfo(c, d2, "test")
   186  	job := testCreateSchema(c, ctx, d2, dbInfo)
   187  	testCheckSchemaState(c, d2, dbInfo, model.StatePublic)
   188  
   189  	// d2 must not be owner.
   190  	testCheckOwner(c, d2, false, ddlJobFlag)
   191  
   192  	schemaID, err := d2.genGlobalID()
   193  	c.Assert(err, IsNil)
   194  
   195  	job = &model.Job{
   196  		SchemaID: schemaID,
   197  		Type:     model.ActionCreateSchema,
   198  		Args:     []interface{}{dbInfo},
   199  	}
   200  
   201  	err = d2.doDDLJob(ctx, job)
   202  	c.Assert(err, NotNil)
   203  	testCheckJobCancelled(c, d2, job)
   204  
   205  	// d2 must not be owner.
   206  	testCheckOwner(c, d2, false, ddlJobFlag)
   207  }
   208  
   209  func testRunInterruptedJob(c *C, d *ddl, job *model.Job) {
   210  	ctx := mock.NewContext()
   211  	done := make(chan error, 1)
   212  	go func() {
   213  		done <- d.doDDLJob(ctx, job)
   214  	}()
   215  
   216  	ticker := time.NewTicker(d.lease * 1)
   217  	defer ticker.Stop()
   218  
   219  LOOP:
   220  	for {
   221  		select {
   222  		case <-ticker.C:
   223  			d.close()
   224  			d.start()
   225  		case err := <-done:
   226  			c.Assert(err, IsNil)
   227  			break LOOP
   228  		}
   229  	}
   230  }
   231  
   232  func (s *testSchemaSuite) TestSchemaResume(c *C) {
   233  	defer testleak.AfterTest(c)()
   234  	store := testCreateStore(c, "test_schema_resume")
   235  	defer store.Close()
   236  
   237  	lease := 50 * time.Millisecond
   238  
   239  	d1 := newDDL(store, nil, nil, lease)
   240  	defer d1.close()
   241  
   242  	testCheckOwner(c, d1, true, ddlJobFlag)
   243  
   244  	dbInfo := testSchemaInfo(c, d1, "test")
   245  
   246  	job := &model.Job{
   247  		SchemaID: dbInfo.ID,
   248  		Type:     model.ActionCreateSchema,
   249  		Args:     []interface{}{dbInfo},
   250  	}
   251  
   252  	testRunInterruptedJob(c, d1, job)
   253  	testCheckSchemaState(c, d1, dbInfo, model.StatePublic)
   254  	job = &model.Job{
   255  		SchemaID: dbInfo.ID,
   256  		Type:     model.ActionDropSchema,
   257  	}
   258  
   259  	testRunInterruptedJob(c, d1, job)
   260  	testCheckSchemaState(c, d1, dbInfo, model.StateNone)
   261  }