github.com/lbryio/lbcd@v0.22.119/database/ffldb/dbcache.go (about)

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