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  }