github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/explorer/database.go (about)

     1  package explorer
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/NebulousLabs/Sia/encoding"
     7  	"github.com/NebulousLabs/Sia/types"
     8  
     9  	"github.com/NebulousLabs/bolt"
    10  )
    11  
    12  var (
    13  	errNotExist = errors.New("entry does not exist")
    14  
    15  	// database buckets
    16  	bucketBlockFacts            = []byte("BlockFacts")
    17  	bucketBlockIDs              = []byte("BlockIDs")
    18  	bucketBlocksDifficulty      = []byte("BlocksDifficulty")
    19  	bucketBlockTargets          = []byte("BlockTargets")
    20  	bucketFileContractHistories = []byte("FileContractHistories")
    21  	bucketFileContractIDs       = []byte("FileContractIDs")
    22  	bucketSiacoinOutputIDs      = []byte("SiacoinOutputIDs")
    23  	bucketSiacoinOutputs        = []byte("SiacoinOutputs")
    24  	bucketSiafundOutputIDs      = []byte("SiafundOutputIDs")
    25  	bucketSiafundOutputs        = []byte("SiafundOutputs")
    26  	bucketTransactionIDs        = []byte("TransactionIDs")
    27  	bucketUnlockHashes          = []byte("UnlockHashes")
    28  
    29  	// bucketInternal is used to store values internal to the explorer
    30  	bucketInternal = []byte("Internal")
    31  
    32  	// keys for bucketInternal
    33  	internalBlockHeight  = []byte("BlockHeight")
    34  	internalRecentChange = []byte("RecentChange")
    35  )
    36  
    37  // These functions all return a 'func(*bolt.Tx) error', which, allows them to
    38  // be called concisely with the db.View and db.Update functions, e.g.:
    39  //
    40  //    var height types.BlockHeight
    41  //    db.View(dbGetAndDecode(bucketBlockIDs, id, &height))
    42  //
    43  // Instead of:
    44  //
    45  //   var height types.BlockHeight
    46  //   db.View(func(tx *bolt.Tx) error {
    47  //       bytes := tx.Bucket(bucketBlockIDs).Get(encoding.Marshal(id))
    48  //       return encoding.Unmarshal(bytes, &height)
    49  //   })
    50  
    51  // dbGetAndDecode returns a 'func(*bolt.Tx) error' that retrieves and decodes
    52  // a value from the specified bucket. If the value does not exist,
    53  // dbGetAndDecode returns errNotExist.
    54  func dbGetAndDecode(bucket []byte, key, val interface{}) func(*bolt.Tx) error {
    55  	return func(tx *bolt.Tx) error {
    56  		valBytes := tx.Bucket(bucket).Get(encoding.Marshal(key))
    57  		if valBytes == nil {
    58  			return errNotExist
    59  		}
    60  		return encoding.Unmarshal(valBytes, val)
    61  	}
    62  }
    63  
    64  // dbGetTransactionIDSet returns a 'func(*bolt.Tx) error' that decodes a
    65  // bucket of transaction IDs into a slice. If the bucket is nil,
    66  // dbGetTransactionIDSet returns errNotExist.
    67  func dbGetTransactionIDSet(bucket []byte, key interface{}, ids *[]types.TransactionID) func(*bolt.Tx) error {
    68  	return func(tx *bolt.Tx) error {
    69  		b := tx.Bucket(bucket).Bucket(encoding.Marshal(key))
    70  		if b == nil {
    71  			return errNotExist
    72  		}
    73  		// decode into a local slice
    74  		var txids []types.TransactionID
    75  		err := b.ForEach(func(txid, _ []byte) error {
    76  			var id types.TransactionID
    77  			err := encoding.Unmarshal(txid, &id)
    78  			if err != nil {
    79  				return err
    80  			}
    81  			txids = append(txids, id)
    82  			return nil
    83  		})
    84  		if err != nil {
    85  			return err
    86  		}
    87  		// set pointer
    88  		*ids = txids
    89  		return nil
    90  	}
    91  }
    92  
    93  // dbSetInternal sets the specified key of bucketInternal to the encoded value.
    94  func dbSetInternal(key []byte, val interface{}) func(*bolt.Tx) error {
    95  	return func(tx *bolt.Tx) error {
    96  		return tx.Bucket(bucketInternal).Put(key, encoding.Marshal(val))
    97  	}
    98  }
    99  
   100  // dbGetInternal decodes the specified key of bucketInternal into the supplied pointer.
   101  func dbGetInternal(key []byte, val interface{}) func(*bolt.Tx) error {
   102  	return func(tx *bolt.Tx) error {
   103  		return encoding.Unmarshal(tx.Bucket(bucketInternal).Get(key), val)
   104  	}
   105  }