github.com/btcsuite/btcwallet/walletdb@v1.4.2/interface.go (about) 1 // Copyright (c) 2014 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 // This interface was inspired heavily by the excellent boltdb project at 6 // https://github.com/boltdb/bolt by Ben B. Johnson. 7 8 package walletdb 9 10 import ( 11 "fmt" 12 "io" 13 ) 14 15 // ReadTx represents a database transaction that can only be used for reads. If 16 // a database update must occur, use a ReadWriteTx. 17 type ReadTx interface { 18 // ReadBucket opens the root bucket for read only access. If the bucket 19 // described by the key does not exist, nil is returned. 20 ReadBucket(key []byte) ReadBucket 21 22 // ForEachBucket will iterate through all top level buckets. 23 ForEachBucket(func(key []byte) error) error 24 25 // Rollback closes the transaction, discarding changes (if any) if the 26 // database was modified by a write transaction. 27 Rollback() error 28 } 29 30 // ReadWriteTx represents a database transaction that can be used for both reads 31 // and writes. When only reads are necessary, consider using a ReadTx instead. 32 type ReadWriteTx interface { 33 ReadTx 34 35 // ReadWriteBucket opens the root bucket for read/write access. If the 36 // bucket described by the key does not exist, nil is returned. 37 ReadWriteBucket(key []byte) ReadWriteBucket 38 39 // CreateTopLevelBucket creates the top level bucket for a key if it 40 // does not exist. The newly-created bucket it returned. 41 CreateTopLevelBucket(key []byte) (ReadWriteBucket, error) 42 43 // DeleteTopLevelBucket deletes the top level bucket for a key. This 44 // errors if the bucket can not be found or the key keys a single value 45 // instead of a bucket. 46 DeleteTopLevelBucket(key []byte) error 47 48 // Commit commits all changes that have been on the transaction's root 49 // buckets and all of their sub-buckets to persistent storage. 50 Commit() error 51 52 // OnCommit takes a function closure that will be executed when the 53 // transaction successfully gets committed. 54 OnCommit(func()) 55 } 56 57 // ReadBucket represents a bucket (a hierarchical structure within the database) 58 // that is only allowed to perform read operations. 59 type ReadBucket interface { 60 // NestedReadBucket retrieves a nested bucket with the given key. 61 // Returns nil if the bucket does not exist. 62 NestedReadBucket(key []byte) ReadBucket 63 64 // ForEach invokes the passed function with every key/value pair in 65 // the bucket. This includes nested buckets, in which case the value 66 // is nil, but it does not include the key/value pairs within those 67 // nested buckets. 68 // 69 // NOTE: The values returned by this function are only valid during a 70 // transaction. Attempting to access them after a transaction has ended 71 // results in undefined behavior. This constraint prevents additional 72 // data copies and allows support for memory-mapped database 73 // implementations. 74 ForEach(func(k, v []byte) error) error 75 76 // Get returns the value for the given key. Returns nil if the key does 77 // not exist in this bucket (or nested buckets). 78 // 79 // NOTE: The value returned by this function is only valid during a 80 // transaction. Attempting to access it after a transaction has ended 81 // results in undefined behavior. This constraint prevents additional 82 // data copies and allows support for memory-mapped database 83 // implementations. 84 Get(key []byte) []byte 85 86 ReadCursor() ReadCursor 87 } 88 89 // ReadWriteBucket represents a bucket (a hierarchical structure within the 90 // database) that is allowed to perform both read and write operations. 91 type ReadWriteBucket interface { 92 ReadBucket 93 94 // NestedReadWriteBucket retrieves a nested bucket with the given key. 95 // Returns nil if the bucket does not exist. 96 NestedReadWriteBucket(key []byte) ReadWriteBucket 97 98 // CreateBucket creates and returns a new nested bucket with the given 99 // key. Returns ErrBucketExists if the bucket already exists, 100 // ErrBucketNameRequired if the key is empty, or ErrIncompatibleValue 101 // if the key value is otherwise invalid for the particular database 102 // implementation. Other errors are possible depending on the 103 // implementation. 104 CreateBucket(key []byte) (ReadWriteBucket, error) 105 106 // CreateBucketIfNotExists creates and returns a new nested bucket with 107 // the given key if it does not already exist. Returns 108 // ErrBucketNameRequired if the key is empty or ErrIncompatibleValue 109 // if the key value is otherwise invalid for the particular database 110 // backend. Other errors are possible depending on the implementation. 111 CreateBucketIfNotExists(key []byte) (ReadWriteBucket, error) 112 113 // DeleteNestedBucket removes a nested bucket with the given key. 114 // Returns ErrTxNotWritable if attempted against a read-only transaction 115 // and ErrBucketNotFound if the specified bucket does not exist. 116 DeleteNestedBucket(key []byte) error 117 118 // Put saves the specified key/value pair to the bucket. Keys that do 119 // not already exist are added and keys that already exist are 120 // overwritten. Returns ErrTxNotWritable if attempted against a 121 // read-only transaction. 122 Put(key, value []byte) error 123 124 // Delete removes the specified key from the bucket. Deleting a key 125 // that does not exist does not return an error. Returns 126 // ErrTxNotWritable if attempted against a read-only transaction. 127 Delete(key []byte) error 128 129 // ReadWriteCursor returns a new cursor, allowing for iteration over the 130 // bucket's key/value pairs and nested buckets in forward or backward 131 // order. 132 ReadWriteCursor() ReadWriteCursor 133 134 // Tx returns the bucket's transaction. 135 Tx() ReadWriteTx 136 137 // NextSequence returns an autoincrementing integer for the bucket. 138 NextSequence() (uint64, error) 139 140 // SetSequence updates the sequence number for the bucket. 141 SetSequence(v uint64) error 142 143 // Sequence returns the current integer for the bucket without 144 // incrementing it. 145 Sequence() uint64 146 } 147 148 // ReadCursor represents a bucket cursor that can be positioned at the start or 149 // end of the bucket's key/value pairs and iterate over pairs in the bucket. 150 // This type is only allowed to perform database read operations. 151 type ReadCursor interface { 152 // First positions the cursor at the first key/value pair and returns 153 // the pair. 154 First() (key, value []byte) 155 156 // Last positions the cursor at the last key/value pair and returns the 157 // pair. 158 Last() (key, value []byte) 159 160 // Next moves the cursor one key/value pair forward and returns the new 161 // pair. 162 Next() (key, value []byte) 163 164 // Prev moves the cursor one key/value pair backward and returns the new 165 // pair. 166 Prev() (key, value []byte) 167 168 // Seek positions the cursor at the passed seek key. If the key does 169 // not exist, the cursor is moved to the next key after seek. Returns 170 // the new pair. 171 Seek(seek []byte) (key, value []byte) 172 } 173 174 // ReadWriteCursor represents a bucket cursor that can be positioned at the 175 // start or end of the bucket's key/value pairs and iterate over pairs in the 176 // bucket. This abstraction is allowed to perform both database read and write 177 // operations. 178 type ReadWriteCursor interface { 179 ReadCursor 180 181 // Delete removes the current key/value pair the cursor is at without 182 // invalidating the cursor. Returns ErrIncompatibleValue if attempted 183 // when the cursor points to a nested bucket. 184 Delete() error 185 } 186 187 // BucketIsEmpty returns whether the bucket is empty, that is, whether there are 188 // no key/value pairs or nested buckets. 189 func BucketIsEmpty(bucket ReadBucket) bool { 190 k, v := bucket.ReadCursor().First() 191 return k == nil && v == nil 192 } 193 194 // DB represents an ACID database. All database access is performed through 195 // read or read+write transactions. 196 type DB interface { 197 // BeginReadTx opens a database read transaction. 198 BeginReadTx() (ReadTx, error) 199 200 // BeginReadWriteTx opens a database read+write transaction. 201 BeginReadWriteTx() (ReadWriteTx, error) 202 203 // Copy writes a copy of the database to the provided writer. This 204 // call will start a read-only transaction to perform all operations. 205 Copy(w io.Writer) error 206 207 // Close cleanly shuts down the database and syncs all data. 208 Close() error 209 210 // PrintStats returns all collected stats pretty printed into a string. 211 PrintStats() string 212 213 // View opens a database read transaction and executes the function f 214 // with the transaction passed as a parameter. After f exits, the 215 // transaction is rolled back. If f errors, its error is returned, not a 216 // rollback error (if any occur). The passed reset function is called 217 // before the start of the transaction and can be used to reset 218 // intermediate state. As callers may expect retries of the f closure 219 // (depending on the database backend used), the reset function will be 220 // called before each retry respectively. 221 // 222 // NOTE: For new code, this method should be used directly instead of 223 // the package level View() function. 224 View(f func(tx ReadTx) error, reset func()) error 225 226 // Update opens a database read/write transaction and executes the 227 // function f with the transaction passed as a parameter. After f exits, 228 // if f did not error, the transaction is committed. Otherwise, if f did 229 // error, the transaction is rolled back. If the rollback fails, the 230 // original error returned by f is still returned. If the commit fails, 231 // the commit error is returned. As callers may expect retries of the f 232 // closure (depending on the database backend used), the reset function 233 // will be called before each retry respectively. 234 // 235 // NOTE: For new code, this method should be used directly instead of 236 // the package level Update() function. 237 Update(f func(tx ReadWriteTx) error, reset func()) error 238 } 239 240 // BatchDB is a special version of the main DB interface that allows the caller 241 // to specify write transactions that should be combined toegether if multiple 242 // goroutines are calling the Batch method. 243 type BatchDB interface { 244 DB 245 246 // Batch is similar to the package-level Update method, but it will 247 // attempt to optimistically combine the invocation of several 248 // transaction functions into a single db write transaction. 249 Batch(func(tx ReadWriteTx) error) error 250 } 251 252 // View opens a database read transaction and executes the function f with the 253 // transaction passed as a parameter. After f exits, the transaction is rolled 254 // back. If f errors, its error is returned, not a rollback error (if any 255 // occur). 256 // 257 // NOTE: For new code the database backend's View method should be used directly 258 // as this package level function will be phased out in the future. 259 func View(db DB, f func(tx ReadTx) error) error { 260 return db.View(f, func() {}) 261 } 262 263 // Update opens a database read/write transaction and executes the function f 264 // with the transaction passed as a parameter. After f exits, if f did not 265 // error, the transaction is committed. Otherwise, if f did error, the 266 // transaction is rolled back. If the rollback fails, the original error 267 // returned by f is still returned. If the commit fails, the commit error is 268 // returned. 269 // 270 // NOTE: For new code the database backend's Update method should be used 271 // directly as this package level function will be phased out in the future. 272 func Update(db DB, f func(tx ReadWriteTx) error) error { 273 return db.Update(f, func() {}) 274 } 275 276 // Batch opens a database read/write transaction and executes the function f 277 // with the transaction passed as a parameter. After f exits, if f did not 278 // error, the transaction is committed. Otherwise, if f did error, the 279 // transaction is rolled back. If the rollback fails, the original error 280 // returned by f is still returned. If the commit fails, the commit error is 281 // returned. 282 // 283 // Batch is only useful when there are multiple goroutines calling it. 284 func Batch(db DB, f func(tx ReadWriteTx) error) error { 285 batchDB, ok := db.(BatchDB) 286 if !ok { 287 return fmt.Errorf("need batch") 288 } 289 290 return batchDB.Batch(f) 291 } 292 293 // Driver defines a structure for backend drivers to use when they registered 294 // themselves as a backend which implements the Db interface. 295 type Driver struct { 296 // DbType is the identifier used to uniquely identify a specific 297 // database driver. There can be only one driver with the same name. 298 DbType string 299 300 // Create is the function that will be invoked with all user-specified 301 // arguments to create the database. This function must return 302 // ErrDbExists if the database already exists. 303 Create func(args ...interface{}) (DB, error) 304 305 // Open is the function that will be invoked with all user-specified 306 // arguments to open the database. This function must return 307 // ErrDbDoesNotExist if the database has not already been created. 308 Open func(args ...interface{}) (DB, error) 309 } 310 311 // driverList holds all of the registered database backends. 312 var drivers = make(map[string]*Driver) 313 314 // RegisterDriver adds a backend database driver to available interfaces. 315 // ErrDbTypeRegistered will be retruned if the database type for the driver has 316 // already been registered. 317 func RegisterDriver(driver Driver) error { 318 if _, exists := drivers[driver.DbType]; exists { 319 return ErrDbTypeRegistered 320 } 321 322 drivers[driver.DbType] = &driver 323 return nil 324 } 325 326 // SupportedDrivers returns a slice of strings that represent the database 327 // drivers that have been registered and are therefore supported. 328 func SupportedDrivers() []string { 329 supportedDBs := make([]string, 0, len(drivers)) 330 for _, drv := range drivers { 331 supportedDBs = append(supportedDBs, drv.DbType) 332 } 333 return supportedDBs 334 } 335 336 // Create intializes and opens a database for the specified type. The arguments 337 // are specific to the database type driver. See the documentation for the 338 // database driver for further details. 339 // 340 // ErrDbUnknownType will be returned if the the database type is not registered. 341 func Create(dbType string, args ...interface{}) (DB, error) { 342 drv, exists := drivers[dbType] 343 if !exists { 344 return nil, ErrDbUnknownType 345 } 346 347 return drv.Create(args...) 348 } 349 350 // Open opens an existing database for the specified type. The arguments are 351 // specific to the database type driver. See the documentation for the database 352 // driver for further details. 353 // 354 // ErrDbUnknownType will be returned if the the database type is not registered. 355 func Open(dbType string, args ...interface{}) (DB, error) { 356 drv, exists := drivers[dbType] 357 if !exists { 358 return nil, ErrDbUnknownType 359 } 360 361 return drv.Open(args...) 362 }