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 }