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