github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/meta/meta.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 spacetime 15 16 import ( 17 "encoding/binary" 18 "encoding/json" 19 "fmt" 20 "math" 21 "sort" 22 "strconv" 23 "strings" 24 "sync" 25 "time" 26 27 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 28 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 29 "github.com/whtcorpsinc/BerolinaSQL/terror" 30 "github.com/whtcorpsinc/errors" 31 "github.com/whtcorpsinc/milevadb/ekv" 32 "github.com/whtcorpsinc/milevadb/metrics" 33 "github.com/whtcorpsinc/milevadb/soliton/logutil" 34 "github.com/whtcorpsinc/milevadb/structure" 35 "go.uber.org/zap" 36 ) 37 38 var ( 39 globalIDMutex sync.Mutex 40 ) 41 42 // Meta structure: 43 // NextGlobalID -> int64 44 // SchemaVersion -> int64 45 // DBs -> { 46 // EDB:1 -> EDB spacetime data []byte 47 // EDB:2 -> EDB spacetime data []byte 48 // } 49 // EDB:1 -> { 50 // Block:1 -> causet spacetime data []byte 51 // Block:2 -> causet spacetime data []byte 52 // TID:1 -> int64 53 // TID:2 -> int64 54 // } 55 // 56 57 var ( 58 mMetaPrefix = []byte("m") 59 mNextGlobalIDKey = []byte("NextGlobalID") 60 mSchemaVersionKey = []byte("SchemaVersionKey") 61 mDBs = []byte("DBs") 62 mDBPrefix = "EDB" 63 mBlockPrefix = "Block" 64 mSequencePrefix = "SID" 65 mSeqCyclePrefix = "SequenceCycle" 66 mBlockIDPrefix = "TID" 67 mRandomIDPrefix = "TARID" 68 mBootstrapKey = []byte("BootstrapKey") 69 mSchemaDiffPrefix = "Diff" 70 ) 71 72 var ( 73 // ErrDBExists is the error for EDB exists. 74 ErrDBExists = terror.ClassMeta.New(allegrosql.ErrDBCreateExists, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrDBCreateExists]) 75 // ErrDBNotExists is the error for EDB not exists. 76 ErrDBNotExists = terror.ClassMeta.New(allegrosql.ErrBadDB, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrBadDB]) 77 // ErrBlockExists is the error for causet exists. 78 ErrBlockExists = terror.ClassMeta.New(allegrosql.ErrBlockExists, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrBlockExists]) 79 // ErrBlockNotExists is the error for causet not exists. 80 ErrBlockNotExists = terror.ClassMeta.New(allegrosql.ErrNoSuchBlock, allegrosql.MyALLEGROSQLErrName[allegrosql.ErrNoSuchBlock]) 81 ) 82 83 // Meta is for handling spacetime information in a transaction. 84 type Meta struct { 85 txn *structure.TxStructure 86 StartTS uint64 // StartTS is the txn's start TS. 87 jobListKey JobListKeyType 88 } 89 90 // NewMeta creates a Meta in transaction txn. 91 // If the current Meta needs to handle a job, jobListKey is the type of the job's list. 92 func NewMeta(txn ekv.Transaction, jobListKeys ...JobListKeyType) *Meta { 93 txn.SetOption(ekv.Priority, ekv.PriorityHigh) 94 txn.SetOption(ekv.SyncLog, true) 95 t := structure.NewStructure(txn, txn, mMetaPrefix) 96 listKey := DefaultJobListKey 97 if len(jobListKeys) != 0 { 98 listKey = jobListKeys[0] 99 } 100 return &Meta{txn: t, 101 StartTS: txn.StartTS(), 102 jobListKey: listKey, 103 } 104 } 105 106 // NewSnapshotMeta creates a Meta with snapshot. 107 func NewSnapshotMeta(snapshot ekv.Snapshot) *Meta { 108 t := structure.NewStructure(snapshot, nil, mMetaPrefix) 109 return &Meta{txn: t} 110 } 111 112 // GenGlobalID generates next id globally. 113 func (m *Meta) GenGlobalID() (int64, error) { 114 globalIDMutex.Lock() 115 defer globalIDMutex.Unlock() 116 117 return m.txn.Inc(mNextGlobalIDKey, 1) 118 } 119 120 // GenGlobalIDs generates the next n global IDs. 121 func (m *Meta) GenGlobalIDs(n int) ([]int64, error) { 122 globalIDMutex.Lock() 123 defer globalIDMutex.Unlock() 124 125 newID, err := m.txn.Inc(mNextGlobalIDKey, int64(n)) 126 if err != nil { 127 return nil, err 128 } 129 origID := newID - int64(n) 130 ids := make([]int64, 0, n) 131 for i := origID + 1; i <= newID; i++ { 132 ids = append(ids, i) 133 } 134 return ids, nil 135 } 136 137 // GetGlobalID gets current global id. 138 func (m *Meta) GetGlobalID() (int64, error) { 139 return m.txn.GetInt64(mNextGlobalIDKey) 140 } 141 142 func (m *Meta) dbKey(dbID int64) []byte { 143 return []byte(fmt.Sprintf("%s:%d", mDBPrefix, dbID)) 144 } 145 146 func (m *Meta) autoBlockIDKey(blockID int64) []byte { 147 return []byte(fmt.Sprintf("%s:%d", mBlockIDPrefix, blockID)) 148 } 149 150 func (m *Meta) autoRandomBlockIDKey(blockID int64) []byte { 151 return []byte(fmt.Sprintf("%s:%d", mRandomIDPrefix, blockID)) 152 } 153 154 func (m *Meta) blockKey(blockID int64) []byte { 155 return []byte(fmt.Sprintf("%s:%d", mBlockPrefix, blockID)) 156 } 157 158 func (m *Meta) sequenceKey(sequenceID int64) []byte { 159 return []byte(fmt.Sprintf("%s:%d", mSequencePrefix, sequenceID)) 160 } 161 162 func (m *Meta) sequenceCycleKey(sequenceID int64) []byte { 163 return []byte(fmt.Sprintf("%s:%d", mSeqCyclePrefix, sequenceID)) 164 } 165 166 // DBSJobHistoryKey is only used for testing. 167 func DBSJobHistoryKey(m *Meta, jobID int64) []byte { 168 return m.txn.EncodeHashDataKey(mDBSJobHistoryKey, m.jobIDKey(jobID)) 169 } 170 171 // GenAutoBlockIDKeyValue generates spacetime key by dbID, blockID and corresponding value by autoID. 172 func (m *Meta) GenAutoBlockIDKeyValue(dbID, blockID, autoID int64) (key, value []byte) { 173 dbKey := m.dbKey(dbID) 174 autoBlockIDKey := m.autoBlockIDKey(blockID) 175 return m.txn.EncodeHashAutoIDKeyValue(dbKey, autoBlockIDKey, autoID) 176 } 177 178 // GenAutoBlockID adds step to the auto ID of the causet and returns the sum. 179 func (m *Meta) GenAutoBlockID(dbID, blockID, step int64) (int64, error) { 180 // Check if EDB exists. 181 dbKey := m.dbKey(dbID) 182 if err := m.checkDBExists(dbKey); err != nil { 183 return 0, errors.Trace(err) 184 } 185 // Check if causet exists. 186 blockKey := m.blockKey(blockID) 187 if err := m.checkBlockExists(dbKey, blockKey); err != nil { 188 return 0, errors.Trace(err) 189 } 190 191 return m.txn.HInc(dbKey, m.autoBlockIDKey(blockID), step) 192 } 193 194 // GenAutoRandomID adds step to the auto shard ID of the causet and returns the sum. 195 func (m *Meta) GenAutoRandomID(dbID, blockID, step int64) (int64, error) { 196 // Check if EDB exists. 197 dbKey := m.dbKey(dbID) 198 if err := m.checkDBExists(dbKey); err != nil { 199 return 0, errors.Trace(err) 200 } 201 // Check if causet exists. 202 blockKey := m.blockKey(blockID) 203 if err := m.checkBlockExists(dbKey, blockKey); err != nil { 204 return 0, errors.Trace(err) 205 } 206 207 return m.txn.HInc(dbKey, m.autoRandomBlockIDKey(blockID), step) 208 } 209 210 // GetAutoBlockID gets current auto id with causet id. 211 func (m *Meta) GetAutoBlockID(dbID int64, blockID int64) (int64, error) { 212 return m.txn.HGetInt64(m.dbKey(dbID), m.autoBlockIDKey(blockID)) 213 } 214 215 // GetAutoRandomID gets current auto random id with causet id. 216 func (m *Meta) GetAutoRandomID(dbID int64, blockID int64) (int64, error) { 217 return m.txn.HGetInt64(m.dbKey(dbID), m.autoRandomBlockIDKey(blockID)) 218 } 219 220 // GenSequenceValue adds step to the sequence value and returns the sum. 221 func (m *Meta) GenSequenceValue(dbID, sequenceID, step int64) (int64, error) { 222 // Check if EDB exists. 223 dbKey := m.dbKey(dbID) 224 if err := m.checkDBExists(dbKey); err != nil { 225 return 0, errors.Trace(err) 226 } 227 // Check if sequence exists. 228 blockKey := m.blockKey(sequenceID) 229 if err := m.checkBlockExists(dbKey, blockKey); err != nil { 230 return 0, errors.Trace(err) 231 } 232 return m.txn.HInc(dbKey, m.sequenceKey(sequenceID), step) 233 } 234 235 // GetSequenceValue gets current sequence value with sequence id. 236 func (m *Meta) GetSequenceValue(dbID int64, sequenceID int64) (int64, error) { 237 return m.txn.HGetInt64(m.dbKey(dbID), m.sequenceKey(sequenceID)) 238 } 239 240 // SetSequenceValue sets start value when sequence in cycle. 241 func (m *Meta) SetSequenceValue(dbID int64, sequenceID int64, start int64) error { 242 return m.txn.HSet(m.dbKey(dbID), m.sequenceKey(sequenceID), []byte(strconv.FormatInt(start, 10))) 243 } 244 245 // GetSequenceCycle gets current sequence cycle times with sequence id. 246 func (m *Meta) GetSequenceCycle(dbID int64, sequenceID int64) (int64, error) { 247 return m.txn.HGetInt64(m.dbKey(dbID), m.sequenceCycleKey(sequenceID)) 248 } 249 250 // SetSequenceCycle sets cycle times value when sequence in cycle. 251 func (m *Meta) SetSequenceCycle(dbID int64, sequenceID int64, round int64) error { 252 return m.txn.HSet(m.dbKey(dbID), m.sequenceCycleKey(sequenceID), []byte(strconv.FormatInt(round, 10))) 253 } 254 255 // GetSchemaVersion gets current global schemaReplicant version. 256 func (m *Meta) GetSchemaVersion() (int64, error) { 257 return m.txn.GetInt64(mSchemaVersionKey) 258 } 259 260 // GenSchemaVersion generates next schemaReplicant version. 261 func (m *Meta) GenSchemaVersion() (int64, error) { 262 return m.txn.Inc(mSchemaVersionKey, 1) 263 } 264 265 func (m *Meta) checkDBExists(dbKey []byte) error { 266 v, err := m.txn.HGet(mDBs, dbKey) 267 if err == nil && v == nil { 268 err = ErrDBNotExists.GenWithStack("database doesn't exist") 269 } 270 return errors.Trace(err) 271 } 272 273 func (m *Meta) checkDBNotExists(dbKey []byte) error { 274 v, err := m.txn.HGet(mDBs, dbKey) 275 if err == nil && v != nil { 276 err = ErrDBExists.GenWithStack("database already exists") 277 } 278 return errors.Trace(err) 279 } 280 281 func (m *Meta) checkBlockExists(dbKey []byte, blockKey []byte) error { 282 v, err := m.txn.HGet(dbKey, blockKey) 283 if err == nil && v == nil { 284 err = ErrBlockNotExists.GenWithStack("causet doesn't exist") 285 } 286 return errors.Trace(err) 287 } 288 289 func (m *Meta) checkBlockNotExists(dbKey []byte, blockKey []byte) error { 290 v, err := m.txn.HGet(dbKey, blockKey) 291 if err == nil && v != nil { 292 err = ErrBlockExists.GenWithStack("causet already exists") 293 } 294 return errors.Trace(err) 295 } 296 297 // CreateDatabase creates a database with EDB info. 298 func (m *Meta) CreateDatabase(dbInfo *perceptron.DBInfo) error { 299 dbKey := m.dbKey(dbInfo.ID) 300 301 if err := m.checkDBNotExists(dbKey); err != nil { 302 return errors.Trace(err) 303 } 304 305 data, err := json.Marshal(dbInfo) 306 if err != nil { 307 return errors.Trace(err) 308 } 309 310 return m.txn.HSet(mDBs, dbKey, data) 311 } 312 313 // UFIDelateDatabase uFIDelates a database with EDB info. 314 func (m *Meta) UFIDelateDatabase(dbInfo *perceptron.DBInfo) error { 315 dbKey := m.dbKey(dbInfo.ID) 316 317 if err := m.checkDBExists(dbKey); err != nil { 318 return errors.Trace(err) 319 } 320 321 data, err := json.Marshal(dbInfo) 322 if err != nil { 323 return errors.Trace(err) 324 } 325 326 return m.txn.HSet(mDBs, dbKey, data) 327 } 328 329 // CreateBlockOrView creates a causet with blockInfo in database. 330 func (m *Meta) CreateBlockOrView(dbID int64, blockInfo *perceptron.BlockInfo) error { 331 // Check if EDB exists. 332 dbKey := m.dbKey(dbID) 333 if err := m.checkDBExists(dbKey); err != nil { 334 return errors.Trace(err) 335 } 336 337 // Check if causet exists. 338 blockKey := m.blockKey(blockInfo.ID) 339 if err := m.checkBlockNotExists(dbKey, blockKey); err != nil { 340 return errors.Trace(err) 341 } 342 343 data, err := json.Marshal(blockInfo) 344 if err != nil { 345 return errors.Trace(err) 346 } 347 348 return m.txn.HSet(dbKey, blockKey, data) 349 } 350 351 // CreateBlockAndSetAutoID creates a causet with blockInfo in database, 352 // and rebases the causet autoID. 353 func (m *Meta) CreateBlockAndSetAutoID(dbID int64, blockInfo *perceptron.BlockInfo, autoIncID, autoRandID int64) error { 354 err := m.CreateBlockOrView(dbID, blockInfo) 355 if err != nil { 356 return errors.Trace(err) 357 } 358 _, err = m.txn.HInc(m.dbKey(dbID), m.autoBlockIDKey(blockInfo.ID), autoIncID) 359 if err != nil { 360 return errors.Trace(err) 361 } 362 if blockInfo.AutoRandomBits > 0 { 363 _, err = m.txn.HInc(m.dbKey(dbID), m.autoRandomBlockIDKey(blockInfo.ID), autoRandID) 364 if err != nil { 365 return errors.Trace(err) 366 } 367 } 368 return nil 369 } 370 371 // CreateSequenceAndSetSeqValue creates sequence with blockInfo in database, and rebase the sequence seqValue. 372 func (m *Meta) CreateSequenceAndSetSeqValue(dbID int64, blockInfo *perceptron.BlockInfo, seqValue int64) error { 373 err := m.CreateBlockOrView(dbID, blockInfo) 374 if err != nil { 375 return errors.Trace(err) 376 } 377 _, err = m.txn.HInc(m.dbKey(dbID), m.sequenceKey(blockInfo.ID), seqValue) 378 return errors.Trace(err) 379 } 380 381 // DroFIDelatabase drops whole database. 382 func (m *Meta) DroFIDelatabase(dbID int64) error { 383 // Check if EDB exists. 384 dbKey := m.dbKey(dbID) 385 if err := m.txn.HClear(dbKey); err != nil { 386 return errors.Trace(err) 387 } 388 389 if err := m.txn.HDel(mDBs, dbKey); err != nil { 390 return errors.Trace(err) 391 } 392 393 return nil 394 } 395 396 // DropSequence drops sequence in database. 397 // Sequence is made of causet struct and ekv value pair. 398 func (m *Meta) DropSequence(dbID int64, tblID int64, delAutoID bool) error { 399 err := m.DropBlockOrView(dbID, tblID, delAutoID) 400 if err != nil { 401 return err 402 } 403 err = m.txn.HDel(m.dbKey(dbID), m.sequenceKey(tblID)) 404 return errors.Trace(err) 405 } 406 407 // DropBlockOrView drops causet in database. 408 // If delAutoID is true, it will delete the auto_increment id key-value of the causet. 409 // For rename causet, we do not need to rename auto_increment id key-value. 410 func (m *Meta) DropBlockOrView(dbID int64, tblID int64, delAutoID bool) error { 411 // Check if EDB exists. 412 dbKey := m.dbKey(dbID) 413 if err := m.checkDBExists(dbKey); err != nil { 414 return errors.Trace(err) 415 } 416 417 // Check if causet exists. 418 blockKey := m.blockKey(tblID) 419 if err := m.checkBlockExists(dbKey, blockKey); err != nil { 420 return errors.Trace(err) 421 } 422 423 if err := m.txn.HDel(dbKey, blockKey); err != nil { 424 return errors.Trace(err) 425 } 426 if delAutoID { 427 if err := m.txn.HDel(dbKey, m.autoBlockIDKey(tblID)); err != nil { 428 return errors.Trace(err) 429 } 430 if err := m.txn.HDel(dbKey, m.autoRandomBlockIDKey(tblID)); err != nil { 431 return errors.Trace(err) 432 } 433 } 434 return nil 435 } 436 437 // UFIDelateBlock uFIDelates the causet with causet info. 438 func (m *Meta) UFIDelateBlock(dbID int64, blockInfo *perceptron.BlockInfo) error { 439 // Check if EDB exists. 440 dbKey := m.dbKey(dbID) 441 if err := m.checkDBExists(dbKey); err != nil { 442 return errors.Trace(err) 443 } 444 445 // Check if causet exists. 446 blockKey := m.blockKey(blockInfo.ID) 447 if err := m.checkBlockExists(dbKey, blockKey); err != nil { 448 return errors.Trace(err) 449 } 450 451 data, err := json.Marshal(blockInfo) 452 if err != nil { 453 return errors.Trace(err) 454 } 455 456 err = m.txn.HSet(dbKey, blockKey, data) 457 return errors.Trace(err) 458 } 459 460 // ListBlocks shows all blocks in database. 461 func (m *Meta) ListBlocks(dbID int64) ([]*perceptron.BlockInfo, error) { 462 dbKey := m.dbKey(dbID) 463 if err := m.checkDBExists(dbKey); err != nil { 464 return nil, errors.Trace(err) 465 } 466 467 res, err := m.txn.HGetAll(dbKey) 468 if err != nil { 469 return nil, errors.Trace(err) 470 } 471 472 blocks := make([]*perceptron.BlockInfo, 0, len(res)/2) 473 for _, r := range res { 474 // only handle causet spacetime 475 blockKey := string(r.Field) 476 if !strings.HasPrefix(blockKey, mBlockPrefix) { 477 continue 478 } 479 480 tbInfo := &perceptron.BlockInfo{} 481 err = json.Unmarshal(r.Value, tbInfo) 482 if err != nil { 483 return nil, errors.Trace(err) 484 } 485 486 blocks = append(blocks, tbInfo) 487 } 488 489 return blocks, nil 490 } 491 492 // ListDatabases shows all databases. 493 func (m *Meta) ListDatabases() ([]*perceptron.DBInfo, error) { 494 res, err := m.txn.HGetAll(mDBs) 495 if err != nil { 496 return nil, errors.Trace(err) 497 } 498 499 dbs := make([]*perceptron.DBInfo, 0, len(res)) 500 for _, r := range res { 501 dbInfo := &perceptron.DBInfo{} 502 err = json.Unmarshal(r.Value, dbInfo) 503 if err != nil { 504 return nil, errors.Trace(err) 505 } 506 dbs = append(dbs, dbInfo) 507 } 508 return dbs, nil 509 } 510 511 // GetDatabase gets the database value with ID. 512 func (m *Meta) GetDatabase(dbID int64) (*perceptron.DBInfo, error) { 513 dbKey := m.dbKey(dbID) 514 value, err := m.txn.HGet(mDBs, dbKey) 515 if err != nil || value == nil { 516 return nil, errors.Trace(err) 517 } 518 519 dbInfo := &perceptron.DBInfo{} 520 err = json.Unmarshal(value, dbInfo) 521 return dbInfo, errors.Trace(err) 522 } 523 524 // GetBlock gets the causet value in database with blockID. 525 func (m *Meta) GetBlock(dbID int64, blockID int64) (*perceptron.BlockInfo, error) { 526 // Check if EDB exists. 527 dbKey := m.dbKey(dbID) 528 if err := m.checkDBExists(dbKey); err != nil { 529 return nil, errors.Trace(err) 530 } 531 532 blockKey := m.blockKey(blockID) 533 value, err := m.txn.HGet(dbKey, blockKey) 534 if err != nil || value == nil { 535 return nil, errors.Trace(err) 536 } 537 538 blockInfo := &perceptron.BlockInfo{} 539 err = json.Unmarshal(value, blockInfo) 540 return blockInfo, errors.Trace(err) 541 } 542 543 // DBS job structure 544 // DBSJobList: list jobs 545 // DBSJobHistory: hash 546 // DBSJobReorg: hash 547 // 548 // for multi DBS workers, only one can become the tenant 549 // to operate DBS jobs, and dispatch them to MR Jobs. 550 551 var ( 552 mDBSJobListKey = []byte("DBSJobList") 553 mDBSJobAddIdxList = []byte("DBSJobAddIdxList") 554 mDBSJobHistoryKey = []byte("DBSJobHistory") 555 mDBSJobReorgKey = []byte("DBSJobReorg") 556 ) 557 558 // JobListKeyType is a key type of the DBS job queue. 559 type JobListKeyType []byte 560 561 var ( 562 // DefaultJobListKey keeps all actions of DBS jobs except "add index". 563 DefaultJobListKey JobListKeyType = mDBSJobListKey 564 // AddIndexJobListKey only keeps the action of adding index. 565 AddIndexJobListKey JobListKeyType = mDBSJobAddIdxList 566 ) 567 568 func (m *Meta) enQueueDBSJob(key []byte, job *perceptron.Job) error { 569 b, err := job.Encode(true) 570 if err == nil { 571 err = m.txn.RPush(key, b) 572 } 573 return errors.Trace(err) 574 } 575 576 // EnQueueDBSJob adds a DBS job to the list. 577 func (m *Meta) EnQueueDBSJob(job *perceptron.Job, jobListKeys ...JobListKeyType) error { 578 listKey := m.jobListKey 579 if len(jobListKeys) != 0 { 580 listKey = jobListKeys[0] 581 } 582 583 return m.enQueueDBSJob(listKey, job) 584 } 585 586 func (m *Meta) deQueueDBSJob(key []byte) (*perceptron.Job, error) { 587 value, err := m.txn.LPop(key) 588 if err != nil || value == nil { 589 return nil, errors.Trace(err) 590 } 591 592 job := &perceptron.Job{} 593 err = job.Decode(value) 594 return job, errors.Trace(err) 595 } 596 597 // DeQueueDBSJob pops a DBS job from the list. 598 func (m *Meta) DeQueueDBSJob() (*perceptron.Job, error) { 599 return m.deQueueDBSJob(m.jobListKey) 600 } 601 602 func (m *Meta) getDBSJob(key []byte, index int64) (*perceptron.Job, error) { 603 value, err := m.txn.LIndex(key, index) 604 if err != nil || value == nil { 605 return nil, errors.Trace(err) 606 } 607 608 job := &perceptron.Job{ 609 // For compatibility, if the job is enqueued by old version MilevaDB and Priority field is omitted, 610 // set the default priority to ekv.PriorityLow. 611 Priority: ekv.PriorityLow, 612 } 613 err = job.Decode(value) 614 // Check if the job.Priority is valid. 615 if job.Priority < ekv.PriorityNormal || job.Priority > ekv.PriorityHigh { 616 job.Priority = ekv.PriorityLow 617 } 618 return job, errors.Trace(err) 619 } 620 621 // GetDBSJobByIdx returns the corresponding DBS job by the index. 622 // The length of jobListKeys can only be 1 or 0. 623 // If its length is 1, we need to replace m.jobListKey with jobListKeys[0]. 624 // Otherwise, we use m.jobListKey directly. 625 func (m *Meta) GetDBSJobByIdx(index int64, jobListKeys ...JobListKeyType) (*perceptron.Job, error) { 626 listKey := m.jobListKey 627 if len(jobListKeys) != 0 { 628 listKey = jobListKeys[0] 629 } 630 631 startTime := time.Now() 632 job, err := m.getDBSJob(listKey, index) 633 metrics.MetaHistogram.WithLabelValues(metrics.GetDBSJobByIdx, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds()) 634 return job, errors.Trace(err) 635 } 636 637 // uFIDelateDBSJob uFIDelates the DBS job with index and key. 638 // uFIDelateRawArgs is used to determine whether to uFIDelate the raw args when encode the job. 639 func (m *Meta) uFIDelateDBSJob(index int64, job *perceptron.Job, key []byte, uFIDelateRawArgs bool) error { 640 b, err := job.Encode(uFIDelateRawArgs) 641 if err == nil { 642 err = m.txn.LSet(key, index, b) 643 } 644 return errors.Trace(err) 645 } 646 647 // UFIDelateDBSJob uFIDelates the DBS job with index. 648 // uFIDelateRawArgs is used to determine whether to uFIDelate the raw args when encode the job. 649 // The length of jobListKeys can only be 1 or 0. 650 // If its length is 1, we need to replace m.jobListKey with jobListKeys[0]. 651 // Otherwise, we use m.jobListKey directly. 652 func (m *Meta) UFIDelateDBSJob(index int64, job *perceptron.Job, uFIDelateRawArgs bool, jobListKeys ...JobListKeyType) error { 653 listKey := m.jobListKey 654 if len(jobListKeys) != 0 { 655 listKey = jobListKeys[0] 656 } 657 658 startTime := time.Now() 659 err := m.uFIDelateDBSJob(index, job, listKey, uFIDelateRawArgs) 660 metrics.MetaHistogram.WithLabelValues(metrics.UFIDelateDBSJob, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds()) 661 return errors.Trace(err) 662 } 663 664 // DBSJobQueueLen returns the DBS job queue length. 665 // The length of jobListKeys can only be 1 or 0. 666 // If its length is 1, we need to replace m.jobListKey with jobListKeys[0]. 667 // Otherwise, we use m.jobListKey directly. 668 func (m *Meta) DBSJobQueueLen(jobListKeys ...JobListKeyType) (int64, error) { 669 listKey := m.jobListKey 670 if len(jobListKeys) != 0 { 671 listKey = jobListKeys[0] 672 } 673 return m.txn.LLen(listKey) 674 } 675 676 // GetAllDBSJobsInQueue gets all DBS Jobs in the current queue. 677 // The length of jobListKeys can only be 1 or 0. 678 // If its length is 1, we need to replace m.jobListKey with jobListKeys[0]. 679 // Otherwise, we use m.jobListKey directly. 680 func (m *Meta) GetAllDBSJobsInQueue(jobListKeys ...JobListKeyType) ([]*perceptron.Job, error) { 681 listKey := m.jobListKey 682 if len(jobListKeys) != 0 { 683 listKey = jobListKeys[0] 684 } 685 686 values, err := m.txn.LGetAll(listKey) 687 if err != nil || values == nil { 688 return nil, errors.Trace(err) 689 } 690 691 jobs := make([]*perceptron.Job, 0, len(values)) 692 for _, val := range values { 693 job := &perceptron.Job{} 694 err = job.Decode(val) 695 if err != nil { 696 return nil, errors.Trace(err) 697 } 698 jobs = append(jobs, job) 699 } 700 701 return jobs, nil 702 } 703 704 func (m *Meta) jobIDKey(id int64) []byte { 705 b := make([]byte, 8) 706 binary.BigEndian.PutUint64(b, uint64(id)) 707 return b 708 } 709 710 func (m *Meta) reorgJobStartHandle(id int64) []byte { 711 // There is no "_start", to make it compatible with the older MilevaDB versions. 712 return m.jobIDKey(id) 713 } 714 715 func (m *Meta) reorgJobEndHandle(id int64) []byte { 716 b := make([]byte, 8, 12) 717 binary.BigEndian.PutUint64(b, uint64(id)) 718 b = append(b, "_end"...) 719 return b 720 } 721 722 func (m *Meta) reorgJobPhysicalBlockID(id int64) []byte { 723 b := make([]byte, 8, 12) 724 binary.BigEndian.PutUint64(b, uint64(id)) 725 b = append(b, "_pid"...) 726 return b 727 } 728 729 func (m *Meta) addHistoryDBSJob(key []byte, job *perceptron.Job, uFIDelateRawArgs bool) error { 730 b, err := job.Encode(uFIDelateRawArgs) 731 if err == nil { 732 err = m.txn.HSet(key, m.jobIDKey(job.ID), b) 733 } 734 return errors.Trace(err) 735 } 736 737 // AddHistoryDBSJob adds DBS job to history. 738 func (m *Meta) AddHistoryDBSJob(job *perceptron.Job, uFIDelateRawArgs bool) error { 739 return m.addHistoryDBSJob(mDBSJobHistoryKey, job, uFIDelateRawArgs) 740 } 741 742 func (m *Meta) getHistoryDBSJob(key []byte, id int64) (*perceptron.Job, error) { 743 value, err := m.txn.HGet(key, m.jobIDKey(id)) 744 if err != nil || value == nil { 745 return nil, errors.Trace(err) 746 } 747 748 job := &perceptron.Job{} 749 err = job.Decode(value) 750 return job, errors.Trace(err) 751 } 752 753 // GetHistoryDBSJob gets a history DBS job. 754 func (m *Meta) GetHistoryDBSJob(id int64) (*perceptron.Job, error) { 755 startTime := time.Now() 756 job, err := m.getHistoryDBSJob(mDBSJobHistoryKey, id) 757 metrics.MetaHistogram.WithLabelValues(metrics.GetHistoryDBSJob, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds()) 758 return job, errors.Trace(err) 759 } 760 761 // GetAllHistoryDBSJobs gets all history DBS jobs. 762 func (m *Meta) GetAllHistoryDBSJobs() ([]*perceptron.Job, error) { 763 pairs, err := m.txn.HGetAll(mDBSJobHistoryKey) 764 if err != nil { 765 return nil, errors.Trace(err) 766 } 767 jobs, err := decodeJob(pairs) 768 if err != nil { 769 return nil, errors.Trace(err) 770 } 771 // sort job. 772 sorter := &jobsSorter{jobs: jobs} 773 sort.Sort(sorter) 774 return jobs, nil 775 } 776 777 // GetLastNHistoryDBSJobs gets latest N history dbs jobs. 778 func (m *Meta) GetLastNHistoryDBSJobs(num int) ([]*perceptron.Job, error) { 779 pairs, err := m.txn.HGetLastN(mDBSJobHistoryKey, num) 780 if err != nil { 781 return nil, errors.Trace(err) 782 } 783 return decodeJob(pairs) 784 } 785 786 // LastJobIterator is the iterator for gets latest history. 787 type LastJobIterator struct { 788 iter *structure.ReverseHashIterator 789 } 790 791 // GetLastHistoryDBSJobsIterator gets latest N history dbs jobs iterator. 792 func (m *Meta) GetLastHistoryDBSJobsIterator() (*LastJobIterator, error) { 793 iter, err := structure.NewHashReverseIter(m.txn, mDBSJobHistoryKey) 794 if err != nil { 795 return nil, err 796 } 797 return &LastJobIterator{ 798 iter: iter, 799 }, nil 800 } 801 802 // GetLastJobs gets last several jobs. 803 func (i *LastJobIterator) GetLastJobs(num int, jobs []*perceptron.Job) ([]*perceptron.Job, error) { 804 if len(jobs) < num { 805 jobs = make([]*perceptron.Job, 0, num) 806 } 807 jobs = jobs[:0] 808 iter := i.iter 809 for iter.Valid() && len(jobs) < num { 810 job := &perceptron.Job{} 811 err := job.Decode(iter.Value()) 812 if err != nil { 813 return nil, errors.Trace(err) 814 } 815 jobs = append(jobs, job) 816 err = iter.Next() 817 if err != nil { 818 return nil, errors.Trace(err) 819 } 820 } 821 return jobs, nil 822 } 823 824 func decodeJob(jobPairs []structure.HashPair) ([]*perceptron.Job, error) { 825 jobs := make([]*perceptron.Job, 0, len(jobPairs)) 826 for _, pair := range jobPairs { 827 job := &perceptron.Job{} 828 err := job.Decode(pair.Value) 829 if err != nil { 830 return nil, errors.Trace(err) 831 } 832 jobs = append(jobs, job) 833 } 834 return jobs, nil 835 } 836 837 // jobsSorter implements the sort.Interface interface. 838 type jobsSorter struct { 839 jobs []*perceptron.Job 840 } 841 842 func (s *jobsSorter) Swap(i, j int) { 843 s.jobs[i], s.jobs[j] = s.jobs[j], s.jobs[i] 844 } 845 846 func (s *jobsSorter) Len() int { 847 return len(s.jobs) 848 } 849 850 func (s *jobsSorter) Less(i, j int) bool { 851 return s.jobs[i].ID < s.jobs[j].ID 852 } 853 854 // GetBootstrapVersion returns the version of the server which bootstrap the causetstore. 855 // If the causetstore is not bootstraped, the version will be zero. 856 func (m *Meta) GetBootstrapVersion() (int64, error) { 857 value, err := m.txn.GetInt64(mBootstrapKey) 858 return value, errors.Trace(err) 859 } 860 861 // FinishBootstrap finishes bootstrap. 862 func (m *Meta) FinishBootstrap(version int64) error { 863 err := m.txn.Set(mBootstrapKey, []byte(fmt.Sprintf("%d", version))) 864 return errors.Trace(err) 865 } 866 867 // UFIDelateDBSReorgStartHandle saves the job reorganization latest processed start handle for later resuming. 868 func (m *Meta) UFIDelateDBSReorgStartHandle(job *perceptron.Job, startHandle ekv.Handle) error { 869 return setReorgJobFieldHandle(m.txn, m.reorgJobStartHandle(job.ID), startHandle) 870 } 871 872 // UFIDelateDBSReorgHandle saves the job reorganization latest processed information for later resuming. 873 func (m *Meta) UFIDelateDBSReorgHandle(job *perceptron.Job, startHandle, endHandle ekv.Handle, physicalBlockID int64) error { 874 err := setReorgJobFieldHandle(m.txn, m.reorgJobStartHandle(job.ID), startHandle) 875 if err != nil { 876 return errors.Trace(err) 877 } 878 err = setReorgJobFieldHandle(m.txn, m.reorgJobEndHandle(job.ID), endHandle) 879 if err != nil { 880 return errors.Trace(err) 881 } 882 err = m.txn.HSet(mDBSJobReorgKey, m.reorgJobPhysicalBlockID(job.ID), []byte(strconv.FormatInt(physicalBlockID, 10))) 883 return errors.Trace(err) 884 } 885 886 func setReorgJobFieldHandle(t *structure.TxStructure, reorgJobField []byte, handle ekv.Handle) error { 887 if handle == nil { 888 return nil 889 } 890 var handleEncodedBytes []byte 891 if handle.IsInt() { 892 handleEncodedBytes = []byte(strconv.FormatInt(handle.IntValue(), 10)) 893 } else { 894 handleEncodedBytes = handle.Encoded() 895 } 896 return t.HSet(mDBSJobReorgKey, reorgJobField, handleEncodedBytes) 897 } 898 899 // RemoveDBSReorgHandle removes the job reorganization related handles. 900 func (m *Meta) RemoveDBSReorgHandle(job *perceptron.Job) error { 901 err := m.txn.HDel(mDBSJobReorgKey, m.reorgJobStartHandle(job.ID)) 902 if err != nil { 903 return errors.Trace(err) 904 } 905 if err = m.txn.HDel(mDBSJobReorgKey, m.reorgJobEndHandle(job.ID)); err != nil { 906 logutil.BgLogger().Warn("remove DBS reorg end handle", zap.Error(err)) 907 } 908 if err = m.txn.HDel(mDBSJobReorgKey, m.reorgJobPhysicalBlockID(job.ID)); err != nil { 909 logutil.BgLogger().Warn("remove DBS reorg physical ID", zap.Error(err)) 910 } 911 return nil 912 } 913 914 // GetDBSReorgHandle gets the latest processed DBS reorganize position. 915 func (m *Meta) GetDBSReorgHandle(job *perceptron.Job, isCommonHandle bool) (startHandle, endHandle ekv.Handle, physicalBlockID int64, err error) { 916 startHandle, err = getReorgJobFieldHandle(m.txn, m.reorgJobStartHandle(job.ID), isCommonHandle) 917 if err != nil { 918 return nil, nil, 0, errors.Trace(err) 919 } 920 endHandle, err = getReorgJobFieldHandle(m.txn, m.reorgJobEndHandle(job.ID), isCommonHandle) 921 if err != nil { 922 return nil, nil, 0, errors.Trace(err) 923 } 924 925 physicalBlockID, err = m.txn.HGetInt64(mDBSJobReorgKey, m.reorgJobPhysicalBlockID(job.ID)) 926 if err != nil { 927 err = errors.Trace(err) 928 return 929 } 930 // physicalBlockID may be 0, because older version MilevaDB (without causet partition) doesn't causetstore them. 931 // uFIDelate them to causet's in this case. 932 if physicalBlockID == 0 { 933 if job.ReorgMeta != nil { 934 endHandle = ekv.IntHandle(job.ReorgMeta.EndHandle) 935 } else { 936 endHandle = ekv.IntHandle(math.MaxInt64) 937 } 938 physicalBlockID = job.BlockID 939 logutil.BgLogger().Warn("new MilevaDB binary running on old MilevaDB DBS reorg data", 940 zap.Int64("partition ID", physicalBlockID), 941 zap.Stringer("startHandle", startHandle), 942 zap.Stringer("endHandle", endHandle)) 943 } 944 return 945 } 946 947 func getReorgJobFieldHandle(t *structure.TxStructure, reorgJobField []byte, isCommonHandle bool) (ekv.Handle, error) { 948 bs, err := t.HGet(mDBSJobReorgKey, reorgJobField) 949 if err != nil { 950 return nil, errors.Trace(err) 951 } 952 keyNotFound := bs == nil 953 if keyNotFound { 954 return nil, nil 955 } 956 if isCommonHandle { 957 return ekv.NewCommonHandle(bs) 958 } 959 var n int64 960 n, err = strconv.ParseInt(string(bs), 10, 64) 961 if err != nil { 962 return nil, err 963 } 964 return ekv.IntHandle(n), nil 965 } 966 967 func (m *Meta) schemaDiffKey(schemaVersion int64) []byte { 968 return []byte(fmt.Sprintf("%s:%d", mSchemaDiffPrefix, schemaVersion)) 969 } 970 971 // GetSchemaDiff gets the modification information on a given schemaReplicant version. 972 func (m *Meta) GetSchemaDiff(schemaVersion int64) (*perceptron.SchemaDiff, error) { 973 diffKey := m.schemaDiffKey(schemaVersion) 974 startTime := time.Now() 975 data, err := m.txn.Get(diffKey) 976 metrics.MetaHistogram.WithLabelValues(metrics.GetSchemaDiff, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds()) 977 if err != nil || len(data) == 0 { 978 return nil, errors.Trace(err) 979 } 980 diff := &perceptron.SchemaDiff{} 981 err = json.Unmarshal(data, diff) 982 return diff, errors.Trace(err) 983 } 984 985 // SetSchemaDiff sets the modification information on a given schemaReplicant version. 986 func (m *Meta) SetSchemaDiff(diff *perceptron.SchemaDiff) error { 987 data, err := json.Marshal(diff) 988 if err != nil { 989 return errors.Trace(err) 990 } 991 diffKey := m.schemaDiffKey(diff.Version) 992 startTime := time.Now() 993 err = m.txn.Set(diffKey, data) 994 metrics.MetaHistogram.WithLabelValues(metrics.SetSchemaDiff, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds()) 995 return errors.Trace(err) 996 }