github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/database/interface.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  // Parts of this interface were inspired heavily by the excellent boltdb project
     7  // at https://github.com/boltdb/bolt by Ben B. Johnson.
     8  
     9  package database
    10  
    11  import (
    12  	"github.com/BlockABC/godash/wire"
    13  	"github.com/BlockABC/godashutil"
    14  )
    15  
    16  // Cursor represents a cursor over key/value pairs and nested buckets of a
    17  // bucket.
    18  //
    19  // Note that open cursors are not tracked on bucket changes and any
    20  // modifications to the bucket, with the exception of Cursor.Delete, invalidates
    21  // the cursor.  After invalidation, the cursor must be repositioned, or the keys
    22  // and values returned may be unpredictable.
    23  type Cursor interface {
    24  	// Bucket returns the bucket the cursor was created for.
    25  	Bucket() Bucket
    26  
    27  	// Delete removes the current key/value pair the cursor is at without
    28  	// invalidating the cursor.
    29  	//
    30  	// The interface contract guarantees at least the following errors will
    31  	// be returned (other implementation-specific errors are possible):
    32  	//   - ErrIncompatibleValue if attempted when the cursor points to a
    33  	//     nested bucket
    34  	//   - ErrTxNotWritable if attempted against a read-only transaction
    35  	//   - ErrTxClosed if the transaction has already been closed
    36  	Delete() error
    37  
    38  	// First positions the cursor at the first key/value pair and returns
    39  	// whether or not the pair exists.
    40  	First() bool
    41  
    42  	// Last positions the cursor at the last key/value pair and returns
    43  	// whether or not the pair exists.
    44  	Last() bool
    45  
    46  	// Next moves the cursor one key/value pair forward and returns whether
    47  	// or not the pair exists.
    48  	Next() bool
    49  
    50  	// Prev moves the cursor one key/value pair backward and returns whether
    51  	// or not the pair exists.
    52  	Prev() bool
    53  
    54  	// Seek positions the cursor at the first key/value pair that is greater
    55  	// than or equal to the passed seek key.  Returns whether or not the
    56  	// pair exists.
    57  	Seek(seek []byte) bool
    58  
    59  	// Key returns the current key the cursor is pointing to.
    60  	Key() []byte
    61  
    62  	// Value returns the current value the cursor is pointing to.  This will
    63  	// be nil for nested buckets.
    64  	Value() []byte
    65  }
    66  
    67  // Bucket represents a collection of key/value pairs.
    68  type Bucket interface {
    69  	// Bucket retrieves a nested bucket with the given key.  Returns nil if
    70  	// the bucket does not exist.
    71  	Bucket(key []byte) Bucket
    72  
    73  	// CreateBucket creates and returns a new nested bucket with the given
    74  	// key.
    75  	//
    76  	// The interface contract guarantees at least the following errors will
    77  	// be returned (other implementation-specific errors are possible):
    78  	//   - ErrBucketExists if the bucket already exists
    79  	//   - ErrBucketNameRequired if the key is empty
    80  	//   - ErrIncompatibleValue if the key is otherwise invalid for the
    81  	//     particular implementation
    82  	//   - ErrTxNotWritable if attempted against a read-only transaction
    83  	//   - ErrTxClosed if the transaction has already been closed
    84  	CreateBucket(key []byte) (Bucket, error)
    85  
    86  	// CreateBucketIfNotExists creates and returns a new nested bucket with
    87  	// the given key if it does not already exist.
    88  	//
    89  	// The interface contract guarantees at least the following errors will
    90  	// be returned (other implementation-specific errors are possible):
    91  	//   - ErrBucketNameRequired if the key is empty
    92  	//   - ErrIncompatibleValue if the key is otherwise invalid for the
    93  	//     particular implementation
    94  	//   - ErrTxNotWritable if attempted against a read-only transaction
    95  	//   - ErrTxClosed if the transaction has already been closed
    96  	CreateBucketIfNotExists(key []byte) (Bucket, error)
    97  
    98  	// DeleteBucket removes a nested bucket with the given key.  This also
    99  	// includes removing all nested buckets and keys under the bucket being
   100  	// deleted.
   101  	//
   102  	// The interface contract guarantees at least the following errors will
   103  	// be returned (other implementation-specific errors are possible):
   104  	//   - ErrBucketNotFound if the specified bucket does not exist
   105  	//   - ErrTxNotWritable if attempted against a read-only transaction
   106  	//   - ErrTxClosed if the transaction has already been closed
   107  	DeleteBucket(key []byte) error
   108  
   109  	// ForEach invokes the passed function with every key/value pair in the
   110  	// bucket.  This does not include nested buckets or the key/value pairs
   111  	// within those nested buckets.
   112  	//
   113  	// WARNING: It is not safe to mutate data while iterating with this
   114  	// method.  Doing so may cause the underlying cursor to be invalidated
   115  	// and return unexpected keys and/or values.
   116  	//
   117  	// The interface contract guarantees at least the following errors will
   118  	// be returned (other implementation-specific errors are possible):
   119  	//   - ErrTxClosed if the transaction has already been closed
   120  	//
   121  	// NOTE: The slices returned by this function are only valid during a
   122  	// transaction.  Attempting to access them after a transaction has ended
   123  	// results in undefined behavior.  Additionally, the slices must NOT
   124  	// be modified by the caller.  These constraints prevent additional data
   125  	// copies and allows support for memory-mapped database implementations.
   126  	ForEach(func(k, v []byte) error) error
   127  
   128  	// ForEachBucket invokes the passed function with the key of every
   129  	// nested bucket in the current bucket.  This does not include any
   130  	// nested buckets within those nested buckets.
   131  	//
   132  	// WARNING: It is not safe to mutate data while iterating with this
   133  	// method.  Doing so may cause the underlying cursor to be invalidated
   134  	// and return unexpected keys and/or values.
   135  	//
   136  	// The interface contract guarantees at least the following errors will
   137  	// be returned (other implementation-specific errors are possible):
   138  	//   - ErrTxClosed if the transaction has already been closed
   139  	//
   140  	// NOTE: The keys returned by this function are only valid during a
   141  	// transaction.  Attempting to access them after a transaction has ended
   142  	// results in undefined behavior.  This constraint prevents additional
   143  	// data copies and allows support for memory-mapped database
   144  	// implementations.
   145  	ForEachBucket(func(k []byte) error) error
   146  
   147  	// Cursor returns a new cursor, allowing for iteration over the bucket's
   148  	// key/value pairs and nested buckets in forward or backward order.
   149  	//
   150  	// You must seek to a position using the First, Last, or Seek functions
   151  	// before calling the Next, Prev, Key, or Value functions.  Failure to
   152  	// do so will result in the same return values as an exhausted cursor,
   153  	// which is false for the Prev and Next functions and nil for Key and
   154  	// Value functions.
   155  	Cursor() Cursor
   156  
   157  	// Writable returns whether or not the bucket is writable.
   158  	Writable() bool
   159  
   160  	// Put saves the specified key/value pair to the bucket.  Keys that do
   161  	// not already exist are added and keys that already exist are
   162  	// overwritten.
   163  	//
   164  	// The interface contract guarantees at least the following errors will
   165  	// be returned (other implementation-specific errors are possible):
   166  	//   - ErrKeyRequired if the key is empty
   167  	//   - ErrIncompatibleValue if the key is the same as an existing bucket
   168  	//   - ErrTxNotWritable if attempted against a read-only transaction
   169  	//   - ErrTxClosed if the transaction has already been closed
   170  	//
   171  	// NOTE: The slices passed to this function must NOT be modified by the
   172  	// caller.  This constraint prevents the requirement for additional data
   173  	// copies and allows support for memory-mapped database implementations.
   174  	Put(key, value []byte) error
   175  
   176  	// Get returns the value for the given key.  Returns nil if the key does
   177  	// not exist in this bucket.  An empty slice is returned for keys that
   178  	// exist but have no value assigned.
   179  	//
   180  	// NOTE: The value returned by this function is only valid during a
   181  	// transaction.  Attempting to access it after a transaction has ended
   182  	// results in undefined behavior.  Additionally, the value must NOT
   183  	// be modified by the caller.  These constraints prevent additional data
   184  	// copies and allows support for memory-mapped database implementations.
   185  	Get(key []byte) []byte
   186  
   187  	// Delete removes the specified key from the bucket.  Deleting a key
   188  	// that does not exist does not return an error.
   189  	//
   190  	// The interface contract guarantees at least the following errors will
   191  	// be returned (other implementation-specific errors are possible):
   192  	//   - ErrKeyRequired if the key is empty
   193  	//   - ErrIncompatibleValue if the key is the same as an existing bucket
   194  	//   - ErrTxNotWritable if attempted against a read-only transaction
   195  	//   - ErrTxClosed if the transaction has already been closed
   196  	Delete(key []byte) error
   197  }
   198  
   199  // BlockRegion specifies a particular region of a block identified by the
   200  // specified hash, given an offset and length.
   201  type BlockRegion struct {
   202  	Hash   *wire.ShaHash
   203  	Offset uint32
   204  	Len    uint32
   205  }
   206  
   207  // Tx represents a database transaction.  It can either by read-only or
   208  // read-write.  The transaction provides a metadata bucket against which all
   209  // read and writes occur.
   210  //
   211  // As would be expected with a transaction, no changes will be saved to the
   212  // database until it has been committed.  The transaction will only provide a
   213  // view of the database at the time it was created.  Transactions should not be
   214  // long running operations.
   215  type Tx interface {
   216  	// Metadata returns the top-most bucket for all metadata storage.
   217  	Metadata() Bucket
   218  
   219  	// StoreBlock stores the provided block into the database.  There are no
   220  	// checks to ensure the block connects to a previous block, contains
   221  	// double spends, or any additional functionality such as transaction
   222  	// indexing.  It simply stores the block in the database.
   223  	//
   224  	// The interface contract guarantees at least the following errors will
   225  	// be returned (other implementation-specific errors are possible):
   226  	//   - ErrBlockExists when the block hash already exists
   227  	//   - ErrTxNotWritable if attempted against a read-only transaction
   228  	//   - ErrTxClosed if the transaction has already been closed
   229  	//
   230  	// Other errors are possible depending on the implementation.
   231  	StoreBlock(block *godashutil.Block) error
   232  
   233  	// HasBlock returns whether or not a block with the given hash exists
   234  	// in the database.
   235  	//
   236  	// The interface contract guarantees at least the following errors will
   237  	// be returned (other implementation-specific errors are possible):
   238  	//   - ErrTxClosed if the transaction has already been closed
   239  	//
   240  	// Other errors are possible depending on the implementation.
   241  	HasBlock(hash *wire.ShaHash) (bool, error)
   242  
   243  	// HasBlocks returns whether or not the blocks with the provided hashes
   244  	// exist in the database.
   245  	//
   246  	// The interface contract guarantees at least the following errors will
   247  	// be returned (other implementation-specific errors are possible):
   248  	//   - ErrTxClosed if the transaction has already been closed
   249  	//
   250  	// Other errors are possible depending on the implementation.
   251  	HasBlocks(hashes []wire.ShaHash) ([]bool, error)
   252  
   253  	// FetchBlockHeader returns the raw serialized bytes for the block
   254  	// header identified by the given hash.  The raw bytes are in the format
   255  	// returned by Serialize on a wire.BlockHeader.
   256  	//
   257  	// It is highly recommended to use this function (or FetchBlockHeaders)
   258  	// to obtain block headers over the FetchBlockRegion(s) functions since
   259  	// it provides the backend drivers the freedom to perform very specific
   260  	// optimizations which can result in significant speed advantages when
   261  	// working with headers.
   262  	//
   263  	// The interface contract guarantees at least the following errors will
   264  	// be returned (other implementation-specific errors are possible):
   265  	//   - ErrBlockNotFound if the requested block hash does not exist
   266  	//   - ErrTxClosed if the transaction has already been closed
   267  	//   - ErrCorruption if the database has somehow become corrupted
   268  	//
   269  	// NOTE: The data returned by this function is only valid during a
   270  	// database transaction.  Attempting to access it after a transaction
   271  	// has ended results in undefined behavior.  This constraint prevents
   272  	// additional data copies and allows support for memory-mapped database
   273  	// implementations.
   274  	FetchBlockHeader(hash *wire.ShaHash) ([]byte, error)
   275  
   276  	// FetchBlockHeaders returns the raw serialized bytes for the block
   277  	// headers identified by the given hashes.  The raw bytes are in the
   278  	// format returned by Serialize on a wire.BlockHeader.
   279  	//
   280  	// It is highly recommended to use this function (or FetchBlockHeader)
   281  	// to obtain block headers over the FetchBlockRegion(s) functions since
   282  	// it provides the backend drivers the freedom to perform very specific
   283  	// optimizations which can result in significant speed advantages when
   284  	// working with headers.
   285  	//
   286  	// Furthermore, depending on the specific implementation, this function
   287  	// can be more efficient for bulk loading multiple block headers than
   288  	// loading them one-by-one with FetchBlockHeader.
   289  	//
   290  	// The interface contract guarantees at least the following errors will
   291  	// be returned (other implementation-specific errors are possible):
   292  	//   - ErrBlockNotFound if any of the request block hashes do not exist
   293  	//   - ErrTxClosed if the transaction has already been closed
   294  	//   - ErrCorruption if the database has somehow become corrupted
   295  	//
   296  	// NOTE: The data returned by this function is only valid during a
   297  	// database transaction.  Attempting to access it after a transaction
   298  	// has ended results in undefined behavior.  This constraint prevents
   299  	// additional data copies and allows support for memory-mapped database
   300  	// implementations.
   301  	FetchBlockHeaders(hashes []wire.ShaHash) ([][]byte, error)
   302  
   303  	// FetchBlock returns the raw serialized bytes for the block identified
   304  	// by the given hash.  The raw bytes are in the format returned by
   305  	// Serialize on a wire.MsgBlock.
   306  	//
   307  	// The interface contract guarantees at least the following errors will
   308  	// be returned (other implementation-specific errors are possible):
   309  	//   - ErrBlockNotFound if the requested block hash does not exist
   310  	//   - ErrTxClosed if the transaction has already been closed
   311  	//   - ErrCorruption if the database has somehow become corrupted
   312  	//
   313  	// NOTE: The data returned by this function is only valid during a
   314  	// database transaction.  Attempting to access it after a transaction
   315  	// has ended results in undefined behavior.  This constraint prevents
   316  	// additional data copies and allows support for memory-mapped database
   317  	// implementations.
   318  	FetchBlock(hash *wire.ShaHash) ([]byte, error)
   319  
   320  	// FetchBlocks returns the raw serialized bytes for the blocks
   321  	// identified by the given hashes.  The raw bytes are in the format
   322  	// returned by Serialize on a wire.MsgBlock.
   323  	//
   324  	// The interface contract guarantees at least the following errors will
   325  	// be returned (other implementation-specific errors are possible):
   326  	//   - ErrBlockNotFound if the any of the requested block hashes do not
   327  	//     exist
   328  	//   - ErrTxClosed if the transaction has already been closed
   329  	//   - ErrCorruption if the database has somehow become corrupted
   330  	//
   331  	// NOTE: The data returned by this function is only valid during a
   332  	// database transaction.  Attempting to access it after a transaction
   333  	// has ended results in undefined behavior.  This constraint prevents
   334  	// additional data copies and allows support for memory-mapped database
   335  	// implementations.
   336  	FetchBlocks(hashes []wire.ShaHash) ([][]byte, error)
   337  
   338  	// FetchBlockRegion returns the raw serialized bytes for the given
   339  	// block region.
   340  	//
   341  	// For example, it is possible to directly extract Bitcoin transactions
   342  	// and/or scripts from a block with this function.  Depending on the
   343  	// backend implementation, this can provide significant savings by
   344  	// avoiding the need to load entire blocks.
   345  	//
   346  	// The raw bytes are in the format returned by Serialize on a
   347  	// wire.MsgBlock and the Offset field in the provided BlockRegion is
   348  	// zero-based and relative to the start of the block (byte 0).
   349  	//
   350  	// The interface contract guarantees at least the following errors will
   351  	// be returned (other implementation-specific errors are possible):
   352  	//   - ErrBlockNotFound if the requested block hash does not exist
   353  	//   - ErrBlockRegionInvalid if the region exceeds the bounds of the
   354  	//     associated block
   355  	//   - ErrTxClosed if the transaction has already been closed
   356  	//   - ErrCorruption if the database has somehow become corrupted
   357  	//
   358  	// NOTE: The data returned by this function is only valid during a
   359  	// database transaction.  Attempting to access it after a transaction
   360  	// has ended results in undefined behavior.  This constraint prevents
   361  	// additional data copies and allows support for memory-mapped database
   362  	// implementations.
   363  	FetchBlockRegion(region *BlockRegion) ([]byte, error)
   364  
   365  	// FetchBlockRegions returns the raw serialized bytes for the given
   366  	// block regions.
   367  	//
   368  	// For example, it is possible to directly extract Bitcoin transactions
   369  	// and/or scripts from various blocks with this function.  Depending on
   370  	// the backend implementation, this can provide significant savings by
   371  	// avoiding the need to load entire blocks.
   372  	//
   373  	// The raw bytes are in the format returned by Serialize on a
   374  	// wire.MsgBlock and the Offset fields in the provided BlockRegions are
   375  	// zero-based and relative to the start of the block (byte 0).
   376  	//
   377  	// The interface contract guarantees at least the following errors will
   378  	// be returned (other implementation-specific errors are possible):
   379  	//   - ErrBlockNotFound if any of the requested block hashed do not
   380  	//     exist
   381  	//   - ErrBlockRegionInvalid if one or more region exceed the bounds of
   382  	//     the associated block
   383  	//   - ErrTxClosed if the transaction has already been closed
   384  	//   - ErrCorruption if the database has somehow become corrupted
   385  	//
   386  	// NOTE: The data returned by this function is only valid during a
   387  	// database transaction.  Attempting to access it after a transaction
   388  	// has ended results in undefined behavior.  This constraint prevents
   389  	// additional data copies and allows support for memory-mapped database
   390  	// implementations.
   391  	FetchBlockRegions(regions []BlockRegion) ([][]byte, error)
   392  
   393  	// ******************************************************************
   394  	// Methods related to both atomic metadata storage and block storage.
   395  	// ******************************************************************
   396  
   397  	// Commit commits all changes that have been made to the metadata or
   398  	// block storage.  Depending on the backend implementation this could be
   399  	// to a cache that is periodically synced to persistent storage or
   400  	// directly to persistent storage.  In any case, all transactions which
   401  	// are started after the commit finishes will include all changes made
   402  	// by this transaction.  Calling this function on a managed transaction
   403  	// will result in a panic.
   404  	Commit() error
   405  
   406  	// Rollback undoes all changes that have been made to the metadata or
   407  	// block storage.  Calling this function on a managed transaction will
   408  	// result in a panic.
   409  	Rollback() error
   410  }
   411  
   412  // DB provides a generic interface that is used to store bitcoin blocks and
   413  // related metadata.  This interface is intended to be agnostic to the actual
   414  // mechanism used for backend data storage.  The RegisterDriver function can be
   415  // used to add a new backend data storage method.
   416  //
   417  // This interface is divided into two distinct categories of functionality.
   418  //
   419  // The first category is atomic metadata storage with bucket support.  This is
   420  // accomplished through the use of database transactions.
   421  //
   422  // The second category is generic block storage.  This functionality is
   423  // intentionally separate because the mechanism used for block storage may or
   424  // may not be the same mechanism used for metadata storage.  For example, it is
   425  // often more efficient to store the block data as flat files while the metadata
   426  // is kept in a database.  However, this interface aims to be generic enough to
   427  // support blocks in the database too, if needed by a particular backend.
   428  type DB interface {
   429  	// Type returns the database driver type the current database instance
   430  	// was created with.
   431  	Type() string
   432  
   433  	// Begin starts a transaction which is either read-only or read-write
   434  	// depending on the specified flag.  Multiple read-only transactions
   435  	// can be started simultaneously while only a single read-write
   436  	// transaction can be started at a time.  The call will block when
   437  	// starting a read-write transaction when one is already open.
   438  	//
   439  	// NOTE: The transaction must be closed by calling Rollback or Commit on
   440  	// it when it is no longer needed.  Failure to do so can result in
   441  	// unclaimed memory and/or inablity to close the database due to locks
   442  	// depending on the specific database implementation.
   443  	Begin(writable bool) (Tx, error)
   444  
   445  	// View invokes the passed function in the context of a managed
   446  	// read-only transaction.  Any errors returned from the user-supplied
   447  	// function are returned from this function.
   448  	//
   449  	// Calling Rollback or Commit on the transaction passed to the
   450  	// user-supplied function will result in a panic.
   451  	View(fn func(tx Tx) error) error
   452  
   453  	// Update invokes the passed function in the context of a managed
   454  	// read-write transaction.  Any errors returned from the user-supplied
   455  	// function will cause the transaction to be rolled back and are
   456  	// returned from this function.  Otherwise, the transaction is committed
   457  	// when the user-supplied function returns a nil error.
   458  	//
   459  	// Calling Rollback or Commit on the transaction passed to the
   460  	// user-supplied function will result in a panic.
   461  	Update(fn func(tx Tx) error) error
   462  
   463  	// Close cleanly shuts down the database and syncs all data.  It will
   464  	// block until all database transactions have been finalized (rolled
   465  	// back or committed).
   466  	Close() error
   467  }