github.com/MetalBlockchain/metalgo@v1.11.9/x/archivedb/db.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package archivedb 5 6 import ( 7 "context" 8 "errors" 9 "io" 10 11 "github.com/MetalBlockchain/metalgo/api/health" 12 "github.com/MetalBlockchain/metalgo/database" 13 ) 14 15 var ( 16 ErrNotImplemented = errors.New("feature not implemented") 17 ErrInvalidValue = errors.New("invalid data value") 18 19 _ database.Compacter = (*Database)(nil) 20 _ health.Checker = (*Database)(nil) 21 _ io.Closer = (*Database)(nil) 22 ) 23 24 // Database implements an ArchiveDB on top of a database.Database. An ArchiveDB 25 // is an append only database which stores all state changes happening at every 26 // height. Each record is stored in such way to perform both fast insertions and 27 // lookups. 28 // 29 // The API is quite simple, it has two main functions, one to create a Batch 30 // write with a given height, inside this batch entries can be added with a 31 // given value or they can be deleted. 32 // 33 // The way it works is as follows: 34 // - NewBatch(10) 35 // batch.Put(foo, "foo's value is bar") 36 // batch.Put(bar, "bar's value is bar") 37 // - NewBatch(100) 38 // batch.Put(foo, "updatedfoo's value is bar") 39 // - NewBatch(1000) 40 // batch.Put(bar, "updated bar's value is bar") 41 // batch.Delete(foo) 42 // 43 // The other primary function is to read data at a given height. 44 // 45 // The way it works is as follows: 46 // - Open(10) 47 // reader.Get(foo) 48 // reader.Get(bar) 49 // - Open(99) 50 // reader.GetHeight(foo) 51 // - Open(100) 52 // reader.Get(foo) 53 // - Open(1000) 54 // reader.Get(foo) 55 // 56 // Requesting `reader.Get(foo)` at height 1000 will return ErrNotFound because 57 // foo was deleted at height 1000. When calling `reader.GetHeight(foo)` at 58 // height 99 it will return a tuple `("foo's value is bar", 10)` returning the 59 // value of `foo` at height 99 (which was set at height 10). 60 type Database struct { 61 db database.Database 62 } 63 64 func New(db database.Database) *Database { 65 return &Database{ 66 db: db, 67 } 68 } 69 70 // Height returns the last written height. 71 func (db *Database) Height() (uint64, error) { 72 return database.GetUInt64(db.db, heightKey) 73 } 74 75 // Open returns a reader for the state at the given height. 76 func (db *Database) Open(height uint64) *Reader { 77 return &Reader{ 78 db: db, 79 height: height, 80 } 81 } 82 83 // NewBatch creates a write batch to perform changes at a given height. 84 // 85 // Note: Committing multiple batches at the same height, or at a lower height 86 // than the currently committed height will not error. It is left up to the 87 // caller to enforce any guarantees they need around height consistency. 88 func (db *Database) NewBatch(height uint64) *batch { 89 return &batch{ 90 db: db, 91 height: height, 92 } 93 } 94 95 func (db *Database) Compact(start []byte, limit []byte) error { 96 return db.db.Compact(start, limit) 97 } 98 99 func (db *Database) HealthCheck(ctx context.Context) (interface{}, error) { 100 return db.db.HealthCheck(ctx) 101 } 102 103 func (db *Database) Close() error { 104 return db.db.Close() 105 }