OSDN Git Service

Thanos did someting
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / database / ffldb / blockio.go
diff --git a/vendor/github.com/btcsuite/btcd/database/ffldb/blockio.go b/vendor/github.com/btcsuite/btcd/database/ffldb/blockio.go
deleted file mode 100644 (file)
index 3d7782f..0000000
+++ /dev/null
@@ -1,769 +0,0 @@
-// Copyright (c) 2015-2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-// This file contains the implementation functions for reading, writing, and
-// otherwise working with the flat files that house the actual blocks.
-
-package ffldb
-
-import (
-       "container/list"
-       "encoding/binary"
-       "fmt"
-       "hash/crc32"
-       "io"
-       "os"
-       "path/filepath"
-       "sync"
-
-       "github.com/btcsuite/btcd/chaincfg/chainhash"
-       "github.com/btcsuite/btcd/database"
-       "github.com/btcsuite/btcd/wire"
-)
-
-const (
-       // The Bitcoin protocol encodes block height as int32, so max number of
-       // blocks is 2^31.  Max block size per the protocol is 32MiB per block.
-       // So the theoretical max at the time this comment was written is 64PiB
-       // (pebibytes).  With files @ 512MiB each, this would require a maximum
-       // of 134,217,728 files.  Thus, choose 9 digits of precision for the
-       // filenames.  An additional benefit is 9 digits provides 10^9 files @
-       // 512MiB each for a total of ~476.84PiB (roughly 7.4 times the current
-       // theoretical max), so there is room for the max block size to grow in
-       // the future.
-       blockFilenameTemplate = "%09d.fdb"
-
-       // maxOpenFiles is the max number of open files to maintain in the
-       // open blocks cache.  Note that this does not include the current
-       // write file, so there will typically be one more than this value open.
-       maxOpenFiles = 25
-
-       // maxBlockFileSize is the maximum size for each file used to store
-       // blocks.
-       //
-       // NOTE: The current code uses uint32 for all offsets, so this value
-       // must be less than 2^32 (4 GiB).  This is also why it's a typed
-       // constant.
-       maxBlockFileSize uint32 = 512 * 1024 * 1024 // 512 MiB
-
-       // blockLocSize is the number of bytes the serialized block location
-       // data that is stored in the block index.
-       //
-       // The serialized block location format is:
-       //
-       //  [0:4]  Block file (4 bytes)
-       //  [4:8]  File offset (4 bytes)
-       //  [8:12] Block length (4 bytes)
-       blockLocSize = 12
-)
-
-var (
-       // castagnoli houses the Catagnoli polynomial used for CRC-32 checksums.
-       castagnoli = crc32.MakeTable(crc32.Castagnoli)
-)
-
-// filer is an interface which acts very similar to a *os.File and is typically
-// implemented by it.  It exists so the test code can provide mock files for
-// properly testing corruption and file system issues.
-type filer interface {
-       io.Closer
-       io.WriterAt
-       io.ReaderAt
-       Truncate(size int64) error
-       Sync() error
-}
-
-// lockableFile represents a block file on disk that has been opened for either
-// read or read/write access.  It also contains a read-write mutex to support
-// multiple concurrent readers.
-type lockableFile struct {
-       sync.RWMutex
-       file filer
-}
-
-// writeCursor represents the current file and offset of the block file on disk
-// for performing all writes. It also contains a read-write mutex to support
-// multiple concurrent readers which can reuse the file handle.
-type writeCursor struct {
-       sync.RWMutex
-
-       // curFile is the current block file that will be appended to when
-       // writing new blocks.
-       curFile *lockableFile
-
-       // curFileNum is the current block file number and is used to allow
-       // readers to use the same open file handle.
-       curFileNum uint32
-
-       // curOffset is the offset in the current write block file where the
-       // next new block will be written.
-       curOffset uint32
-}
-
-// blockStore houses information used to handle reading and writing blocks (and
-// part of blocks) into flat files with support for multiple concurrent readers.
-type blockStore struct {
-       // network is the specific network to use in the flat files for each
-       // block.
-       network wire.BitcoinNet
-
-       // basePath is the base path used for the flat block files and metadata.
-       basePath string
-
-       // maxBlockFileSize is the maximum size for each file used to store
-       // blocks.  It is defined on the store so the whitebox tests can
-       // override the value.
-       maxBlockFileSize uint32
-
-       // The following fields are related to the flat files which hold the
-       // actual blocks.   The number of open files is limited by maxOpenFiles.
-       //
-       // obfMutex protects concurrent access to the openBlockFiles map.  It is
-       // a RWMutex so multiple readers can simultaneously access open files.
-       //
-       // openBlockFiles houses the open file handles for existing block files
-       // which have been opened read-only along with an individual RWMutex.
-       // This scheme allows multiple concurrent readers to the same file while
-       // preventing the file from being closed out from under them.
-       //
-       // lruMutex protects concurrent access to the least recently used list
-       // and lookup map.
-       //
-       // openBlocksLRU tracks how the open files are refenced by pushing the
-       // most recently used files to the front of the list thereby trickling
-       // the least recently used files to end of the list.  When a file needs
-       // to be closed due to exceeding the the max number of allowed open
-       // files, the one at the end of the list is closed.
-       //
-       // fileNumToLRUElem is a mapping between a specific block file number
-       // and the associated list element on the least recently used list.
-       //
-       // Thus, with the combination of these fields, the database supports
-       // concurrent non-blocking reads across multiple and individual files
-       // along with intelligently limiting the number of open file handles by
-       // closing the least recently used files as needed.
-       //
-       // NOTE: The locking order used throughout is well-defined and MUST be
-       // followed.  Failure to do so could lead to deadlocks.  In particular,
-       // the locking order is as follows:
-       //   1) obfMutex
-       //   2) lruMutex
-       //   3) writeCursor mutex
-       //   4) specific file mutexes
-       //
-       // None of the mutexes are required to be locked at the same time, and
-       // often aren't.  However, if they are to be locked simultaneously, they
-       // MUST be locked in the order previously specified.
-       //
-       // Due to the high performance and multi-read concurrency requirements,
-       // write locks should only be held for the minimum time necessary.
-       obfMutex         sync.RWMutex
-       lruMutex         sync.Mutex
-       openBlocksLRU    *list.List // Contains uint32 block file numbers.
-       fileNumToLRUElem map[uint32]*list.Element
-       openBlockFiles   map[uint32]*lockableFile
-
-       // writeCursor houses the state for the current file and location that
-       // new blocks are written to.
-       writeCursor *writeCursor
-
-       // These functions are set to openFile, openWriteFile, and deleteFile by
-       // default, but are exposed here to allow the whitebox tests to replace
-       // them when working with mock files.
-       openFileFunc      func(fileNum uint32) (*lockableFile, error)
-       openWriteFileFunc func(fileNum uint32) (filer, error)
-       deleteFileFunc    func(fileNum uint32) error
-}
-
-// blockLocation identifies a particular block file and location.
-type blockLocation struct {
-       blockFileNum uint32
-       fileOffset   uint32
-       blockLen     uint32
-}
-
-// deserializeBlockLoc deserializes the passed serialized block location
-// information.  This is data stored into the block index metadata for each
-// block.  The serialized data passed to this function MUST be at least
-// blockLocSize bytes or it will panic.  The error check is avoided here because
-// this information will always be coming from the block index which includes a
-// checksum to detect corruption.  Thus it is safe to use this unchecked here.
-func deserializeBlockLoc(serializedLoc []byte) blockLocation {
-       // The serialized block location format is:
-       //
-       //  [0:4]  Block file (4 bytes)
-       //  [4:8]  File offset (4 bytes)
-       //  [8:12] Block length (4 bytes)
-       return blockLocation{
-               blockFileNum: byteOrder.Uint32(serializedLoc[0:4]),
-               fileOffset:   byteOrder.Uint32(serializedLoc[4:8]),
-               blockLen:     byteOrder.Uint32(serializedLoc[8:12]),
-       }
-}
-
-// serializeBlockLoc returns the serialization of the passed block location.
-// This is data to be stored into the block index metadata for each block.
-func serializeBlockLoc(loc blockLocation) []byte {
-       // The serialized block location format is:
-       //
-       //  [0:4]  Block file (4 bytes)
-       //  [4:8]  File offset (4 bytes)
-       //  [8:12] Block length (4 bytes)
-       var serializedData [12]byte
-       byteOrder.PutUint32(serializedData[0:4], loc.blockFileNum)
-       byteOrder.PutUint32(serializedData[4:8], loc.fileOffset)
-       byteOrder.PutUint32(serializedData[8:12], loc.blockLen)
-       return serializedData[:]
-}
-
-// blockFilePath return the file path for the provided block file number.
-func blockFilePath(dbPath string, fileNum uint32) string {
-       fileName := fmt.Sprintf(blockFilenameTemplate, fileNum)
-       return filepath.Join(dbPath, fileName)
-}
-
-// openWriteFile returns a file handle for the passed flat file number in
-// read/write mode.  The file will be created if needed.  It is typically used
-// for the current file that will have all new data appended.  Unlike openFile,
-// this function does not keep track of the open file and it is not subject to
-// the maxOpenFiles limit.
-func (s *blockStore) openWriteFile(fileNum uint32) (filer, error) {
-       // The current block file needs to be read-write so it is possible to
-       // append to it.  Also, it shouldn't be part of the least recently used
-       // file.
-       filePath := blockFilePath(s.basePath, fileNum)
-       file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0666)
-       if err != nil {
-               str := fmt.Sprintf("failed to open file %q: %v", filePath, err)
-               return nil, makeDbErr(database.ErrDriverSpecific, str, err)
-       }
-
-       return file, nil
-}
-
-// openFile returns a read-only file handle for the passed flat file number.
-// The function also keeps track of the open files, performs least recently
-// used tracking, and limits the number of open files to maxOpenFiles by closing
-// the least recently used file as needed.
-//
-// This function MUST be called with the overall files mutex (s.obfMutex) locked
-// for WRITES.
-func (s *blockStore) openFile(fileNum uint32) (*lockableFile, error) {
-       // Open the appropriate file as read-only.
-       filePath := blockFilePath(s.basePath, fileNum)
-       file, err := os.Open(filePath)
-       if err != nil {
-               return nil, makeDbErr(database.ErrDriverSpecific, err.Error(),
-                       err)
-       }
-       blockFile := &lockableFile{file: file}
-
-       // Close the least recently used file if the file exceeds the max
-       // allowed open files.  This is not done until after the file open in
-       // case the file fails to open, there is no need to close any files.
-       //
-       // A write lock is required on the LRU list here to protect against
-       // modifications happening as already open files are read from and
-       // shuffled to the front of the list.
-       //
-       // Also, add the file that was just opened to the front of the least
-       // recently used list to indicate it is the most recently used file and
-       // therefore should be closed last.
-       s.lruMutex.Lock()
-       lruList := s.openBlocksLRU
-       if lruList.Len() >= maxOpenFiles {
-               lruFileNum := lruList.Remove(lruList.Back()).(uint32)
-               oldBlockFile := s.openBlockFiles[lruFileNum]
-
-               // Close the old file under the write lock for the file in case
-               // any readers are currently reading from it so it's not closed
-               // out from under them.
-               oldBlockFile.Lock()
-               _ = oldBlockFile.file.Close()
-               oldBlockFile.Unlock()
-
-               delete(s.openBlockFiles, lruFileNum)
-               delete(s.fileNumToLRUElem, lruFileNum)
-       }
-       s.fileNumToLRUElem[fileNum] = lruList.PushFront(fileNum)
-       s.lruMutex.Unlock()
-
-       // Store a reference to it in the open block files map.
-       s.openBlockFiles[fileNum] = blockFile
-
-       return blockFile, nil
-}
-
-// deleteFile removes the block file for the passed flat file number.  The file
-// must already be closed and it is the responsibility of the caller to do any
-// other state cleanup necessary.
-func (s *blockStore) deleteFile(fileNum uint32) error {
-       filePath := blockFilePath(s.basePath, fileNum)
-       if err := os.Remove(filePath); err != nil {
-               return makeDbErr(database.ErrDriverSpecific, err.Error(), err)
-       }
-
-       return nil
-}
-
-// blockFile attempts to return an existing file handle for the passed flat file
-// number if it is already open as well as marking it as most recently used.  It
-// will also open the file when it's not already open subject to the rules
-// described in openFile.
-//
-// NOTE: The returned block file will already have the read lock acquired and
-// the caller MUST call .RUnlock() to release it once it has finished all read
-// operations.  This is necessary because otherwise it would be possible for a
-// separate goroutine to close the file after it is returned from here, but
-// before the caller has acquired a read lock.
-func (s *blockStore) blockFile(fileNum uint32) (*lockableFile, error) {
-       // When the requested block file is open for writes, return it.
-       wc := s.writeCursor
-       wc.RLock()
-       if fileNum == wc.curFileNum && wc.curFile.file != nil {
-               obf := wc.curFile
-               obf.RLock()
-               wc.RUnlock()
-               return obf, nil
-       }
-       wc.RUnlock()
-
-       // Try to return an open file under the overall files read lock.
-       s.obfMutex.RLock()
-       if obf, ok := s.openBlockFiles[fileNum]; ok {
-               s.lruMutex.Lock()
-               s.openBlocksLRU.MoveToFront(s.fileNumToLRUElem[fileNum])
-               s.lruMutex.Unlock()
-
-               obf.RLock()
-               s.obfMutex.RUnlock()
-               return obf, nil
-       }
-       s.obfMutex.RUnlock()
-
-       // Since the file isn't open already, need to check the open block files
-       // map again under write lock in case multiple readers got here and a
-       // separate one is already opening the file.
-       s.obfMutex.Lock()
-       if obf, ok := s.openBlockFiles[fileNum]; ok {
-               obf.RLock()
-               s.obfMutex.Unlock()
-               return obf, nil
-       }
-
-       // The file isn't open, so open it while potentially closing the least
-       // recently used one as needed.
-       obf, err := s.openFileFunc(fileNum)
-       if err != nil {
-               s.obfMutex.Unlock()
-               return nil, err
-       }
-       obf.RLock()
-       s.obfMutex.Unlock()
-       return obf, nil
-}
-
-// writeData is a helper function for writeBlock which writes the provided data
-// at the current write offset and updates the write cursor accordingly.  The
-// field name parameter is only used when there is an error to provide a nicer
-// error message.
-//
-// The write cursor will be advanced the number of bytes actually written in the
-// event of failure.
-//
-// NOTE: This function MUST be called with the write cursor current file lock
-// held and must only be called during a write transaction so it is effectively
-// locked for writes.  Also, the write cursor current file must NOT be nil.
-func (s *blockStore) writeData(data []byte, fieldName string) error {
-       wc := s.writeCursor
-       n, err := wc.curFile.file.WriteAt(data, int64(wc.curOffset))
-       wc.curOffset += uint32(n)
-       if err != nil {
-               str := fmt.Sprintf("failed to write %s to file %d at "+
-                       "offset %d: %v", fieldName, wc.curFileNum,
-                       wc.curOffset-uint32(n), err)
-               return makeDbErr(database.ErrDriverSpecific, str, err)
-       }
-
-       return nil
-}
-
-// writeBlock appends the specified raw block bytes to the store's write cursor
-// location and increments it accordingly.  When the block would exceed the max
-// file size for the current flat file, this function will close the current
-// file, create the next file, update the write cursor, and write the block to
-// the new file.
-//
-// The write cursor will also be advanced the number of bytes actually written
-// in the event of failure.
-//
-// Format: <network><block length><serialized block><checksum>
-func (s *blockStore) writeBlock(rawBlock []byte) (blockLocation, error) {
-       // Compute how many bytes will be written.
-       // 4 bytes each for block network + 4 bytes for block length +
-       // length of raw block + 4 bytes for checksum.
-       blockLen := uint32(len(rawBlock))
-       fullLen := blockLen + 12
-
-       // Move to the next block file if adding the new block would exceed the
-       // max allowed size for the current block file.  Also detect overflow
-       // to be paranoid, even though it isn't possible currently, numbers
-       // might change in the future to make it possible.
-       //
-       // NOTE: The writeCursor.offset field isn't protected by the mutex
-       // since it's only read/changed during this function which can only be
-       // called during a write transaction, of which there can be only one at
-       // a time.
-       wc := s.writeCursor
-       finalOffset := wc.curOffset + fullLen
-       if finalOffset < wc.curOffset || finalOffset > s.maxBlockFileSize {
-               // This is done under the write cursor lock since the curFileNum
-               // field is accessed elsewhere by readers.
-               //
-               // Close the current write file to force a read-only reopen
-               // with LRU tracking.  The close is done under the write lock
-               // for the file to prevent it from being closed out from under
-               // any readers currently reading from it.
-               wc.Lock()
-               wc.curFile.Lock()
-               if wc.curFile.file != nil {
-                       _ = wc.curFile.file.Close()
-                       wc.curFile.file = nil
-               }
-               wc.curFile.Unlock()
-
-               // Start writes into next file.
-               wc.curFileNum++
-               wc.curOffset = 0
-               wc.Unlock()
-       }
-
-       // All writes are done under the write lock for the file to ensure any
-       // readers are finished and blocked first.
-       wc.curFile.Lock()
-       defer wc.curFile.Unlock()
-
-       // Open the current file if needed.  This will typically only be the
-       // case when moving to the next file to write to or on initial database
-       // load.  However, it might also be the case if rollbacks happened after
-       // file writes started during a transaction commit.
-       if wc.curFile.file == nil {
-               file, err := s.openWriteFileFunc(wc.curFileNum)
-               if err != nil {
-                       return blockLocation{}, err
-               }
-               wc.curFile.file = file
-       }
-
-       // Bitcoin network.
-       origOffset := wc.curOffset
-       hasher := crc32.New(castagnoli)
-       var scratch [4]byte
-       byteOrder.PutUint32(scratch[:], uint32(s.network))
-       if err := s.writeData(scratch[:], "network"); err != nil {
-               return blockLocation{}, err
-       }
-       _, _ = hasher.Write(scratch[:])
-
-       // Block length.
-       byteOrder.PutUint32(scratch[:], blockLen)
-       if err := s.writeData(scratch[:], "block length"); err != nil {
-               return blockLocation{}, err
-       }
-       _, _ = hasher.Write(scratch[:])
-
-       // Serialized block.
-       if err := s.writeData(rawBlock[:], "block"); err != nil {
-               return blockLocation{}, err
-       }
-       _, _ = hasher.Write(rawBlock)
-
-       // Castagnoli CRC-32 as a checksum of all the previous.
-       if err := s.writeData(hasher.Sum(nil), "checksum"); err != nil {
-               return blockLocation{}, err
-       }
-
-       loc := blockLocation{
-               blockFileNum: wc.curFileNum,
-               fileOffset:   origOffset,
-               blockLen:     fullLen,
-       }
-       return loc, nil
-}
-
-// readBlock reads the specified block record and returns the serialized block.
-// It ensures the integrity of the block data by checking that the serialized
-// network matches the current network associated with the block store and
-// comparing the calculated checksum against the one stored in the flat file.
-// This function also automatically handles all file management such as opening
-// and closing files as necessary to stay within the maximum allowed open files
-// limit.
-//
-// Returns ErrDriverSpecific if the data fails to read for any reason and
-// ErrCorruption if the checksum of the read data doesn't match the checksum
-// read from the file.
-//
-// Format: <network><block length><serialized block><checksum>
-func (s *blockStore) readBlock(hash *chainhash.Hash, loc blockLocation) ([]byte, error) {
-       // Get the referenced block file handle opening the file as needed.  The
-       // function also handles closing files as needed to avoid going over the
-       // max allowed open files.
-       blockFile, err := s.blockFile(loc.blockFileNum)
-       if err != nil {
-               return nil, err
-       }
-
-       serializedData := make([]byte, loc.blockLen)
-       n, err := blockFile.file.ReadAt(serializedData, int64(loc.fileOffset))
-       blockFile.RUnlock()
-       if err != nil {
-               str := fmt.Sprintf("failed to read block %s from file %d, "+
-                       "offset %d: %v", hash, loc.blockFileNum, loc.fileOffset,
-                       err)
-               return nil, makeDbErr(database.ErrDriverSpecific, str, err)
-       }
-
-       // Calculate the checksum of the read data and ensure it matches the
-       // serialized checksum.  This will detect any data corruption in the
-       // flat file without having to do much more expensive merkle root
-       // calculations on the loaded block.
-       serializedChecksum := binary.BigEndian.Uint32(serializedData[n-4:])
-       calculatedChecksum := crc32.Checksum(serializedData[:n-4], castagnoli)
-       if serializedChecksum != calculatedChecksum {
-               str := fmt.Sprintf("block data for block %s checksum "+
-                       "does not match - got %x, want %x", hash,
-                       calculatedChecksum, serializedChecksum)
-               return nil, makeDbErr(database.ErrCorruption, str, nil)
-       }
-
-       // The network associated with the block must match the current active
-       // network, otherwise somebody probably put the block files for the
-       // wrong network in the directory.
-       serializedNet := byteOrder.Uint32(serializedData[:4])
-       if serializedNet != uint32(s.network) {
-               str := fmt.Sprintf("block data for block %s is for the "+
-                       "wrong network - got %d, want %d", hash, serializedNet,
-                       uint32(s.network))
-               return nil, makeDbErr(database.ErrDriverSpecific, str, nil)
-       }
-
-       // The raw block excludes the network, length of the block, and
-       // checksum.
-       return serializedData[8 : n-4], nil
-}
-
-// readBlockRegion reads the specified amount of data at the provided offset for
-// a given block location.  The offset is relative to the start of the
-// serialized block (as opposed to the beginning of the block record).  This
-// function automatically handles all file management such as opening and
-// closing files as necessary to stay within the maximum allowed open files
-// limit.
-//
-// Returns ErrDriverSpecific if the data fails to read for any reason.
-func (s *blockStore) readBlockRegion(loc blockLocation, offset, numBytes uint32) ([]byte, error) {
-       // Get the referenced block file handle opening the file as needed.  The
-       // function also handles closing files as needed to avoid going over the
-       // max allowed open files.
-       blockFile, err := s.blockFile(loc.blockFileNum)
-       if err != nil {
-               return nil, err
-       }
-
-       // Regions are offsets into the actual block, however the serialized
-       // data for a block includes an initial 4 bytes for network + 4 bytes
-       // for block length.  Thus, add 8 bytes to adjust.
-       readOffset := loc.fileOffset + 8 + offset
-       serializedData := make([]byte, numBytes)
-       _, err = blockFile.file.ReadAt(serializedData, int64(readOffset))
-       blockFile.RUnlock()
-       if err != nil {
-               str := fmt.Sprintf("failed to read region from block file %d, "+
-                       "offset %d, len %d: %v", loc.blockFileNum, readOffset,
-                       numBytes, err)
-               return nil, makeDbErr(database.ErrDriverSpecific, str, err)
-       }
-
-       return serializedData, nil
-}
-
-// syncBlocks performs a file system sync on the flat file associated with the
-// store's current write cursor.  It is safe to call even when there is not a
-// current write file in which case it will have no effect.
-//
-// This is used when flushing cached metadata updates to disk to ensure all the
-// block data is fully written before updating the metadata.  This ensures the
-// metadata and block data can be properly reconciled in failure scenarios.
-func (s *blockStore) syncBlocks() error {
-       wc := s.writeCursor
-       wc.RLock()
-       defer wc.RUnlock()
-
-       // Nothing to do if there is no current file associated with the write
-       // cursor.
-       wc.curFile.RLock()
-       defer wc.curFile.RUnlock()
-       if wc.curFile.file == nil {
-               return nil
-       }
-
-       // Sync the file to disk.
-       if err := wc.curFile.file.Sync(); err != nil {
-               str := fmt.Sprintf("failed to sync file %d: %v", wc.curFileNum,
-                       err)
-               return makeDbErr(database.ErrDriverSpecific, str, err)
-       }
-
-       return nil
-}
-
-// handleRollback rolls the block files on disk back to the provided file number
-// and offset.  This involves potentially deleting and truncating the files that
-// were partially written.
-//
-// There are effectively two scenarios to consider here:
-//   1) Transient write failures from which recovery is possible
-//   2) More permanent failures such as hard disk death and/or removal
-//
-// In either case, the write cursor will be repositioned to the old block file
-// offset regardless of any other errors that occur while attempting to undo
-// writes.
-//
-// For the first scenario, this will lead to any data which failed to be undone
-// being overwritten and thus behaves as desired as the system continues to run.
-//
-// For the second scenario, the metadata which stores the current write cursor
-// position within the block files will not have been updated yet and thus if
-// the system eventually recovers (perhaps the hard drive is reconnected), it
-// will also lead to any data which failed to be undone being overwritten and
-// thus behaves as desired.
-//
-// Therefore, any errors are simply logged at a warning level rather than being
-// returned since there is nothing more that could be done about it anyways.
-func (s *blockStore) handleRollback(oldBlockFileNum, oldBlockOffset uint32) {
-       // Grab the write cursor mutex since it is modified throughout this
-       // function.
-       wc := s.writeCursor
-       wc.Lock()
-       defer wc.Unlock()
-
-       // Nothing to do if the rollback point is the same as the current write
-       // cursor.
-       if wc.curFileNum == oldBlockFileNum && wc.curOffset == oldBlockOffset {
-               return
-       }
-
-       // Regardless of any failures that happen below, reposition the write
-       // cursor to the old block file and offset.
-       defer func() {
-               wc.curFileNum = oldBlockFileNum
-               wc.curOffset = oldBlockOffset
-       }()
-
-       log.Debugf("ROLLBACK: Rolling back to file %d, offset %d",
-               oldBlockFileNum, oldBlockOffset)
-
-       // Close the current write file if it needs to be deleted.  Then delete
-       // all files that are newer than the provided rollback file while
-       // also moving the write cursor file backwards accordingly.
-       if wc.curFileNum > oldBlockFileNum {
-               wc.curFile.Lock()
-               if wc.curFile.file != nil {
-                       _ = wc.curFile.file.Close()
-                       wc.curFile.file = nil
-               }
-               wc.curFile.Unlock()
-       }
-       for ; wc.curFileNum > oldBlockFileNum; wc.curFileNum-- {
-               if err := s.deleteFileFunc(wc.curFileNum); err != nil {
-                       log.Warnf("ROLLBACK: Failed to delete block file "+
-                               "number %d: %v", wc.curFileNum, err)
-                       return
-               }
-       }
-
-       // Open the file for the current write cursor if needed.
-       wc.curFile.Lock()
-       if wc.curFile.file == nil {
-               obf, err := s.openWriteFileFunc(wc.curFileNum)
-               if err != nil {
-                       wc.curFile.Unlock()
-                       log.Warnf("ROLLBACK: %v", err)
-                       return
-               }
-               wc.curFile.file = obf
-       }
-
-       // Truncate the to the provided rollback offset.
-       if err := wc.curFile.file.Truncate(int64(oldBlockOffset)); err != nil {
-               wc.curFile.Unlock()
-               log.Warnf("ROLLBACK: Failed to truncate file %d: %v",
-                       wc.curFileNum, err)
-               return
-       }
-
-       // Sync the file to disk.
-       err := wc.curFile.file.Sync()
-       wc.curFile.Unlock()
-       if err != nil {
-               log.Warnf("ROLLBACK: Failed to sync file %d: %v",
-                       wc.curFileNum, err)
-               return
-       }
-}
-
-// scanBlockFiles searches the database directory for all flat block files to
-// find the end of the most recent file.  This position is considered the
-// current write cursor which is also stored in the metadata.  Thus, it is used
-// to detect unexpected shutdowns in the middle of writes so the block files
-// can be reconciled.
-func scanBlockFiles(dbPath string) (int, uint32) {
-       lastFile := -1
-       fileLen := uint32(0)
-       for i := 0; ; i++ {
-               filePath := blockFilePath(dbPath, uint32(i))
-               st, err := os.Stat(filePath)
-               if err != nil {
-                       break
-               }
-               lastFile = i
-
-               fileLen = uint32(st.Size())
-       }
-
-       log.Tracef("Scan found latest block file #%d with length %d", lastFile,
-               fileLen)
-       return lastFile, fileLen
-}
-
-// newBlockStore returns a new block store with the current block file number
-// and offset set and all fields initialized.
-func newBlockStore(basePath string, network wire.BitcoinNet) *blockStore {
-       // Look for the end of the latest block to file to determine what the
-       // write cursor position is from the viewpoing of the block files on
-       // disk.
-       fileNum, fileOff := scanBlockFiles(basePath)
-       if fileNum == -1 {
-               fileNum = 0
-               fileOff = 0
-       }
-
-       store := &blockStore{
-               network:          network,
-               basePath:         basePath,
-               maxBlockFileSize: maxBlockFileSize,
-               openBlockFiles:   make(map[uint32]*lockableFile),
-               openBlocksLRU:    list.New(),
-               fileNumToLRUElem: make(map[uint32]*list.Element),
-
-               writeCursor: &writeCursor{
-                       curFile:    &lockableFile{},
-                       curFileNum: uint32(fileNum),
-                       curOffset:  fileOff,
-               },
-       }
-       store.openFileFunc = store.openFile
-       store.openWriteFileFunc = store.openWriteFile
-       store.deleteFileFunc = store.deleteFile
-       return store
-}