github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/database/ffldb/dbcache.go (about) 1 // Copyright (c) 2015-2016 The btcsuite developers 2 // Copyright (c) 2016 The Dash developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package ffldb 7 8 import ( 9 "bytes" 10 "fmt" 11 "sync" 12 "time" 13 14 "github.com/btcsuite/goleveldb/leveldb" 15 "github.com/btcsuite/goleveldb/leveldb/iterator" 16 "github.com/btcsuite/goleveldb/leveldb/util" 17 "github.com/BlockABC/godash/database/internal/treap" 18 ) 19 20 const ( 21 // defaultCacheSize is the default size for the database cache. 22 defaultCacheSize = 100 * 1024 * 1024 // 100 MB 23 24 // defaultFlushSecs is the default number of seconds to use as a 25 // threshold in between database cache flushes when the cache size has 26 // not been exceeded. 27 defaultFlushSecs = 300 // 5 minutes 28 29 // ldbBatchHeaderSize is the size of a leveldb batch header which 30 // includes the sequence header and record counter. 31 // 32 // ldbRecordIKeySize is the size of the ikey used internally by leveldb 33 // when appending a record to a batch. 34 // 35 // These are used to help preallocate space needed for a batch in one 36 // allocation instead of letting leveldb itself constantly grow it. 37 // This results in far less pressure on the GC and consequently helps 38 // prevent the GC from allocating a lot of extra unneeded space. 39 ldbBatchHeaderSize = 12 40 ldbRecordIKeySize = 8 41 ) 42 43 // ldbCacheIter wraps a treap iterator to provide the additional functionality 44 // needed to satisfy the leveldb iterator.Iterator interface. 45 type ldbCacheIter struct { 46 *treap.Iterator 47 } 48 49 // Enforce ldbCacheIterator implements the leveldb iterator.Iterator interface. 50 var _ iterator.Iterator = (*ldbCacheIter)(nil) 51 52 // Error is only provided to satisfy the iterator interface as there are no 53 // errors for this memory-only structure. 54 // 55 // This is part of the leveldb iterator.Iterator interface implementation. 56 func (iter *ldbCacheIter) Error() error { 57 return nil 58 } 59 60 // SetReleaser is only provided to satisfy the iterator interface as there is no 61 // need to override it. 62 // 63 // This is part of the leveldb iterator.Iterator interface implementation. 64 func (iter *ldbCacheIter) SetReleaser(releaser util.Releaser) { 65 } 66 67 // Release is only provided to satisfy the iterator interface. 68 // 69 // This is part of the leveldb iterator.Iterator interface implementation. 70 func (iter *ldbCacheIter) Release() { 71 } 72 73 // newLdbCacheIter creates a new treap iterator for the given slice against the 74 // pending keys for the passed cache snapshot and returns it wrapped in an 75 // ldbCacheIter so it can be used as a leveldb iterator. 76 func newLdbCacheIter(snap *dbCacheSnapshot, slice *util.Range) *ldbCacheIter { 77 iter := snap.pendingKeys.Iterator(slice.Start, slice.Limit) 78 return &ldbCacheIter{Iterator: iter} 79 } 80 81 // dbCacheIterator defines an iterator over the key/value pairs in the database 82 // cache and underlying database. 83 type dbCacheIterator struct { 84 cacheSnapshot *dbCacheSnapshot 85 dbIter iterator.Iterator 86 cacheIter iterator.Iterator 87 currentIter iterator.Iterator 88 released bool 89 } 90 91 // Enforce dbCacheIterator implements the leveldb iterator.Iterator interface. 92 var _ iterator.Iterator = (*dbCacheIterator)(nil) 93 94 // skipPendingUpdates skips any keys at the current database iterator position 95 // that are being updated by the cache. The forwards flag indicates the 96 // direction the iterator is moving. 97 func (iter *dbCacheIterator) skipPendingUpdates(forwards bool) { 98 for iter.dbIter.Valid() { 99 var skip bool 100 key := iter.dbIter.Key() 101 if iter.cacheSnapshot.pendingRemove.Has(key) { 102 skip = true 103 } else if iter.cacheSnapshot.pendingKeys.Has(key) { 104 skip = true 105 } 106 if !skip { 107 break 108 } 109 110 if forwards { 111 iter.dbIter.Next() 112 } else { 113 iter.dbIter.Prev() 114 } 115 } 116 } 117 118 // chooseIterator first skips any entries in the database iterator that are 119 // being updated by the cache and sets the current iterator to the appropriate 120 // iterator depending on their validity and the order they compare in while taking 121 // into account the direction flag. When the iterator is being moved forwards 122 // and both iterators are valid, the iterator with the smaller key is chosen and 123 // vice versa when the iterator is being moved backwards. 124 func (iter *dbCacheIterator) chooseIterator(forwards bool) bool { 125 // Skip any keys at the current database iterator position that are 126 // being updated by the cache. 127 iter.skipPendingUpdates(forwards) 128 129 // When both iterators are exhausted, the iterator is exhausted too. 130 if !iter.dbIter.Valid() && !iter.cacheIter.Valid() { 131 iter.currentIter = nil 132 return false 133 } 134 135 // Choose the database iterator when the cache iterator is exhausted. 136 if !iter.cacheIter.Valid() { 137 iter.currentIter = iter.dbIter 138 return true 139 } 140 141 // Choose the cache iterator when the database iterator is exhausted. 142 if !iter.dbIter.Valid() { 143 iter.currentIter = iter.cacheIter 144 return true 145 } 146 147 // Both iterators are valid, so choose the iterator with either the 148 // smaller or larger key depending on the forwards flag. 149 compare := bytes.Compare(iter.dbIter.Key(), iter.cacheIter.Key()) 150 if (forwards && compare > 0) || (!forwards && compare < 0) { 151 iter.currentIter = iter.cacheIter 152 } else { 153 iter.currentIter = iter.dbIter 154 } 155 return true 156 } 157 158 // First positions the iterator at the first key/value pair and returns whether 159 // or not the pair exists. 160 // 161 // This is part of the leveldb iterator.Iterator interface implementation. 162 func (iter *dbCacheIterator) First() bool { 163 // Seek to the first key in both the database and cache iterators and 164 // choose the iterator that is both valid and has the smaller key. 165 iter.dbIter.First() 166 iter.cacheIter.First() 167 return iter.chooseIterator(true) 168 } 169 170 // Last positions the iterator at the last key/value pair and returns whether or 171 // not the pair exists. 172 // 173 // This is part of the leveldb iterator.Iterator interface implementation. 174 func (iter *dbCacheIterator) Last() bool { 175 // Seek to the last key in both the database and cache iterators and 176 // choose the iterator that is both valid and has the larger key. 177 iter.dbIter.Last() 178 iter.cacheIter.Last() 179 return iter.chooseIterator(false) 180 } 181 182 // Next moves the iterator one key/value pair forward and returns whether or not 183 // the pair exists. 184 // 185 // This is part of the leveldb iterator.Iterator interface implementation. 186 func (iter *dbCacheIterator) Next() bool { 187 // Nothing to return if cursor is exhausted. 188 if iter.currentIter == nil { 189 return false 190 } 191 192 // Move the current iterator to the next entry and choose the iterator 193 // that is both valid and has the smaller key. 194 iter.currentIter.Next() 195 return iter.chooseIterator(true) 196 } 197 198 // Prev moves the iterator one key/value pair backward and returns whether or 199 // not the pair exists. 200 // 201 // This is part of the leveldb iterator.Iterator interface implementation. 202 func (iter *dbCacheIterator) Prev() bool { 203 // Nothing to return if cursor is exhausted. 204 if iter.currentIter == nil { 205 return false 206 } 207 208 // Move the current iterator to the previous entry and choose the 209 // iterator that is both valid and has the larger key. 210 iter.currentIter.Prev() 211 return iter.chooseIterator(false) 212 } 213 214 // Seek positions the iterator at the first key/value pair that is greater than 215 // or equal to the passed seek key. Returns false if no suitable key was found. 216 // 217 // This is part of the leveldb iterator.Iterator interface implementation. 218 func (iter *dbCacheIterator) Seek(key []byte) bool { 219 // Seek to the provided key in both the database and cache iterators 220 // then choose the iterator that is both valid and has the larger key. 221 iter.dbIter.Seek(key) 222 iter.cacheIter.Seek(key) 223 return iter.chooseIterator(true) 224 } 225 226 // Valid indicates whether the iterator is positioned at a valid key/value pair. 227 // It will be considered invalid when the iterator is newly created or exhausted. 228 // 229 // This is part of the leveldb iterator.Iterator interface implementation. 230 func (iter *dbCacheIterator) Valid() bool { 231 return iter.currentIter != nil 232 } 233 234 // Key returns the current key the iterator is pointing to. 235 // 236 // This is part of the leveldb iterator.Iterator interface implementation. 237 func (iter *dbCacheIterator) Key() []byte { 238 // Nothing to return if iterator is exhausted. 239 if iter.currentIter == nil { 240 return nil 241 } 242 243 return iter.currentIter.Key() 244 } 245 246 // Value returns the current value the iterator is pointing to. 247 // 248 // This is part of the leveldb iterator.Iterator interface implementation. 249 func (iter *dbCacheIterator) Value() []byte { 250 // Nothing to return if iterator is exhausted. 251 if iter.currentIter == nil { 252 return nil 253 } 254 255 return iter.currentIter.Value() 256 } 257 258 // SetReleaser is only provided to satisfy the iterator interface as there is no 259 // need to override it. 260 // 261 // This is part of the leveldb iterator.Iterator interface implementation. 262 func (iter *dbCacheIterator) SetReleaser(releaser util.Releaser) { 263 } 264 265 // Release releases the iterator by removing the underlying treap iterator from 266 // the list of active iterators against the pending keys treap. 267 // 268 // This is part of the leveldb iterator.Iterator interface implementation. 269 func (iter *dbCacheIterator) Release() { 270 if !iter.released { 271 iter.dbIter.Release() 272 iter.cacheIter.Release() 273 iter.currentIter = nil 274 iter.released = true 275 } 276 } 277 278 // Error is only provided to satisfy the iterator interface as there are no 279 // errors for this memory-only structure. 280 // 281 // This is part of the leveldb iterator.Iterator interface implementation. 282 func (iter *dbCacheIterator) Error() error { 283 return nil 284 } 285 286 // dbCacheSnapshot defines a snapshot of the database cache and underlying 287 // database at a particular point in time. 288 type dbCacheSnapshot struct { 289 dbSnapshot *leveldb.Snapshot 290 pendingKeys *treap.Immutable 291 pendingRemove *treap.Immutable 292 } 293 294 // Has returns whether or not the passed key exists. 295 func (snap *dbCacheSnapshot) Has(key []byte) bool { 296 // Check the cached entries first. 297 if snap.pendingRemove.Has(key) { 298 return false 299 } 300 if snap.pendingKeys.Has(key) { 301 return true 302 } 303 304 // Consult the database. 305 hasKey, _ := snap.dbSnapshot.Has(key, nil) 306 return hasKey 307 } 308 309 // Get returns the value for the passed key. The function will return nil when 310 // the key does not exist. 311 func (snap *dbCacheSnapshot) Get(key []byte) []byte { 312 // Check the cached entries first. 313 if snap.pendingRemove.Has(key) { 314 return nil 315 } 316 if value := snap.pendingKeys.Get(key); value != nil { 317 return value 318 } 319 320 // Consult the database. 321 value, err := snap.dbSnapshot.Get(key, nil) 322 if err != nil { 323 return nil 324 } 325 return value 326 } 327 328 // Release releases the snapshot. 329 func (snap *dbCacheSnapshot) Release() { 330 snap.dbSnapshot.Release() 331 snap.pendingKeys = nil 332 snap.pendingRemove = nil 333 } 334 335 // NewIterator returns a new iterator for the snapshot. The newly returned 336 // iterator is not pointing to a valid item until a call to one of the methods 337 // to position it is made. 338 // 339 // The slice parameter allows the iterator to be limited to a range of keys. 340 // The start key is inclusive and the limit key is exclusive. Either or both 341 // can be nil if the functionality is not desired. 342 func (snap *dbCacheSnapshot) NewIterator(slice *util.Range) *dbCacheIterator { 343 return &dbCacheIterator{ 344 dbIter: snap.dbSnapshot.NewIterator(slice, nil), 345 cacheIter: newLdbCacheIter(snap, slice), 346 cacheSnapshot: snap, 347 } 348 } 349 350 // dbCache provides a database cache layer backed by an underlying database. It 351 // allows a maximum cache size and flush interval to be specified such that the 352 // cache is flushed to the database when the cache size exceeds the maximum 353 // configured value or it has been longer than the configured interval since the 354 // last flush. This effectively provides transaction batching so that callers 355 // can commit transactions at will without incurring large performance hits due 356 // to frequent disk syncs. 357 type dbCache struct { 358 // ldb is the underlying leveldb DB for metadata. 359 ldb *leveldb.DB 360 361 // store is used to sync blocks to flat files. 362 store *blockStore 363 364 // The following fields are related to flushing the cache to persistent 365 // storage. Note that all flushing is performed in an opportunistic 366 // fashion. This means that it is only flushed during a transaction or 367 // when the database cache is closed. 368 // 369 // maxSize is the maximum size threshold the cache can grow to before 370 // it is flushed. 371 // 372 // flushInterval is the threshold interval of time that is allowed to 373 // pass before the cache is flushed. 374 // 375 // lastFlush is the time the cache was last flushed. It is used in 376 // conjunction with the current time and the flush interval. 377 // 378 // NOTE: These flush related fields are protected by the database write 379 // lock. 380 maxSize uint64 381 flushInterval time.Duration 382 lastFlush time.Time 383 384 // The following fields hold the keys that need to be stored or deleted 385 // from the underlying database once the cache is full, enough time has 386 // passed, or when the database is shutting down. Note that these are 387 // stored using immutable treaps to support O(1) MVCC snapshots against 388 // the cached data. The cacheLock is used to protect concurrent access 389 // for cache updates and snapshots. 390 cacheLock sync.RWMutex 391 cachedKeys *treap.Immutable 392 cachedRemove *treap.Immutable 393 } 394 395 // Snapshot returns a snapshot of the database cache and underlying database at 396 // a particular point in time. 397 // 398 // The snapshot must be released after use by calling Release. 399 func (c *dbCache) Snapshot() (*dbCacheSnapshot, error) { 400 dbSnapshot, err := c.ldb.GetSnapshot() 401 if err != nil { 402 str := "failed to open transaction" 403 return nil, convertErr(str, err) 404 } 405 406 // Since the cached keys to be added and removed use an immutable treap, 407 // a snapshot is simply obtaining the root of the tree under the lock 408 // which is used to atomically swap the root. 409 c.cacheLock.RLock() 410 cacheSnapshot := &dbCacheSnapshot{ 411 dbSnapshot: dbSnapshot, 412 pendingKeys: c.cachedKeys, 413 pendingRemove: c.cachedRemove, 414 } 415 c.cacheLock.RUnlock() 416 return cacheSnapshot, nil 417 } 418 419 // updateDB invokes the passed function in the context of a managed leveldb 420 // transaction. Any errors returned from the user-supplied function will cause 421 // the transaction to be rolled back and are returned from this function. 422 // Otherwise, the transaction is committed when the user-supplied function 423 // returns a nil error. 424 func (c *dbCache) updateDB(fn func(ldbTx *leveldb.Transaction) error) error { 425 // Start a leveldb transaction. 426 ldbTx, err := c.ldb.OpenTransaction() 427 if err != nil { 428 return convertErr("failed to open ldb transaction", err) 429 } 430 431 if err := fn(ldbTx); err != nil { 432 ldbTx.Discard() 433 return err 434 } 435 436 // Commit the leveldb transaction and convert any errors as needed. 437 if err := ldbTx.Commit(); err != nil { 438 return convertErr("failed to commit leveldb transaction", err) 439 } 440 return nil 441 } 442 443 // TreapForEacher is an interface which allows iteration of a treap in ascending 444 // order using a user-supplied callback for each key/value pair. It mainly 445 // exists so both mutable and immutable treaps can be atomically committed to 446 // the database with the same function. 447 type TreapForEacher interface { 448 ForEach(func(k, v []byte) bool) 449 } 450 451 // commitTreaps atomically commits all of the passed pending add/update/remove 452 // updates to the underlying database. 453 func (c *dbCache) commitTreaps(pendingKeys, pendingRemove TreapForEacher) error { 454 // Perform all leveldb updates using an atomic transaction. 455 return c.updateDB(func(ldbTx *leveldb.Transaction) error { 456 var innerErr error 457 pendingKeys.ForEach(func(k, v []byte) bool { 458 if dbErr := ldbTx.Put(k, v, nil); dbErr != nil { 459 str := fmt.Sprintf("failed to put key %q to "+ 460 "ldb transaction", k) 461 innerErr = convertErr(str, dbErr) 462 return false 463 } 464 return true 465 }) 466 if innerErr != nil { 467 return innerErr 468 } 469 470 pendingRemove.ForEach(func(k, v []byte) bool { 471 if dbErr := ldbTx.Delete(k, nil); dbErr != nil { 472 str := fmt.Sprintf("failed to delete "+ 473 "key %q from ldb transaction", 474 k) 475 innerErr = convertErr(str, dbErr) 476 return false 477 } 478 return true 479 }) 480 return innerErr 481 }) 482 } 483 484 // flush flushes the database cache to persistent storage. This involes syncing 485 // the block store and replaying all transactions that have been applied to the 486 // cache to the underlying database. 487 // 488 // This function MUST be called with the database write lock held. 489 func (c *dbCache) flush() error { 490 c.lastFlush = time.Now() 491 492 // Sync the current write file associated with the block store. This is 493 // necessary before writing the metadata to prevent the case where the 494 // metadata contains information about a block which actually hasn't 495 // been written yet in unexpected shutdown scenarios. 496 if err := c.store.syncBlocks(); err != nil { 497 return err 498 } 499 500 // Since the cached keys to be added and removed use an immutable treap, 501 // a snapshot is simply obtaining the root of the tree under the lock 502 // which is used to atomically swap the root. 503 c.cacheLock.RLock() 504 cachedKeys := c.cachedKeys 505 cachedRemove := c.cachedRemove 506 c.cacheLock.RUnlock() 507 508 // Nothing to do if there is no data to flush. 509 if cachedKeys.Len() == 0 && cachedRemove.Len() == 0 { 510 return nil 511 } 512 513 // Perform all leveldb updates using an atomic transaction. 514 if err := c.commitTreaps(cachedKeys, cachedRemove); err != nil { 515 return err 516 } 517 518 // Clear the cache since it has been flushed. 519 c.cacheLock.Lock() 520 c.cachedKeys = treap.NewImmutable() 521 c.cachedRemove = treap.NewImmutable() 522 c.cacheLock.Unlock() 523 524 return nil 525 } 526 527 // needsFlush returns whether or not the database cache needs to be flushed to 528 // persistent storage based on its current size, whether or not adding all of 529 // the entries in the passed database transaction would cause it to exceed the 530 // configured limit, and how much time has elapsed since the last time the cache 531 // was flushed. 532 // 533 // This function MUST be called with the database write lock held. 534 func (c *dbCache) needsFlush(tx *transaction) bool { 535 // A flush is needed when more time has elapsed than the configured 536 // flush interval. 537 if time.Now().Sub(c.lastFlush) > c.flushInterval { 538 return true 539 } 540 541 // A flush is needed when the size of the database cache exceeds the 542 // specified max cache size. The total calculated size is multiplied by 543 // 1.5 here to account for additional memory consumption that will be 544 // needed during the flush as well as old nodes in the cache that are 545 // referenced by the snapshot used by the transaction. 546 snap := tx.snapshot 547 totalSize := snap.pendingKeys.Size() + snap.pendingRemove.Size() 548 totalSize = uint64(float64(totalSize) * 1.5) 549 if totalSize > c.maxSize { 550 return true 551 } 552 553 return false 554 } 555 556 // commitTx atomically adds all of the pending keys to add and remove into the 557 // database cache. When adding the pending keys would cause the size of the 558 // cache to exceed the max cache size, or the time since the last flush exceeds 559 // the configured flush interval, the cache will be flushed to the underlying 560 // persistent database. 561 // 562 // This is an atomic operation with respect to the cache in that either all of 563 // the pending keys to add and remove in the transaction will be applied or none 564 // of them will. 565 // 566 // The database cache itself might be flushed to the underlying persistent 567 // database even if the transaction fails to apply, but it will only be the 568 // state of the cache without the transaction applied. 569 // 570 // This function MUST be called during a database write transaction which in 571 // turn implies the database write lock will be held. 572 func (c *dbCache) commitTx(tx *transaction) error { 573 // Flush the cache and write the current transaction directly to the 574 // database if a flush is needed. 575 if c.needsFlush(tx) { 576 if err := c.flush(); err != nil { 577 return err 578 } 579 580 // Perform all leveldb updates using an atomic transaction. 581 err := c.commitTreaps(tx.pendingKeys, tx.pendingRemove) 582 if err != nil { 583 return err 584 } 585 586 // Clear the transaction entries since they have been committed. 587 tx.pendingKeys = nil 588 tx.pendingRemove = nil 589 return nil 590 } 591 592 // At this point a database flush is not needed, so atomically commit 593 // the transaction to the cache. 594 595 // Since the cached keys to be added and removed use an immutable treap, 596 // a snapshot is simply obtaining the root of the tree under the lock 597 // which is used to atomically swap the root. 598 c.cacheLock.RLock() 599 newCachedKeys := c.cachedKeys 600 newCachedRemove := c.cachedRemove 601 c.cacheLock.RUnlock() 602 603 // Apply every key to add in the database transaction to the cache. 604 tx.pendingKeys.ForEach(func(k, v []byte) bool { 605 newCachedRemove = newCachedRemove.Delete(k) 606 newCachedKeys = newCachedKeys.Put(k, v) 607 return true 608 }) 609 tx.pendingKeys = nil 610 611 // Apply every key to remove in the database transaction to the cache. 612 tx.pendingRemove.ForEach(func(k, v []byte) bool { 613 newCachedKeys = newCachedKeys.Delete(k) 614 newCachedRemove = newCachedRemove.Put(k, nil) 615 return true 616 }) 617 tx.pendingRemove = nil 618 619 // Atomically replace the immutable treaps which hold the cached keys to 620 // add and delete. 621 c.cacheLock.Lock() 622 c.cachedKeys = newCachedKeys 623 c.cachedRemove = newCachedRemove 624 c.cacheLock.Unlock() 625 return nil 626 } 627 628 // Close cleanly shuts down the database cache by syncing all data and closing 629 // the underlying leveldb database. 630 // 631 // This function MUST be called with the database write lock held. 632 func (c *dbCache) Close() error { 633 // Flush any outstanding cached entries to disk. 634 if err := c.flush(); err != nil { 635 // Even if there is an error while flushing, attempt to close 636 // the underlying database. The error is ignored since it would 637 // mask the flush error. 638 _ = c.ldb.Close() 639 return err 640 } 641 642 // Close the underlying leveldb database. 643 if err := c.ldb.Close(); err != nil { 644 str := "failed to close underlying leveldb database" 645 return convertErr(str, err) 646 } 647 648 return nil 649 } 650 651 // newDbCache returns a new database cache instance backed by the provided 652 // leveldb instance. The cache will be flushed to leveldb when the max size 653 // exceeds the provided value or it has been longer than the provided interval 654 // since the last flush. 655 func newDbCache(ldb *leveldb.DB, store *blockStore, maxSize uint64, flushIntervalSecs uint32) *dbCache { 656 return &dbCache{ 657 ldb: ldb, 658 store: store, 659 maxSize: maxSize, 660 flushInterval: time.Second * time.Duration(flushIntervalSecs), 661 lastFlush: time.Now(), 662 cachedKeys: treap.NewImmutable(), 663 cachedRemove: treap.NewImmutable(), 664 } 665 }