github.com/iotexproject/iotex-core@v1.14.1-rc1/db/db_bolt.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package db 7 8 import ( 9 "bytes" 10 "context" 11 "syscall" 12 13 "github.com/pkg/errors" 14 "github.com/prometheus/client_golang/prometheus" 15 bolt "go.etcd.io/bbolt" 16 "go.uber.org/zap" 17 18 "github.com/iotexproject/iotex-core/db/batch" 19 "github.com/iotexproject/iotex-core/pkg/lifecycle" 20 "github.com/iotexproject/iotex-core/pkg/log" 21 "github.com/iotexproject/iotex-core/pkg/util/byteutil" 22 ) 23 24 const _fileMode = 0600 25 26 var ( 27 // ErrDBNotStarted represents the error when a db has not started 28 ErrDBNotStarted = errors.New("db has not started") 29 30 boltdbMtc = prometheus.NewGaugeVec(prometheus.GaugeOpts{ 31 Name: "iotex_boltdb_metrics", 32 Help: "boltdb metrics.", 33 }, []string{"type", "method"}) 34 ) 35 36 func init() { 37 prometheus.MustRegister(boltdbMtc) 38 } 39 40 // BoltDB is KVStore implementation based bolt DB 41 type BoltDB struct { 42 lifecycle.Readiness 43 db *bolt.DB 44 path string 45 config Config 46 } 47 48 // NewBoltDB instantiates an BoltDB with implements KVStore 49 func NewBoltDB(cfg Config) *BoltDB { 50 return &BoltDB{ 51 db: nil, 52 path: cfg.DbPath, 53 config: cfg, 54 } 55 } 56 57 // Start opens the BoltDB (creates new file if not existing yet) 58 func (b *BoltDB) Start(_ context.Context) error { 59 opts := *bolt.DefaultOptions 60 if b.config.ReadOnly { 61 opts.ReadOnly = true 62 } 63 db, err := bolt.Open(b.path, _fileMode, &opts) 64 if err != nil { 65 return errors.Wrap(ErrIO, err.Error()) 66 } 67 b.db = db 68 return b.TurnOn() 69 } 70 71 // Stop closes the BoltDB 72 func (b *BoltDB) Stop(_ context.Context) error { 73 if err := b.TurnOff(); err != nil { 74 return err 75 } 76 if err := b.db.Close(); err != nil { 77 return errors.Wrap(ErrIO, err.Error()) 78 } 79 return nil 80 } 81 82 // Put inserts a <key, value> record 83 func (b *BoltDB) Put(namespace string, key, value []byte) (err error) { 84 if !b.IsReady() { 85 return ErrDBNotStarted 86 } 87 88 for c := uint8(0); c < b.config.NumRetries; c++ { 89 if err = b.db.Update(func(tx *bolt.Tx) error { 90 bucket, err := tx.CreateBucketIfNotExists([]byte(namespace)) 91 if err != nil { 92 return err 93 } 94 return bucket.Put(key, value) 95 }); err == nil { 96 break 97 } 98 } 99 if err != nil { 100 if errors.Is(err, syscall.ENOSPC) { 101 log.L().Fatal("Failed to put db.", zap.Error(err)) 102 } 103 err = errors.Wrap(ErrIO, err.Error()) 104 } 105 return err 106 } 107 108 // Get retrieves a record 109 func (b *BoltDB) Get(namespace string, key []byte) ([]byte, error) { 110 if !b.IsReady() { 111 return nil, ErrDBNotStarted 112 } 113 114 var value []byte 115 err := b.db.View(func(tx *bolt.Tx) error { 116 bucket := tx.Bucket([]byte(namespace)) 117 if bucket == nil { 118 return errors.Wrapf(ErrNotExist, "bucket = %x doesn't exist", []byte(namespace)) 119 } 120 v := bucket.Get(key) 121 if v == nil { 122 return errors.Wrapf(ErrNotExist, "key = %x doesn't exist", key) 123 } 124 value = make([]byte, len(v)) 125 // TODO: this is not an efficient way of passing the data 126 copy(value, v) 127 return nil 128 }) 129 if err == nil { 130 return value, nil 131 } 132 if errors.Cause(err) == ErrNotExist { 133 return nil, err 134 } 135 return nil, errors.Wrap(ErrIO, err.Error()) 136 } 137 138 // Filter returns <k, v> pair in a bucket that meet the condition 139 func (b *BoltDB) Filter(namespace string, cond Condition, minKey, maxKey []byte) ([][]byte, [][]byte, error) { 140 if !b.IsReady() { 141 return nil, nil, ErrDBNotStarted 142 } 143 144 var fk, fv [][]byte 145 if err := b.db.View(func(tx *bolt.Tx) error { 146 bucket := tx.Bucket([]byte(namespace)) 147 if bucket == nil { 148 return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", []byte(namespace)) 149 } 150 151 var k, v []byte 152 c := bucket.Cursor() 153 if len(minKey) > 0 { 154 k, v = c.Seek(minKey) 155 } else { 156 k, v = c.First() 157 } 158 159 if k == nil { 160 return nil 161 } 162 163 checkMax := len(maxKey) > 0 164 for ; k != nil; k, v = c.Next() { 165 if checkMax && bytes.Compare(k, maxKey) == 1 { 166 return nil 167 } 168 if cond(k, v) { 169 key := make([]byte, len(k)) 170 copy(key, k) 171 value := make([]byte, len(v)) 172 copy(value, v) 173 fk = append(fk, key) 174 fv = append(fv, value) 175 } 176 } 177 return nil 178 }); err != nil { 179 return nil, nil, err 180 } 181 182 if len(fk) == 0 { 183 return nil, nil, errors.Wrap(ErrNotExist, "filter returns no match") 184 } 185 return fk, fv, nil 186 } 187 188 // Range retrieves values for a range of keys 189 func (b *BoltDB) Range(namespace string, key []byte, count uint64) ([][]byte, error) { 190 if !b.IsReady() { 191 return nil, ErrDBNotStarted 192 } 193 194 value := make([][]byte, count) 195 err := b.db.View(func(tx *bolt.Tx) error { 196 bucket := tx.Bucket([]byte(namespace)) 197 if bucket == nil { 198 return errors.Wrapf(ErrNotExist, "bucket = %s doesn't exist", namespace) 199 } 200 // seek to start 201 cur := bucket.Cursor() 202 k, v := cur.Seek(key) 203 if k == nil { 204 return errors.Wrapf(ErrNotExist, "entry for key 0x%x doesn't exist", key) 205 } 206 // retrieve 'count' items 207 for i := uint64(0); i < count; i++ { 208 if k == nil { 209 return errors.Wrapf(ErrNotExist, "entry for key 0x%x doesn't exist", k) 210 } 211 value[i] = make([]byte, len(v)) 212 copy(value[i], v) 213 k, v = cur.Next() 214 } 215 return nil 216 }) 217 if err == nil { 218 return value, nil 219 } 220 if errors.Cause(err) == ErrNotExist { 221 return nil, err 222 } 223 return nil, errors.Wrap(ErrIO, err.Error()) 224 } 225 226 // GetBucketByPrefix retrieves all bucket those with const namespace prefix 227 func (b *BoltDB) GetBucketByPrefix(namespace []byte) ([][]byte, error) { 228 if !b.IsReady() { 229 return nil, ErrDBNotStarted 230 } 231 232 allKey := make([][]byte, 0) 233 err := b.db.View(func(tx *bolt.Tx) error { 234 if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error { 235 if bytes.HasPrefix(name, namespace) && !bytes.Equal(name, namespace) { 236 temp := make([]byte, len(name)) 237 copy(temp, name) 238 allKey = append(allKey, temp) 239 } 240 return nil 241 }); err != nil { 242 return err 243 } 244 return nil 245 }) 246 return allKey, err 247 } 248 249 // GetKeyByPrefix retrieves all keys those with const prefix 250 func (b *BoltDB) GetKeyByPrefix(namespace, prefix []byte) ([][]byte, error) { 251 if !b.IsReady() { 252 return nil, ErrDBNotStarted 253 } 254 255 allKey := make([][]byte, 0) 256 err := b.db.View(func(tx *bolt.Tx) error { 257 buck := tx.Bucket(namespace) 258 if buck == nil { 259 return ErrNotExist 260 } 261 c := buck.Cursor() 262 for k, _ := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, _ = c.Next() { 263 temp := make([]byte, len(k)) 264 copy(temp, k) 265 allKey = append(allKey, temp) 266 } 267 return nil 268 }) 269 return allKey, err 270 } 271 272 // Delete deletes a record,if key is nil,this will delete the whole bucket 273 func (b *BoltDB) Delete(namespace string, key []byte) (err error) { 274 if !b.IsReady() { 275 return ErrDBNotStarted 276 } 277 278 numRetries := b.config.NumRetries 279 for c := uint8(0); c < numRetries; c++ { 280 if key == nil { 281 err = b.db.Update(func(tx *bolt.Tx) error { 282 if err := tx.DeleteBucket([]byte(namespace)); err != bolt.ErrBucketNotFound { 283 return err 284 } 285 return nil 286 }) 287 } else { 288 err = b.db.Update(func(tx *bolt.Tx) error { 289 bucket := tx.Bucket([]byte(namespace)) 290 if bucket == nil { 291 return nil 292 } 293 return bucket.Delete(key) 294 }) 295 } 296 if err == nil { 297 break 298 } 299 } 300 if err != nil { 301 if errors.Is(err, syscall.ENOSPC) { 302 log.L().Fatal("Failed to delete db.", zap.Error(err)) 303 } 304 err = errors.Wrap(ErrIO, err.Error()) 305 } 306 return err 307 } 308 309 // WriteBatch commits a batch 310 func (b *BoltDB) WriteBatch(kvsb batch.KVStoreBatch) (err error) { 311 if !b.IsReady() { 312 return ErrDBNotStarted 313 } 314 315 kvsb.Lock() 316 defer kvsb.Unlock() 317 318 type doubleKey struct { 319 ns string 320 key string 321 } 322 // remove duplicate keys, only keep the last write for each key 323 entryKeySet := make(map[doubleKey]struct{}) 324 uniqEntries := make([]*batch.WriteInfo, 0) 325 for i := kvsb.Size() - 1; i >= 0; i-- { 326 write, e := kvsb.Entry(i) 327 if e != nil { 328 return e 329 } 330 // only handle Put and Delete 331 if write.WriteType() != batch.Put && write.WriteType() != batch.Delete { 332 continue 333 } 334 k := doubleKey{ns: write.Namespace(), key: string(write.Key())} 335 if _, ok := entryKeySet[k]; !ok { 336 entryKeySet[k] = struct{}{} 337 uniqEntries = append(uniqEntries, write) 338 } 339 } 340 boltdbMtc.WithLabelValues(b.path, "entrySize").Set(float64(kvsb.Size())) 341 boltdbMtc.WithLabelValues(b.path, "uniqueEntrySize").Set(float64(len(entryKeySet))) 342 for c := uint8(0); c < b.config.NumRetries; c++ { 343 if err = b.db.Update(func(tx *bolt.Tx) error { 344 // keep order of the writes same as the original batch 345 for i := len(uniqEntries) - 1; i >= 0; i-- { 346 write := uniqEntries[i] 347 ns := write.Namespace() 348 switch write.WriteType() { 349 case batch.Put: 350 bucket, e := tx.CreateBucketIfNotExists([]byte(ns)) 351 if e != nil { 352 return errors.Wrap(e, write.Error()) 353 } 354 if p, ok := kvsb.CheckFillPercent(ns); ok { 355 bucket.FillPercent = p 356 } 357 if e := bucket.Put(write.Key(), write.Value()); e != nil { 358 return errors.Wrap(e, write.Error()) 359 } 360 case batch.Delete: 361 bucket := tx.Bucket([]byte(ns)) 362 if bucket == nil { 363 continue 364 } 365 if e := bucket.Delete(write.Key()); e != nil { 366 return errors.Wrap(e, write.Error()) 367 } 368 } 369 } 370 return nil 371 }); err == nil { 372 break 373 } 374 } 375 376 if err != nil { 377 if errors.Is(err, syscall.ENOSPC) { 378 log.L().Fatal("Failed to write batch db.", zap.Error(err)) 379 } 380 err = errors.Wrap(ErrIO, err.Error()) 381 } 382 return err 383 } 384 385 // BucketExists returns true if bucket exists 386 func (b *BoltDB) BucketExists(namespace string) bool { 387 if !b.IsReady() { 388 log.L().Debug(ErrDBNotStarted.Error()) 389 return false 390 } 391 392 var exist bool 393 _ = b.db.View(func(tx *bolt.Tx) error { 394 bucket := tx.Bucket([]byte(namespace)) 395 if bucket != nil { 396 exist = true 397 } 398 return nil 399 }) 400 return exist 401 } 402 403 // ====================================== 404 // below functions used by RangeIndex 405 // ====================================== 406 407 // Insert inserts a value into the index 408 func (b *BoltDB) Insert(name []byte, key uint64, value []byte) error { 409 if !b.IsReady() { 410 return ErrDBNotStarted 411 } 412 413 var err error 414 for i := uint8(0); i < b.config.NumRetries; i++ { 415 if err = b.db.Update(func(tx *bolt.Tx) error { 416 bucket := tx.Bucket(name) 417 if bucket == nil { 418 return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name) 419 } 420 cur := bucket.Cursor() 421 ak := byteutil.Uint64ToBytesBigEndian(key - 1) 422 k, v := cur.Seek(ak) 423 if !bytes.Equal(k, ak) { 424 // insert new key 425 if err := bucket.Put(ak, v); err != nil { 426 return err 427 } 428 } else { 429 // update an existing key 430 k, _ = cur.Next() 431 } 432 if k != nil { 433 return bucket.Put(k, value) 434 } 435 return nil 436 }); err == nil { 437 break 438 } 439 } 440 if err != nil { 441 if errors.Is(err, syscall.ENOSPC) { 442 log.L().Fatal("Failed to insert db.", zap.Error(err)) 443 } 444 return errors.Wrap(ErrIO, err.Error()) 445 } 446 return nil 447 } 448 449 // SeekNext returns value by the key (if key not exist, use next key) 450 func (b *BoltDB) SeekNext(name []byte, key uint64) ([]byte, error) { 451 if !b.IsReady() { 452 return nil, ErrDBNotStarted 453 } 454 455 var value []byte 456 err := b.db.View(func(tx *bolt.Tx) error { 457 bucket := tx.Bucket(name) 458 if bucket == nil { 459 return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name) 460 } 461 // seek to start 462 cur := bucket.Cursor() 463 _, v := cur.Seek(byteutil.Uint64ToBytesBigEndian(key)) 464 value = make([]byte, len(v)) 465 copy(value, v) 466 return nil 467 }) 468 if err != nil { 469 return nil, err 470 } 471 return value, nil 472 } 473 474 // SeekPrev returns value by the key (if key not exist, use previous key) 475 func (b *BoltDB) SeekPrev(name []byte, key uint64) ([]byte, error) { 476 if !b.IsReady() { 477 return nil, ErrDBNotStarted 478 } 479 480 var value []byte 481 if err := b.db.View(func(tx *bolt.Tx) error { 482 bucket := tx.Bucket(name) 483 if bucket == nil { 484 return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name) 485 } 486 // seek to start 487 cur := bucket.Cursor() 488 cur.Seek(byteutil.Uint64ToBytesBigEndian(key)) 489 _, v := cur.Prev() 490 value = make([]byte, len(v)) 491 copy(value, v) 492 return nil 493 }); err != nil { 494 return nil, err 495 } 496 return value, nil 497 } 498 499 // Remove removes an existing key 500 func (b *BoltDB) Remove(name []byte, key uint64) error { 501 if !b.IsReady() { 502 return ErrDBNotStarted 503 } 504 505 var err error 506 for i := uint8(0); i < b.config.NumRetries; i++ { 507 if err = b.db.Update(func(tx *bolt.Tx) error { 508 bucket := tx.Bucket(name) 509 if bucket == nil { 510 return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name) 511 } 512 cur := bucket.Cursor() 513 ak := byteutil.Uint64ToBytesBigEndian(key - 1) 514 k, v := cur.Seek(ak) 515 if !bytes.Equal(k, ak) { 516 // return nil if the key does not exist 517 return nil 518 } 519 if err := bucket.Delete(ak); err != nil { 520 return err 521 } 522 // write the corresponding value to next key 523 k, _ = cur.Next() 524 if k != nil { 525 return bucket.Put(k, v) 526 } 527 return nil 528 }); err == nil { 529 break 530 } 531 } 532 533 if err != nil { 534 if errors.Is(err, syscall.ENOSPC) { 535 log.L().Fatal("Failed to remove db.", zap.Error(err)) 536 } 537 err = errors.Wrap(ErrIO, err.Error()) 538 } 539 return err 540 } 541 542 // Purge deletes an existing key and all keys before it 543 func (b *BoltDB) Purge(name []byte, key uint64) error { 544 if !b.IsReady() { 545 return ErrDBNotStarted 546 } 547 548 var err error 549 for i := uint8(0); i < b.config.NumRetries; i++ { 550 if err = b.db.Update(func(tx *bolt.Tx) error { 551 bucket := tx.Bucket(name) 552 if bucket == nil { 553 return errors.Wrapf(ErrBucketNotExist, "bucket = %x doesn't exist", name) 554 } 555 cur := bucket.Cursor() 556 nk, _ := cur.Seek(byteutil.Uint64ToBytesBigEndian(key)) 557 // delete all keys before this key 558 for k, _ := cur.Prev(); k != nil; k, _ = cur.Prev() { 559 if err := bucket.Delete(k); err != nil { 560 return err 561 } 562 } 563 // write not exist value to next key 564 if nk != nil { 565 return bucket.Put(nk, NotExist) 566 } 567 return nil 568 }); err == nil { 569 break 570 } 571 } 572 573 if err != nil { 574 if errors.Is(err, syscall.ENOSPC) { 575 log.L().Fatal("Failed to purge db.", zap.Error(err)) 576 } 577 err = errors.Wrap(ErrIO, err.Error()) 578 } 579 return err 580 } 581 582 // ====================================== 583 // private functions 584 // ====================================== 585 586 // intentionally fail to test DB can successfully rollback 587 func (b *BoltDB) batchPutForceFail(namespace string, key [][]byte, value [][]byte) error { 588 if !b.IsReady() { 589 return ErrDBNotStarted 590 } 591 592 return b.db.Update(func(tx *bolt.Tx) error { 593 bucket, err := tx.CreateBucketIfNotExists([]byte(namespace)) 594 if err != nil { 595 return err 596 } 597 if len(key) != len(value) { 598 return errors.Wrap(ErrIO, "batch put <k, v> size not match") 599 } 600 for i := 0; i < len(key); i++ { 601 if err := bucket.Put(key[i], value[i]); err != nil { 602 return err 603 } 604 // intentionally fail to test DB can successfully rollback 605 if i == len(key)-1 { 606 return errors.Wrapf(ErrIO, "force fail to test DB rollback") 607 } 608 } 609 return nil 610 }) 611 }