2020-03-24 02:12:55 +00:00
package ethdb
import (
"context"
2020-08-05 10:13:35 +00:00
"errors"
2020-11-28 15:08:02 +00:00
"unsafe"
2020-09-29 14:09:29 +00:00
2020-08-30 17:34:18 +00:00
"github.com/ledgerwatch/turbo-geth/common/dbutils"
2021-03-09 06:34:13 +00:00
"github.com/ledgerwatch/turbo-geth/metrics"
2020-08-05 10:13:35 +00:00
)
2021-03-23 07:28:04 +00:00
const ReadersLimit = 2000 // MDBX_READERS_LIMIT on 64bit system
2020-08-05 10:13:35 +00:00
var (
ErrAttemptToDeleteNonDeprecatedBucket = errors . New ( "only buckets from dbutils.DeprecatedBuckets can be deleted" )
ErrUnknownBucket = errors . New ( "unknown bucket. add it to dbutils.Buckets" )
2021-03-09 06:34:13 +00:00
2021-03-10 03:58:57 +00:00
dbSize = metrics . GetOrRegisterGauge ( "db/size" , metrics . DefaultRegistry )
tableScsLeaf = metrics . GetOrRegisterGauge ( "table/scs/leaf" , metrics . DefaultRegistry ) //nolint
tableScsBranch = metrics . GetOrRegisterGauge ( "table/scs/branch" , metrics . DefaultRegistry ) //nolint
tableScsOverflow = metrics . GetOrRegisterGauge ( "table/scs/overflow" , metrics . DefaultRegistry ) //nolint
tableScsEntries = metrics . GetOrRegisterGauge ( "table/scs/entries" , metrics . DefaultRegistry ) //nolint
tableStateLeaf = metrics . GetOrRegisterGauge ( "table/state/leaf" , metrics . DefaultRegistry ) //nolint
tableStateBranch = metrics . GetOrRegisterGauge ( "table/state/branch" , metrics . DefaultRegistry ) //nolint
tableStateOverflow = metrics . GetOrRegisterGauge ( "table/state/overflow" , metrics . DefaultRegistry ) //nolint
tableStateEntries = metrics . GetOrRegisterGauge ( "table/state/entries" , metrics . DefaultRegistry ) //nolint
tableLogLeaf = metrics . GetOrRegisterGauge ( "table/log/leaf" , metrics . DefaultRegistry ) //nolint
tableLogBranch = metrics . GetOrRegisterGauge ( "table/log/branch" , metrics . DefaultRegistry ) //nolint
tableLogOverflow = metrics . GetOrRegisterGauge ( "table/log/overflow" , metrics . DefaultRegistry ) //nolint
tableLogEntries = metrics . GetOrRegisterGauge ( "table/log/entries" , metrics . DefaultRegistry ) //nolint
tableTxLeaf = metrics . GetOrRegisterGauge ( "table/tx/leaf" , metrics . DefaultRegistry ) //nolint
tableTxBranch = metrics . GetOrRegisterGauge ( "table/tx/branch" , metrics . DefaultRegistry ) //nolint
tableTxOverflow = metrics . GetOrRegisterGauge ( "table/tx/overflow" , metrics . DefaultRegistry ) //nolint
tableTxEntries = metrics . GetOrRegisterGauge ( "table/tx/entries" , metrics . DefaultRegistry ) //nolint
tableGcLeaf = metrics . GetOrRegisterGauge ( "table/gc/leaf" , metrics . DefaultRegistry ) //nolint
tableGcBranch = metrics . GetOrRegisterGauge ( "table/gc/branch" , metrics . DefaultRegistry ) //nolint
tableGcOverflow = metrics . GetOrRegisterGauge ( "table/gc/overflow" , metrics . DefaultRegistry ) //nolint
tableGcEntries = metrics . GetOrRegisterGauge ( "table/gc/entries" , metrics . DefaultRegistry ) //nolint
2020-03-24 02:12:55 +00:00
)
2020-09-05 07:26:24 +00:00
// KV low-level database interface - main target is - to provide common abstraction over top of LMDB and RemoteKV.
//
// Common pattern for short-living transactions:
//
// if err := db.View(ctx, func(tx ethdb.Tx) error {
// ... code which uses database in transaction
// }); err != nil {
// return err
// }
//
// Common pattern for long-living transactions:
2020-10-25 08:38:55 +00:00
// tx, err := db.Begin(ethdb.RW)
2020-09-05 07:26:24 +00:00
// if err != nil {
// return err
// }
// defer tx.Rollback()
//
// ... code which uses database in transaction
//
// err := tx.Commit()
// if err != nil {
// return err
// }
//
2020-03-24 02:12:55 +00:00
type KV interface {
2020-05-27 16:24:34 +00:00
View ( ctx context . Context , f func ( tx Tx ) error ) error
2021-03-21 13:15:25 +00:00
Update ( ctx context . Context , f func ( tx RwTx ) error ) error
2020-04-04 07:18:10 +00:00
Close ( )
2020-09-05 07:26:24 +00:00
// Begin - creates transaction
// tx may be discarded by .Rollback() method
//
// A transaction and its cursors must only be used by a single
// thread (not goroutine), and a thread may only have a single transaction at a time.
// It happen automatically by - because this method calls runtime.LockOSThread() inside (Rollback/Commit releases it)
// By this reason application code can't call runtime.UnlockOSThread() - it leads to undefined behavior.
//
// If this `parent` is non-NULL, the new transaction
// will be a nested transaction, with the transaction indicated by parent
// as its parent. Transactions may be nested to any level. A parent
// transaction and its cursors may not issue any other operations than
// Commit and Rollback while it has active child transactions.
2021-03-21 13:15:25 +00:00
Begin ( ctx context . Context ) ( Tx , error )
BeginRw ( ctx context . Context ) ( RwTx , error )
2020-08-30 17:34:18 +00:00
AllBuckets ( ) dbutils . BucketsCfg
2021-03-09 06:34:13 +00:00
CollectMetrics ( )
2020-03-24 02:12:55 +00:00
}
2020-10-25 08:38:55 +00:00
type TxFlags uint
const (
2021-03-21 13:15:25 +00:00
RW TxFlags = 0x00 // default
RO TxFlags = 0x02
2020-10-25 08:38:55 +00:00
)
2020-03-24 02:12:55 +00:00
type Tx interface {
2020-09-05 07:26:24 +00:00
// Cursor - creates cursor object on top of given bucket. Type of cursor - depends on bucket configuration.
// If bucket was created with lmdb.DupSort flag, then cursor with interface CursorDupSort created
// Otherwise - object of interface Cursor created
//
// Cursor, also provides a grain of magic - it can use a declarative configuration - and automatically break
// long keys into DupSort key/values. See docs for `bucket.go:BucketConfigItem`
2020-08-14 06:41:18 +00:00
Cursor ( bucket string ) Cursor
2021-02-10 09:56:44 +00:00
CursorDupSort ( bucket string ) CursorDupSort // CursorDupSort - can be used if bucket has lmdb.DupSort flag
2020-10-24 08:09:20 +00:00
GetOne ( bucket string , key [ ] byte ) ( val [ ] byte , err error )
HasOne ( bucket string , key [ ] byte ) ( bool , error )
2020-04-04 07:18:10 +00:00
2020-09-05 07:26:24 +00:00
Commit ( ctx context . Context ) error // Commit all the operations of a transaction into the database.
Rollback ( ) // Rollback - abandon all the operations of the transaction instead of saving them.
2020-08-17 07:24:59 +00:00
BucketSize ( name string ) ( uint64 , error )
2020-09-10 12:35:58 +00:00
Comparator ( bucket string ) dbutils . CmpFunc
2020-11-14 13:48:29 +00:00
2021-03-21 13:15:25 +00:00
// ReadSequence - allows to create a linear sequence of unique positive integers for each table.
2020-11-14 13:48:29 +00:00
// Can be called for a read transaction to retrieve the current sequence value, and the increment must be zero.
// Sequence changes become visible outside the current write transaction after it is committed, and discarded on abort.
// Starts from 0.
2021-03-20 14:12:54 +00:00
ReadSequence ( bucket string ) ( uint64 , error )
2020-11-28 15:08:02 +00:00
CHandle ( ) unsafe . Pointer // Pointer to the underlying C transaction handle (e.g. *C.MDB_txn)
2020-08-05 10:13:35 +00:00
}
2021-03-21 13:15:25 +00:00
type RwTx interface {
Tx
RwCursor ( bucket string ) RwCursor
RwCursorDupSort ( bucket string ) RwCursorDupSort
IncrementSequence ( bucket string , amount uint64 ) ( uint64 , error )
}
// BucketMigrator used for buckets migration, don't use it in usual app code
2020-08-05 10:13:35 +00:00
type BucketMigrator interface {
2020-08-14 06:41:18 +00:00
DropBucket ( string ) error
CreateBucket ( string ) error
ExistsBucket ( string ) bool
ClearBucket ( string ) error
ExistingBuckets ( ) ( [ ] string , error )
2020-03-24 02:12:55 +00:00
}
2020-09-05 07:26:24 +00:00
// Cursor - class for navigating through a database
2021-02-10 09:56:44 +00:00
// CursorDupSort are inherit this class
2020-09-05 07:26:24 +00:00
//
// If methods (like First/Next/Seek) return error, then returned key SHOULD not be nil (can be []byte{} for example).
// Then looping code will look as:
// c := kv.Cursor(bucketName)
// for k, v, err := c.First(); k != nil; k, v, err = c.Next() {
// if err != nil {
// return err
// }
// ... logic
// }
2020-03-24 02:12:55 +00:00
type Cursor interface {
2020-11-16 12:08:28 +00:00
First ( ) ( [ ] byte , [ ] byte , error ) // First - position at first key/data item
Seek ( seek [ ] byte ) ( [ ] byte , [ ] byte , error ) // Seek - position at first key greater than or equal to specified key
SeekExact ( key [ ] byte ) ( [ ] byte , [ ] byte , error ) // SeekExact - position at first key greater than or equal to specified key
Next ( ) ( [ ] byte , [ ] byte , error ) // Next - position at next key/value (can iterate over DupSort key/values automatically)
Prev ( ) ( [ ] byte , [ ] byte , error ) // Prev - position at previous key
Last ( ) ( [ ] byte , [ ] byte , error ) // Last - position at last key and last possible value
Current ( ) ( [ ] byte , [ ] byte , error ) // Current - return key/data at current cursor position
2020-09-05 07:26:24 +00:00
2021-03-21 13:15:25 +00:00
Count ( ) ( uint64 , error ) // Count - fast way to calculate amount of keys in bucket. It counts all keys even if Prefix was set.
Close ( )
}
type RwCursor interface {
Cursor
2020-09-05 07:26:24 +00:00
Put ( k , v [ ] byte ) error // Put - based on order
Append ( k [ ] byte , v [ ] byte ) error // Append - append the given key/data pair to the end of the database. This option allows fast bulk loading when keys are already known to be in the correct order.
2020-10-29 13:19:31 +00:00
Delete ( k , v [ ] byte ) error // Delete - short version of SeekExact+DeleteCurrent or SeekBothExact+DeleteCurrent
2020-09-05 07:26:24 +00:00
// DeleteCurrent This function deletes the key/data pair to which the cursor refers.
// This does not invalidate the cursor, so operations such as MDB_NEXT
// can still be used on it.
// Both MDB_NEXT and MDB_GET_CURRENT will return the same record after
// this operation.
DeleteCurrent ( ) error
2020-03-24 02:12:55 +00:00
}
2020-09-04 03:54:15 +00:00
type CursorDupSort interface {
Cursor
2020-09-10 12:35:58 +00:00
// SeekBothExact -
// second parameter can be nil only if searched key has no duplicates, or return error
2020-09-04 03:54:15 +00:00
SeekBothExact ( key , value [ ] byte ) ( [ ] byte , [ ] byte , error )
2021-03-19 07:45:01 +00:00
SeekBothRange ( key , value [ ] byte ) ( [ ] byte , error )
2020-09-05 07:26:24 +00:00
FirstDup ( ) ( [ ] byte , error ) // FirstDup - position at first data item of current key
NextDup ( ) ( [ ] byte , [ ] byte , error ) // NextDup - position at next data item of current key
NextNoDup ( ) ( [ ] byte , [ ] byte , error ) // NextNoDup - position at first data item of next key
2021-03-19 07:45:01 +00:00
LastDup ( ) ( [ ] byte , error ) // LastDup - position at last data item of current key
2020-09-04 03:54:15 +00:00
2021-03-21 13:15:25 +00:00
CountDuplicates ( ) ( uint64 , error ) // CountDuplicates - number of duplicates for the current key
}
type RwCursorDupSort interface {
CursorDupSort
RwCursor
2020-09-05 07:26:24 +00:00
DeleteCurrentDuplicates ( ) error // DeleteCurrentDuplicates - deletes all of the data items for the current key
AppendDup ( key , value [ ] byte ) error // AppendDup - same as Append, but for sorted dup data
2020-09-04 03:54:15 +00:00
}
2020-06-04 09:35:42 +00:00
type HasStats interface {
2020-07-29 04:31:46 +00:00
DiskSize ( context . Context ) ( uint64 , error ) // db size
2020-06-04 09:35:42 +00:00
}