github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/meta/meta.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 meta 15 16 import ( 17 "encoding/binary" 18 "encoding/json" 19 "fmt" 20 "strconv" 21 "strings" 22 "sync" 23 "time" 24 25 "github.com/insionng/yougam/libraries/juju/errors" 26 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 27 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 28 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 29 "github.com/insionng/yougam/libraries/pingcap/tidb/structure" 30 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 31 ) 32 33 var ( 34 globalIDMutex sync.Mutex 35 ) 36 37 // Meta structure: 38 // NextGlobalID -> int64 39 // SchemaVersion -> int64 40 // DBs -> { 41 // DB:1 -> db meta data []byte 42 // DB:2 -> db meta data []byte 43 // } 44 // DB:1 -> { 45 // Table:1 -> table meta data []byte 46 // Table:2 -> table meta data []byte 47 // TID:1 -> int64 48 // TID:2 -> int64 49 // } 50 // 51 52 var ( 53 mNextGlobalIDKey = []byte("NextGlobalID") 54 mSchemaVersionKey = []byte("SchemaVersionKey") 55 mDBs = []byte("DBs") 56 mDBPrefix = "DB" 57 mTablePrefix = "Table" 58 mTableIDPrefix = "TID" 59 mBootstrapKey = []byte("BootstrapKey") 60 ) 61 62 var ( 63 errInvalidTableKey = terror.ClassMeta.New(codeInvalidTableKey, "invalid table meta key") 64 errInvalidDBKey = terror.ClassMeta.New(codeInvalidDBKey, "invalid db key") 65 66 // ErrDBExists is the error for db exists. 67 ErrDBExists = terror.ClassMeta.New(codeDatabaseExists, "database already exists") 68 // ErrDBNotExists is the error for db not exists. 69 ErrDBNotExists = terror.ClassMeta.New(codeDatabaseNotExists, "database doesn't exist") 70 // ErrTableExists is the error for table exists. 71 ErrTableExists = terror.ClassMeta.New(codeTableExists, "table already exists") 72 // ErrTableNotExists is the error for table not exists. 73 ErrTableNotExists = terror.ClassMeta.New(codeTableNotExists, "table doesn't exist") 74 ) 75 76 // Meta is for handling meta information in a transaction. 77 type Meta struct { 78 txn *structure.TxStructure 79 } 80 81 // NewMeta creates a Meta in transaction txn. 82 func NewMeta(txn kv.Transaction) *Meta { 83 t := structure.NewStructure(txn, []byte{'m'}) 84 return &Meta{txn: t} 85 } 86 87 // GenGlobalID generates next id globally. 88 func (m *Meta) GenGlobalID() (int64, error) { 89 globalIDMutex.Lock() 90 defer globalIDMutex.Unlock() 91 92 return m.txn.Inc(mNextGlobalIDKey, 1) 93 } 94 95 // GetGlobalID gets current global id. 96 func (m *Meta) GetGlobalID() (int64, error) { 97 return m.txn.GetInt64(mNextGlobalIDKey) 98 } 99 100 func (m *Meta) dbKey(dbID int64) []byte { 101 return []byte(fmt.Sprintf("%s:%d", mDBPrefix, dbID)) 102 } 103 104 func (m *Meta) parseDatabaseID(key string) (int64, error) { 105 seps := strings.Split(key, ":") 106 if len(seps) != 2 { 107 return 0, errors.Errorf("invalid db key %s", key) 108 } 109 110 n, err := strconv.ParseInt(seps[1], 10, 64) 111 return n, errors.Trace(err) 112 } 113 114 func (m *Meta) autoTalbeIDKey(tableID int64) []byte { 115 return []byte(fmt.Sprintf("%s:%d", mTableIDPrefix, tableID)) 116 } 117 118 func (m *Meta) tableKey(tableID int64) []byte { 119 return []byte(fmt.Sprintf("%s:%d", mTablePrefix, tableID)) 120 } 121 122 func (m *Meta) parseTableID(key string) (int64, error) { 123 seps := strings.Split(key, ":") 124 if len(seps) != 2 { 125 return 0, errors.Errorf("invalid table meta key %s", key) 126 } 127 128 n, err := strconv.ParseInt(seps[1], 10, 64) 129 return n, errors.Trace(err) 130 } 131 132 // GenAutoTableID adds step to the auto id of the table and returns the sum. 133 func (m *Meta) GenAutoTableID(dbID int64, tableID int64, step int64) (int64, error) { 134 // Check if db exists. 135 dbKey := m.dbKey(dbID) 136 if err := m.checkDBExists(dbKey); err != nil { 137 return 0, errors.Trace(err) 138 } 139 140 // Check if table exists. 141 tableKey := m.tableKey(tableID) 142 if err := m.checkTableExists(dbKey, tableKey); err != nil { 143 return 0, errors.Trace(err) 144 } 145 146 return m.txn.HInc(dbKey, m.autoTalbeIDKey(tableID), step) 147 } 148 149 // GetAutoTableID gets current auto id with table id. 150 func (m *Meta) GetAutoTableID(dbID int64, tableID int64) (int64, error) { 151 return m.txn.HGetInt64(m.dbKey(dbID), m.autoTalbeIDKey(tableID)) 152 } 153 154 // GetSchemaVersion gets current global schema version. 155 func (m *Meta) GetSchemaVersion() (int64, error) { 156 return m.txn.GetInt64(mSchemaVersionKey) 157 } 158 159 // GenSchemaVersion generates next schema version. 160 func (m *Meta) GenSchemaVersion() (int64, error) { 161 return m.txn.Inc(mSchemaVersionKey, 1) 162 } 163 164 func (m *Meta) checkDBExists(dbKey []byte) error { 165 v, err := m.txn.HGet(mDBs, dbKey) 166 if err != nil { 167 return errors.Trace(err) 168 } else if v == nil { 169 return ErrDBNotExists 170 } 171 172 return nil 173 } 174 175 func (m *Meta) checkDBNotExists(dbKey []byte) error { 176 v, err := m.txn.HGet(mDBs, dbKey) 177 if err != nil { 178 return errors.Trace(err) 179 } 180 181 if v != nil { 182 return ErrDBExists 183 } 184 185 return nil 186 } 187 188 func (m *Meta) checkTableExists(dbKey []byte, tableKey []byte) error { 189 v, err := m.txn.HGet(dbKey, tableKey) 190 if err != nil { 191 return errors.Trace(err) 192 } 193 194 if v == nil { 195 return ErrTableNotExists 196 } 197 198 return nil 199 } 200 201 func (m *Meta) checkTableNotExists(dbKey []byte, tableKey []byte) error { 202 v, err := m.txn.HGet(dbKey, tableKey) 203 if err != nil { 204 return errors.Trace(err) 205 } 206 207 if v != nil { 208 return ErrTableExists 209 } 210 211 return nil 212 } 213 214 // CreateDatabase creates a database with db info. 215 func (m *Meta) CreateDatabase(dbInfo *model.DBInfo) error { 216 dbKey := m.dbKey(dbInfo.ID) 217 218 if err := m.checkDBNotExists(dbKey); err != nil { 219 return errors.Trace(err) 220 } 221 222 data, err := json.Marshal(dbInfo) 223 if err != nil { 224 return errors.Trace(err) 225 } 226 227 return m.txn.HSet(mDBs, dbKey, data) 228 } 229 230 // UpdateDatabase updates a database with db info. 231 func (m *Meta) UpdateDatabase(dbInfo *model.DBInfo) error { 232 dbKey := m.dbKey(dbInfo.ID) 233 234 if err := m.checkDBExists(dbKey); err != nil { 235 return errors.Trace(err) 236 } 237 238 data, err := json.Marshal(dbInfo) 239 if err != nil { 240 return errors.Trace(err) 241 } 242 243 return m.txn.HSet(mDBs, dbKey, data) 244 } 245 246 // CreateTable creates a table with tableInfo in database. 247 func (m *Meta) CreateTable(dbID int64, tableInfo *model.TableInfo) error { 248 // Check if db exists. 249 dbKey := m.dbKey(dbID) 250 if err := m.checkDBExists(dbKey); err != nil { 251 return errors.Trace(err) 252 } 253 254 // Check if table exists. 255 tableKey := m.tableKey(tableInfo.ID) 256 if err := m.checkTableNotExists(dbKey, tableKey); err != nil { 257 return errors.Trace(err) 258 } 259 260 data, err := json.Marshal(tableInfo) 261 if err != nil { 262 return errors.Trace(err) 263 } 264 265 return m.txn.HSet(dbKey, tableKey, data) 266 } 267 268 // DropDatabase drops whole database. 269 func (m *Meta) DropDatabase(dbID int64) error { 270 // Check if db exists. 271 dbKey := m.dbKey(dbID) 272 if err := m.txn.HClear(dbKey); err != nil { 273 return errors.Trace(err) 274 } 275 276 if err := m.txn.HDel(mDBs, dbKey); err != nil { 277 return errors.Trace(err) 278 } 279 280 return nil 281 } 282 283 // DropTable drops table in database. 284 func (m *Meta) DropTable(dbID int64, tableID int64) error { 285 // Check if db exists. 286 dbKey := m.dbKey(dbID) 287 if err := m.checkDBExists(dbKey); err != nil { 288 return errors.Trace(err) 289 } 290 291 // Check if table exists. 292 tableKey := m.tableKey(tableID) 293 if err := m.checkTableExists(dbKey, tableKey); err != nil { 294 return errors.Trace(err) 295 } 296 297 if err := m.txn.HDel(dbKey, tableKey); err != nil { 298 return errors.Trace(err) 299 } 300 301 if err := m.txn.HDel(dbKey, m.autoTalbeIDKey(tableID)); err != nil { 302 return errors.Trace(err) 303 } 304 305 return nil 306 } 307 308 // UpdateTable updates the table with table info. 309 func (m *Meta) UpdateTable(dbID int64, tableInfo *model.TableInfo) error { 310 // Check if db exists. 311 dbKey := m.dbKey(dbID) 312 if err := m.checkDBExists(dbKey); err != nil { 313 return errors.Trace(err) 314 } 315 316 // Check if table exists. 317 tableKey := m.tableKey(tableInfo.ID) 318 if err := m.checkTableExists(dbKey, tableKey); err != nil { 319 return errors.Trace(err) 320 } 321 322 data, err := json.Marshal(tableInfo) 323 if err != nil { 324 return errors.Trace(err) 325 } 326 327 err = m.txn.HSet(dbKey, tableKey, data) 328 return errors.Trace(err) 329 } 330 331 // ListTables shows all tables in database. 332 func (m *Meta) ListTables(dbID int64) ([]*model.TableInfo, error) { 333 dbKey := m.dbKey(dbID) 334 if err := m.checkDBExists(dbKey); err != nil { 335 return nil, errors.Trace(err) 336 } 337 338 res, err := m.txn.HGetAll(dbKey) 339 if err != nil { 340 return nil, errors.Trace(err) 341 } 342 343 tables := make([]*model.TableInfo, 0, len(res)/2) 344 for _, r := range res { 345 // only handle table meta 346 tableKey := string(r.Field) 347 if !strings.HasPrefix(tableKey, mTablePrefix) { 348 continue 349 } 350 351 tbInfo := &model.TableInfo{} 352 err = json.Unmarshal(r.Value, tbInfo) 353 if err != nil { 354 return nil, errors.Trace(err) 355 } 356 357 tables = append(tables, tbInfo) 358 } 359 360 return tables, nil 361 } 362 363 // ListDatabases shows all databases. 364 func (m *Meta) ListDatabases() ([]*model.DBInfo, error) { 365 res, err := m.txn.HGetAll(mDBs) 366 if err != nil { 367 return nil, errors.Trace(err) 368 } 369 370 dbs := make([]*model.DBInfo, 0, len(res)) 371 for _, r := range res { 372 dbInfo := &model.DBInfo{} 373 err = json.Unmarshal(r.Value, dbInfo) 374 if err != nil { 375 return nil, errors.Trace(err) 376 } 377 dbs = append(dbs, dbInfo) 378 } 379 return dbs, nil 380 } 381 382 // GetDatabase gets the database value with ID. 383 func (m *Meta) GetDatabase(dbID int64) (*model.DBInfo, error) { 384 dbKey := m.dbKey(dbID) 385 value, err := m.txn.HGet(mDBs, dbKey) 386 if err != nil || value == nil { 387 return nil, errors.Trace(err) 388 } 389 390 dbInfo := &model.DBInfo{} 391 err = json.Unmarshal(value, dbInfo) 392 return dbInfo, errors.Trace(err) 393 } 394 395 // GetTable gets the table value in database with tableID. 396 func (m *Meta) GetTable(dbID int64, tableID int64) (*model.TableInfo, error) { 397 // Check if db exists. 398 dbKey := m.dbKey(dbID) 399 if err := m.checkDBExists(dbKey); err != nil { 400 return nil, errors.Trace(err) 401 } 402 403 tableKey := m.tableKey(tableID) 404 value, err := m.txn.HGet(dbKey, tableKey) 405 if err != nil || value == nil { 406 return nil, errors.Trace(err) 407 } 408 409 tableInfo := &model.TableInfo{} 410 err = json.Unmarshal(value, tableInfo) 411 return tableInfo, errors.Trace(err) 412 } 413 414 // DDL job structure 415 // DDLOnwer: []byte 416 // DDLJobList: list jobs 417 // DDLJobHistory: hash 418 // DDLJobReorg: hash 419 // 420 // for multi DDL workers, only one can become the owner 421 // to operate DDL jobs, and dispatch them to MR Jobs. 422 423 var ( 424 mDDLJobOwnerKey = []byte("DDLJobOwner") 425 mDDLJobListKey = []byte("DDLJobList") 426 mDDLJobHistoryKey = []byte("DDLJobHistory") 427 mDDLJobReorgKey = []byte("DDLJobReorg") 428 ) 429 430 func (m *Meta) getJobOwner(key []byte) (*model.Owner, error) { 431 value, err := m.txn.Get(key) 432 if err != nil || value == nil { 433 return nil, errors.Trace(err) 434 } 435 436 owner := &model.Owner{} 437 err = json.Unmarshal(value, owner) 438 return owner, errors.Trace(err) 439 } 440 441 // GetDDLJobOwner gets the current owner for DDL. 442 func (m *Meta) GetDDLJobOwner() (*model.Owner, error) { 443 return m.getJobOwner(mDDLJobOwnerKey) 444 } 445 446 func (m *Meta) setJobOwner(key []byte, o *model.Owner) error { 447 b, err := json.Marshal(o) 448 if err != nil { 449 return errors.Trace(err) 450 } 451 return m.txn.Set(key, b) 452 } 453 454 // SetDDLJobOwner sets the current owner for DDL. 455 func (m *Meta) SetDDLJobOwner(o *model.Owner) error { 456 return m.setJobOwner(mDDLJobOwnerKey, o) 457 } 458 459 func (m *Meta) enQueueDDLJob(key []byte, job *model.Job) error { 460 b, err := job.Encode() 461 if err != nil { 462 return errors.Trace(err) 463 } 464 return m.txn.RPush(key, b) 465 } 466 467 // EnQueueDDLJob adds a DDL job to the list. 468 func (m *Meta) EnQueueDDLJob(job *model.Job) error { 469 return m.enQueueDDLJob(mDDLJobListKey, job) 470 } 471 472 func (m *Meta) deQueueDDLJob(key []byte) (*model.Job, error) { 473 value, err := m.txn.LPop(key) 474 if err != nil || value == nil { 475 return nil, errors.Trace(err) 476 } 477 478 job := &model.Job{} 479 err = job.Decode(value) 480 return job, errors.Trace(err) 481 } 482 483 // DeQueueDDLJob pops a DDL job from the list. 484 func (m *Meta) DeQueueDDLJob() (*model.Job, error) { 485 return m.deQueueDDLJob(mDDLJobListKey) 486 } 487 488 func (m *Meta) getDDLJob(key []byte, index int64) (*model.Job, error) { 489 value, err := m.txn.LIndex(key, index) 490 if err != nil || value == nil { 491 return nil, errors.Trace(err) 492 } 493 494 job := &model.Job{} 495 err = job.Decode(value) 496 return job, errors.Trace(err) 497 } 498 499 // GetDDLJob returns the DDL job with index. 500 func (m *Meta) GetDDLJob(index int64) (*model.Job, error) { 501 job, err := m.getDDLJob(mDDLJobListKey, index) 502 return job, errors.Trace(err) 503 } 504 505 func (m *Meta) updateDDLJob(index int64, job *model.Job, key []byte) error { 506 // TODO: use timestamp allocated by TSO 507 job.LastUpdateTS = time.Now().UnixNano() 508 b, err := job.Encode() 509 if err != nil { 510 return errors.Trace(err) 511 } 512 return m.txn.LSet(key, index, b) 513 } 514 515 // UpdateDDLJob updates the DDL job with index. 516 func (m *Meta) UpdateDDLJob(index int64, job *model.Job) error { 517 return m.updateDDLJob(index, job, mDDLJobListKey) 518 } 519 520 // DDLJobQueueLen returns the DDL job queue length. 521 func (m *Meta) DDLJobQueueLen() (int64, error) { 522 return m.txn.LLen(mDDLJobListKey) 523 } 524 525 func (m *Meta) jobIDKey(id int64) []byte { 526 b := make([]byte, 8) 527 binary.BigEndian.PutUint64(b, uint64(id)) 528 return b 529 } 530 531 func (m *Meta) addHistoryDDLJob(key []byte, job *model.Job) error { 532 b, err := job.Encode() 533 if err != nil { 534 return errors.Trace(err) 535 } 536 537 return m.txn.HSet(key, m.jobIDKey(job.ID), b) 538 } 539 540 // AddHistoryDDLJob adds DDL job to history. 541 func (m *Meta) AddHistoryDDLJob(job *model.Job) error { 542 return m.addHistoryDDLJob(mDDLJobHistoryKey, job) 543 } 544 545 func (m *Meta) getHistoryDDLJob(key []byte, id int64) (*model.Job, error) { 546 value, err := m.txn.HGet(key, m.jobIDKey(id)) 547 if err != nil || value == nil { 548 return nil, errors.Trace(err) 549 } 550 551 job := &model.Job{} 552 err = job.Decode(value) 553 return job, errors.Trace(err) 554 } 555 556 // GetHistoryDDLJob gets a history DDL job. 557 func (m *Meta) GetHistoryDDLJob(id int64) (*model.Job, error) { 558 return m.getHistoryDDLJob(mDDLJobHistoryKey, id) 559 } 560 561 // IsBootstrapped returns whether we have already run bootstrap or not. 562 // return true means we don't need doing any other bootstrap. 563 func (m *Meta) IsBootstrapped() (bool, error) { 564 value, err := m.txn.GetInt64(mBootstrapKey) 565 if err != nil { 566 return false, errors.Trace(err) 567 } 568 return value == 1, nil 569 } 570 571 // FinishBootstrap finishes bootstrap. 572 func (m *Meta) FinishBootstrap() error { 573 err := m.txn.Set(mBootstrapKey, []byte("1")) 574 return errors.Trace(err) 575 } 576 577 // UpdateDDLReorgHandle saves the job reorganization latest processed handle for later resuming. 578 func (m *Meta) UpdateDDLReorgHandle(job *model.Job, handle int64) error { 579 err := m.txn.HSet(mDDLJobReorgKey, m.jobIDKey(job.ID), []byte(strconv.FormatInt(handle, 10))) 580 return errors.Trace(err) 581 } 582 583 // RemoveDDLReorgHandle removes the job reorganization handle. 584 func (m *Meta) RemoveDDLReorgHandle(job *model.Job) error { 585 err := m.txn.HDel(mDDLJobReorgKey, m.jobIDKey(job.ID)) 586 return errors.Trace(err) 587 } 588 589 // GetDDLReorgHandle gets the latest processed handle. 590 func (m *Meta) GetDDLReorgHandle(job *model.Job) (int64, error) { 591 value, err := m.txn.HGetInt64(mDDLJobReorgKey, m.jobIDKey(job.ID)) 592 return value, errors.Trace(err) 593 } 594 595 // DDL background job structure 596 // BgJobOnwer: []byte 597 // BgJobList: list jobs 598 // BgJobHistory: hash 599 // BgJobReorg: hash 600 // 601 // for multi background worker, only one can become the owner 602 // to operate background job, and dispatch them to MR background job. 603 604 var ( 605 mBgJobOwnerKey = []byte("BgJobOwner") 606 mBgJobListKey = []byte("BgJobList") 607 mBgJobHistoryKey = []byte("BgJobHistory") 608 ) 609 610 // UpdateBgJob updates the background job with index. 611 func (m *Meta) UpdateBgJob(index int64, job *model.Job) error { 612 return m.updateDDLJob(index, job, mBgJobListKey) 613 } 614 615 // GetBgJob returns the background job with index. 616 func (m *Meta) GetBgJob(index int64) (*model.Job, error) { 617 job, err := m.getDDLJob(mBgJobListKey, index) 618 619 return job, errors.Trace(err) 620 } 621 622 // EnQueueBgJob adds a background job to the list. 623 func (m *Meta) EnQueueBgJob(job *model.Job) error { 624 return m.enQueueDDLJob(mBgJobListKey, job) 625 } 626 627 // BgJobQueueLen returns the background job queue length. 628 func (m *Meta) BgJobQueueLen() (int64, error) { 629 return m.txn.LLen(mBgJobListKey) 630 } 631 632 // AddHistoryBgJob adds background job to history. 633 func (m *Meta) AddHistoryBgJob(job *model.Job) error { 634 return m.addHistoryDDLJob(mBgJobHistoryKey, job) 635 } 636 637 // GetHistoryBgJob gets a history background job. 638 func (m *Meta) GetHistoryBgJob(id int64) (*model.Job, error) { 639 return m.getHistoryDDLJob(mBgJobHistoryKey, id) 640 } 641 642 // DeQueueBgJob pops a background job from the list. 643 func (m *Meta) DeQueueBgJob() (*model.Job, error) { 644 return m.deQueueDDLJob(mBgJobListKey) 645 } 646 647 // GetBgJobOwner gets the current background job owner. 648 func (m *Meta) GetBgJobOwner() (*model.Owner, error) { 649 return m.getJobOwner(mBgJobOwnerKey) 650 } 651 652 // SetBgJobOwner sets the current background job owner. 653 func (m *Meta) SetBgJobOwner(o *model.Owner) error { 654 return m.setJobOwner(mBgJobOwnerKey, o) 655 } 656 657 // meta error codes. 658 const ( 659 codeInvalidTableKey terror.ErrCode = 1 660 codeInvalidDBKey = 2 661 662 codeDatabaseExists = 1007 663 codeDatabaseNotExists = 1049 664 codeTableExists = 1050 665 codeTableNotExists = 1146 666 ) 667 668 func init() { 669 metaMySQLErrCodes := map[terror.ErrCode]uint16{ 670 codeDatabaseExists: mysql.ErrDBCreateExists, 671 codeDatabaseNotExists: mysql.ErrBadDB, 672 codeTableNotExists: mysql.ErrNoSuchTable, 673 codeTableExists: mysql.ErrTableExists, 674 } 675 terror.ErrClassToMySQLCodes[terror.ClassMeta] = metaMySQLErrCodes 676 }