mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 03:30:37 +00:00
move NewHashBatch to erigon-lib, remove oddb package (#8408)
This commit is contained in:
parent
afd88edea8
commit
62395c767e
@ -577,7 +577,7 @@ func generate6(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dropT(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
func dropT(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
||||||
if err := tx.(kv.BucketMigrator).ClearBucket("t"); err != nil {
|
if err := tx.ClearBucket("t"); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
@ -607,14 +607,14 @@ func generate7(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dropT1(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
func dropT1(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
||||||
if err := tx.(kv.BucketMigrator).ClearBucket("t1"); err != nil {
|
if err := tx.ClearBucket("t1"); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dropT2(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
func dropT2(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
||||||
if err := tx.(kv.BucketMigrator).ClearBucket("t2"); err != nil {
|
if err := tx.ClearBucket("t2"); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
@ -624,7 +624,7 @@ func dropT2(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
|||||||
func generate8(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
func generate8(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
k := fmt.Sprintf("table_%05d", i)
|
k := fmt.Sprintf("table_%05d", i)
|
||||||
if err := tx.(kv.BucketMigrator).CreateBucket(k); err != nil {
|
if err := tx.CreateBucket(k); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -656,7 +656,7 @@ func generate9(tx kv.RwTx, entries int) error {
|
|||||||
func dropAll(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
func dropAll(_ kv.RwDB, tx kv.RwTx) (bool, error) {
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
k := fmt.Sprintf("table_%05d", i)
|
k := fmt.Sprintf("table_%05d", i)
|
||||||
if err := tx.(kv.BucketMigrator).DropBucket(k); err != nil {
|
if err := tx.DropBucket(k); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"github.com/ledgerwatch/erigon/core/types/accounts"
|
"github.com/ledgerwatch/erigon/core/types/accounts"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ReadAccount(db kv.Tx, addr libcommon.Address, acc *accounts.Account) (bool, error) {
|
func ReadAccount(db kv.Getter, addr libcommon.Address, acc *accounts.Account) (bool, error) {
|
||||||
enc, err := db.GetOne(kv.PlainState, addr[:])
|
enc, err := db.GetOne(kv.PlainState, addr[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -303,8 +303,6 @@ type StatelessReadTx interface {
|
|||||||
// Sequence changes become visible outside the current write transaction after it is committed, and discarded on abort.
|
// Sequence changes become visible outside the current write transaction after it is committed, and discarded on abort.
|
||||||
// Starts from 0.
|
// Starts from 0.
|
||||||
ReadSequence(table string) (uint64, error)
|
ReadSequence(table string) (uint64, error)
|
||||||
|
|
||||||
BucketSize(table string) (uint64, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatelessWriteTx interface {
|
type StatelessWriteTx interface {
|
||||||
@ -340,6 +338,16 @@ type StatelessRwTx interface {
|
|||||||
StatelessWriteTx
|
StatelessWriteTx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PendingMutations in-memory storage of changes
|
||||||
|
// Later they can either be flushed to the database or abandon
|
||||||
|
type PendingMutations interface {
|
||||||
|
StatelessRwTx
|
||||||
|
// Flush all in-memory data into `tx`
|
||||||
|
Flush(ctx context.Context, tx RwTx) error
|
||||||
|
Close()
|
||||||
|
BatchSize() int
|
||||||
|
}
|
||||||
|
|
||||||
// Tx
|
// Tx
|
||||||
// WARNING:
|
// WARNING:
|
||||||
// - Tx is not threadsafe and may only be used in the goroutine that created it
|
// - Tx is not threadsafe and may only be used in the goroutine that created it
|
||||||
@ -397,6 +405,7 @@ type Tx interface {
|
|||||||
|
|
||||||
// Pointer to the underlying C transaction handle (e.g. *C.MDBX_txn)
|
// Pointer to the underlying C transaction handle (e.g. *C.MDBX_txn)
|
||||||
CHandle() unsafe.Pointer
|
CHandle() unsafe.Pointer
|
||||||
|
BucketSize(table string) (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RwTx
|
// RwTx
|
||||||
|
@ -37,10 +37,7 @@ func TestBucketCRUD(t *testing.T) {
|
|||||||
|
|
||||||
normalBucket := kv.ChaindataTables[15]
|
normalBucket := kv.ChaindataTables[15]
|
||||||
deprecatedBucket := kv.ChaindataDeprecatedTables[0]
|
deprecatedBucket := kv.ChaindataDeprecatedTables[0]
|
||||||
migrator, ok := tx.(kv.BucketMigrator)
|
migrator := tx
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// check thad buckets have unique DBI's
|
// check thad buckets have unique DBI's
|
||||||
uniquness := map[kv.DBI]bool{}
|
uniquness := map[kv.DBI]bool{}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//go:build !js
|
//go:build !js
|
||||||
|
|
||||||
package olddb
|
package membatch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -29,9 +29,6 @@ import (
|
|||||||
|
|
||||||
"github.com/ledgerwatch/erigon-lib/kv"
|
"github.com/ledgerwatch/erigon-lib/kv"
|
||||||
"github.com/ledgerwatch/erigon-lib/kv/memdb"
|
"github.com/ledgerwatch/erigon-lib/kv/memdb"
|
||||||
"github.com/ledgerwatch/erigon/common"
|
|
||||||
"github.com/ledgerwatch/erigon/ethdb"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -207,42 +204,3 @@ func TestParallelPutGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
pending.Wait()
|
pending.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
var hexEntries = map[string]string{
|
|
||||||
"6b": "89c6",
|
|
||||||
"91": "c476",
|
|
||||||
"a8": "0a514e",
|
|
||||||
"bb": "7a",
|
|
||||||
"bd": "fe76",
|
|
||||||
"c0": "12",
|
|
||||||
}
|
|
||||||
|
|
||||||
var startKey = common.FromHex("a0")
|
|
||||||
var fixedBits = 3
|
|
||||||
|
|
||||||
var keysInRange = [][]byte{common.FromHex("a8"), common.FromHex("bb"), common.FromHex("bd")}
|
|
||||||
|
|
||||||
func TestWalk(t *testing.T) {
|
|
||||||
_, tx := memdb.NewTestTx(t)
|
|
||||||
|
|
||||||
for k, v := range hexEntries {
|
|
||||||
err := tx.Put(testBucket, common.FromHex(k), common.FromHex(v))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("put failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var gotKeys [][]byte
|
|
||||||
c, err := tx.Cursor(testBucket)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer c.Close()
|
|
||||||
err = ethdb.Walk(c, startKey, fixedBits, func(key, val []byte) (bool, error) {
|
|
||||||
gotKeys = append(gotKeys, common.CopyBytes(key))
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, keysInRange, gotKeys)
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package olddb
|
package membatch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -11,13 +11,11 @@ import (
|
|||||||
"github.com/ledgerwatch/erigon-lib/etl"
|
"github.com/ledgerwatch/erigon-lib/etl"
|
||||||
"github.com/ledgerwatch/erigon-lib/kv"
|
"github.com/ledgerwatch/erigon-lib/kv"
|
||||||
"github.com/ledgerwatch/log/v3"
|
"github.com/ledgerwatch/log/v3"
|
||||||
|
|
||||||
"github.com/ledgerwatch/erigon/ethdb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type mapmutation struct {
|
type Mapmutation struct {
|
||||||
puts map[string]map[string][]byte // table -> key -> value ie. blocks -> hash -> blockBod
|
puts map[string]map[string][]byte // table -> key -> value ie. blocks -> hash -> blockBod
|
||||||
db kv.RwTx
|
db kv.Tx
|
||||||
quit <-chan struct{}
|
quit <-chan struct{}
|
||||||
clean func()
|
clean func()
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
@ -32,10 +30,10 @@ type mapmutation struct {
|
|||||||
// Common pattern:
|
// Common pattern:
|
||||||
//
|
//
|
||||||
// batch := db.NewBatch()
|
// batch := db.NewBatch()
|
||||||
// defer batch.Rollback()
|
// defer batch.Close()
|
||||||
// ... some calculations on `batch`
|
// ... some calculations on `batch`
|
||||||
// batch.Commit()
|
// batch.Commit()
|
||||||
func NewHashBatch(tx kv.RwTx, quit <-chan struct{}, tmpdir string, logger log.Logger) *mapmutation {
|
func NewHashBatch(tx kv.Tx, quit <-chan struct{}, tmpdir string, logger log.Logger) *Mapmutation {
|
||||||
clean := func() {}
|
clean := func() {}
|
||||||
if quit == nil {
|
if quit == nil {
|
||||||
ch := make(chan struct{})
|
ch := make(chan struct{})
|
||||||
@ -43,7 +41,7 @@ func NewHashBatch(tx kv.RwTx, quit <-chan struct{}, tmpdir string, logger log.Lo
|
|||||||
quit = ch
|
quit = ch
|
||||||
}
|
}
|
||||||
|
|
||||||
return &mapmutation{
|
return &Mapmutation{
|
||||||
db: tx,
|
db: tx,
|
||||||
puts: make(map[string]map[string][]byte),
|
puts: make(map[string]map[string][]byte),
|
||||||
quit: quit,
|
quit: quit,
|
||||||
@ -53,14 +51,7 @@ func NewHashBatch(tx kv.RwTx, quit <-chan struct{}, tmpdir string, logger log.Lo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) RwKV() kv.RwDB {
|
func (m *Mapmutation) getMem(table string, key []byte) ([]byte, bool) {
|
||||||
if casted, ok := m.db.(ethdb.HasRwKV); ok {
|
|
||||||
return casted.RwKV()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mapmutation) getMem(table string, key []byte) ([]byte, bool) {
|
|
||||||
m.mu.RLock()
|
m.mu.RLock()
|
||||||
defer m.mu.RUnlock()
|
defer m.mu.RUnlock()
|
||||||
if _, ok := m.puts[table]; !ok {
|
if _, ok := m.puts[table]; !ok {
|
||||||
@ -73,7 +64,7 @@ func (m *mapmutation) getMem(table string, key []byte) ([]byte, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) IncrementSequence(bucket string, amount uint64) (res uint64, err error) {
|
func (m *Mapmutation) IncrementSequence(bucket string, amount uint64) (res uint64, err error) {
|
||||||
v, ok := m.getMem(kv.Sequence, []byte(bucket))
|
v, ok := m.getMem(kv.Sequence, []byte(bucket))
|
||||||
if !ok && m.db != nil {
|
if !ok && m.db != nil {
|
||||||
v, err = m.db.GetOne(kv.Sequence, []byte(bucket))
|
v, err = m.db.GetOne(kv.Sequence, []byte(bucket))
|
||||||
@ -95,7 +86,7 @@ func (m *mapmutation) IncrementSequence(bucket string, amount uint64) (res uint6
|
|||||||
|
|
||||||
return currentV, nil
|
return currentV, nil
|
||||||
}
|
}
|
||||||
func (m *mapmutation) ReadSequence(bucket string) (res uint64, err error) {
|
func (m *Mapmutation) ReadSequence(bucket string) (res uint64, err error) {
|
||||||
v, ok := m.getMem(kv.Sequence, []byte(bucket))
|
v, ok := m.getMem(kv.Sequence, []byte(bucket))
|
||||||
if !ok && m.db != nil {
|
if !ok && m.db != nil {
|
||||||
v, err = m.db.GetOne(kv.Sequence, []byte(bucket))
|
v, err = m.db.GetOne(kv.Sequence, []byte(bucket))
|
||||||
@ -112,7 +103,7 @@ func (m *mapmutation) ReadSequence(bucket string) (res uint64, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Can only be called from the worker thread
|
// Can only be called from the worker thread
|
||||||
func (m *mapmutation) GetOne(table string, key []byte) ([]byte, error) {
|
func (m *Mapmutation) GetOne(table string, key []byte) ([]byte, error) {
|
||||||
if value, ok := m.getMem(table, key); ok {
|
if value, ok := m.getMem(table, key); ok {
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
@ -127,21 +118,7 @@ func (m *mapmutation) GetOne(table string, key []byte) ([]byte, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can only be called from the worker thread
|
func (m *Mapmutation) Last(table string) ([]byte, []byte, error) {
|
||||||
func (m *mapmutation) Get(table string, key []byte) ([]byte, error) {
|
|
||||||
value, err := m.GetOne(table, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if value == nil {
|
|
||||||
return nil, ethdb.ErrKeyNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mapmutation) Last(table string) ([]byte, []byte, error) {
|
|
||||||
c, err := m.db.Cursor(table)
|
c, err := m.db.Cursor(table)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -150,7 +127,7 @@ func (m *mapmutation) Last(table string) ([]byte, []byte, error) {
|
|||||||
return c.Last()
|
return c.Last()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) Has(table string, key []byte) (bool, error) {
|
func (m *Mapmutation) Has(table string, key []byte) (bool, error) {
|
||||||
if _, ok := m.getMem(table, key); ok {
|
if _, ok := m.getMem(table, key); ok {
|
||||||
return ok, nil
|
return ok, nil
|
||||||
}
|
}
|
||||||
@ -161,7 +138,7 @@ func (m *mapmutation) Has(table string, key []byte) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// puts a table key with a value and if the table is not found then it appends a table
|
// puts a table key with a value and if the table is not found then it appends a table
|
||||||
func (m *mapmutation) Put(table string, k, v []byte) error {
|
func (m *Mapmutation) Put(table string, k, v []byte) error {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
if _, ok := m.puts[table]; !ok {
|
if _, ok := m.puts[table]; !ok {
|
||||||
@ -183,40 +160,40 @@ func (m *mapmutation) Put(table string, k, v []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) Append(table string, key []byte, value []byte) error {
|
func (m *Mapmutation) Append(table string, key []byte, value []byte) error {
|
||||||
return m.Put(table, key, value)
|
return m.Put(table, key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) AppendDup(table string, key []byte, value []byte) error {
|
func (m *Mapmutation) AppendDup(table string, key []byte, value []byte) error {
|
||||||
return m.Put(table, key, value)
|
return m.Put(table, key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) BatchSize() int {
|
func (m *Mapmutation) BatchSize() int {
|
||||||
m.mu.RLock()
|
m.mu.RLock()
|
||||||
defer m.mu.RUnlock()
|
defer m.mu.RUnlock()
|
||||||
return m.size
|
return m.size
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) ForEach(bucket string, fromPrefix []byte, walker func(k, v []byte) error) error {
|
func (m *Mapmutation) ForEach(bucket string, fromPrefix []byte, walker func(k, v []byte) error) error {
|
||||||
m.panicOnEmptyDB()
|
m.panicOnEmptyDB()
|
||||||
return m.db.ForEach(bucket, fromPrefix, walker)
|
return m.db.ForEach(bucket, fromPrefix, walker)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) ForPrefix(bucket string, prefix []byte, walker func(k, v []byte) error) error {
|
func (m *Mapmutation) ForPrefix(bucket string, prefix []byte, walker func(k, v []byte) error) error {
|
||||||
m.panicOnEmptyDB()
|
m.panicOnEmptyDB()
|
||||||
return m.db.ForPrefix(bucket, prefix, walker)
|
return m.db.ForPrefix(bucket, prefix, walker)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) ForAmount(bucket string, prefix []byte, amount uint32, walker func(k, v []byte) error) error {
|
func (m *Mapmutation) ForAmount(bucket string, prefix []byte, amount uint32, walker func(k, v []byte) error) error {
|
||||||
m.panicOnEmptyDB()
|
m.panicOnEmptyDB()
|
||||||
return m.db.ForAmount(bucket, prefix, amount, walker)
|
return m.db.ForAmount(bucket, prefix, amount, walker)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) Delete(table string, k []byte) error {
|
func (m *Mapmutation) Delete(table string, k []byte) error {
|
||||||
return m.Put(table, k, nil)
|
return m.Put(table, k, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) doCommit(tx kv.RwTx) error {
|
func (m *Mapmutation) doCommit(tx kv.RwTx) error {
|
||||||
logEvery := time.NewTicker(30 * time.Second)
|
logEvery := time.NewTicker(30 * time.Second)
|
||||||
defer logEvery.Stop()
|
defer logEvery.Stop()
|
||||||
count := 0
|
count := 0
|
||||||
@ -235,7 +212,7 @@ func (m *mapmutation) doCommit(tx kv.RwTx) error {
|
|||||||
tx.CollectMetrics()
|
tx.CollectMetrics()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := collector.Load(m.db, table, etl.IdentityLoadFunc, etl.TransformArgs{Quit: m.quit}); err != nil {
|
if err := collector.Load(tx, table, etl.IdentityLoadFunc, etl.TransformArgs{Quit: m.quit}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,13 +221,13 @@ func (m *mapmutation) doCommit(tx kv.RwTx) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) Commit() error {
|
func (m *Mapmutation) Flush(ctx context.Context, tx kv.RwTx) error {
|
||||||
if m.db == nil {
|
if m.db == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
if err := m.doCommit(m.db); err != nil {
|
if err := m.doCommit(tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +238,7 @@ func (m *mapmutation) Commit() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) Rollback() {
|
func (m *Mapmutation) Close() {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
m.puts = map[string]map[string][]byte{}
|
m.puts = map[string]map[string][]byte{}
|
||||||
@ -270,25 +247,11 @@ func (m *mapmutation) Rollback() {
|
|||||||
m.size = 0
|
m.size = 0
|
||||||
m.clean()
|
m.clean()
|
||||||
}
|
}
|
||||||
|
func (m *Mapmutation) Commit() error { panic("not db txn, use .Flush method") }
|
||||||
|
func (m *Mapmutation) Rollback() { panic("not db txn, use .Close method") }
|
||||||
|
|
||||||
func (m *mapmutation) Close() {
|
func (m *Mapmutation) panicOnEmptyDB() {
|
||||||
m.Rollback()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mapmutation) Begin(ctx context.Context, flags ethdb.TxFlags) (ethdb.DbWithPendingMutations, error) {
|
|
||||||
panic("mutation can't start transaction, because doesn't own it")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mapmutation) panicOnEmptyDB() {
|
|
||||||
if m.db == nil {
|
if m.db == nil {
|
||||||
panic("Not implemented")
|
panic("Not implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mapmutation) SetRwKV(kv kv.RwDB) {
|
|
||||||
hasRwKV, ok := m.db.(ethdb.HasRwKV)
|
|
||||||
if !ok {
|
|
||||||
log.Warn("Failed to convert mapmutation type to HasRwKV interface")
|
|
||||||
}
|
|
||||||
hasRwKV.SetRwKV(kv)
|
|
||||||
}
|
|
@ -41,7 +41,7 @@ type MemoryMutation struct {
|
|||||||
// Common pattern:
|
// Common pattern:
|
||||||
//
|
//
|
||||||
// batch := NewMemoryBatch(db, tmpDir)
|
// batch := NewMemoryBatch(db, tmpDir)
|
||||||
// defer batch.Rollback()
|
// defer batch.Close()
|
||||||
// ... some calculations on `batch`
|
// ... some calculations on `batch`
|
||||||
// batch.Commit()
|
// batch.Commit()
|
||||||
func NewMemoryBatch(tx kv.Tx, tmpDir string) *MemoryMutation {
|
func NewMemoryBatch(tx kv.Tx, tmpDir string) *MemoryMutation {
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/c2h5oh/datasize"
|
"github.com/c2h5oh/datasize"
|
||||||
|
"github.com/ledgerwatch/erigon-lib/kv/membatch"
|
||||||
"github.com/ledgerwatch/log/v3"
|
"github.com/ledgerwatch/log/v3"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
@ -42,8 +43,6 @@ import (
|
|||||||
"github.com/ledgerwatch/erigon/eth/ethconfig/estimate"
|
"github.com/ledgerwatch/erigon/eth/ethconfig/estimate"
|
||||||
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
|
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
|
||||||
trace_logger "github.com/ledgerwatch/erigon/eth/tracers/logger"
|
trace_logger "github.com/ledgerwatch/erigon/eth/tracers/logger"
|
||||||
"github.com/ledgerwatch/erigon/ethdb"
|
|
||||||
"github.com/ledgerwatch/erigon/ethdb/olddb"
|
|
||||||
"github.com/ledgerwatch/erigon/ethdb/prune"
|
"github.com/ledgerwatch/erigon/ethdb/prune"
|
||||||
"github.com/ledgerwatch/erigon/turbo/services"
|
"github.com/ledgerwatch/erigon/turbo/services"
|
||||||
"github.com/ledgerwatch/erigon/turbo/shards"
|
"github.com/ledgerwatch/erigon/turbo/shards"
|
||||||
@ -140,7 +139,7 @@ func StageExecuteBlocksCfg(
|
|||||||
func executeBlock(
|
func executeBlock(
|
||||||
block *types.Block,
|
block *types.Block,
|
||||||
tx kv.RwTx,
|
tx kv.RwTx,
|
||||||
batch ethdb.Database,
|
batch kv.StatelessRwTx,
|
||||||
cfg ExecuteBlockCfg,
|
cfg ExecuteBlockCfg,
|
||||||
vmConfig vm.Config, // emit copy, because will modify it
|
vmConfig vm.Config, // emit copy, because will modify it
|
||||||
writeChangesets bool,
|
writeChangesets bool,
|
||||||
@ -206,7 +205,7 @@ func executeBlock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newStateReaderWriter(
|
func newStateReaderWriter(
|
||||||
batch ethdb.Database,
|
batch kv.StatelessRwTx,
|
||||||
tx kv.RwTx,
|
tx kv.RwTx,
|
||||||
block *types.Block,
|
block *types.Block,
|
||||||
writeChangesets bool,
|
writeChangesets bool,
|
||||||
@ -415,12 +414,12 @@ func SpawnExecuteBlocksStage(s *StageState, u Unwinder, tx kv.RwTx, toBlock uint
|
|||||||
|
|
||||||
var stoppedErr error
|
var stoppedErr error
|
||||||
|
|
||||||
var batch ethdb.DbWithPendingMutations
|
var batch kv.PendingMutations
|
||||||
// state is stored through ethdb batches
|
// state is stored through ethdb batches
|
||||||
batch = olddb.NewHashBatch(tx, quit, cfg.dirs.Tmp, logger)
|
batch = membatch.NewHashBatch(tx, quit, cfg.dirs.Tmp, logger)
|
||||||
// avoids stacking defers within the loop
|
// avoids stacking defers within the loop
|
||||||
defer func() {
|
defer func() {
|
||||||
batch.Rollback()
|
batch.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var readAhead chan uint64
|
var readAhead chan uint64
|
||||||
@ -508,7 +507,7 @@ Loop:
|
|||||||
if shouldUpdateProgress {
|
if shouldUpdateProgress {
|
||||||
logger.Info("Committed State", "gas reached", currentStateGas, "gasTarget", gasState)
|
logger.Info("Committed State", "gas reached", currentStateGas, "gasTarget", gasState)
|
||||||
currentStateGas = 0
|
currentStateGas = 0
|
||||||
if err = batch.Commit(); err != nil {
|
if err = batch.Flush(ctx, tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = s.Update(tx, stageProgress); err != nil {
|
if err = s.Update(tx, stageProgress); err != nil {
|
||||||
@ -525,7 +524,7 @@ Loop:
|
|||||||
// TODO: This creates stacked up deferrals
|
// TODO: This creates stacked up deferrals
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
}
|
}
|
||||||
batch = olddb.NewHashBatch(tx, quit, cfg.dirs.Tmp, logger)
|
batch = membatch.NewHashBatch(tx, quit, cfg.dirs.Tmp, logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
gas = gas + block.GasUsed()
|
gas = gas + block.GasUsed()
|
||||||
@ -543,7 +542,7 @@ Loop:
|
|||||||
if err = s.Update(batch, stageProgress); err != nil {
|
if err = s.Update(batch, stageProgress); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = batch.Commit(); err != nil {
|
if err = batch.Flush(ctx, tx); err != nil {
|
||||||
return fmt.Errorf("batch commit: %w", err)
|
return fmt.Errorf("batch commit: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,7 +646,7 @@ func blocksReadAheadFunc(ctx context.Context, tx kv.Tx, cfg *ExecuteBlockCfg, bl
|
|||||||
}
|
}
|
||||||
|
|
||||||
func logProgress(logPrefix string, prevBlock uint64, prevTime time.Time, currentBlock uint64, prevTx, currentTx uint64, gas uint64,
|
func logProgress(logPrefix string, prevBlock uint64, prevTime time.Time, currentBlock uint64, prevTx, currentTx uint64, gas uint64,
|
||||||
gasState float64, batch ethdb.DbWithPendingMutations, logger log.Logger) (uint64, uint64, time.Time) {
|
gasState float64, batch kv.PendingMutations, logger log.Logger) (uint64, uint64, time.Time) {
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
interval := currentTime.Sub(prevTime)
|
interval := currentTime.Sub(prevTime)
|
||||||
speed := float64(currentBlock-prevBlock) / (float64(interval) / float64(time.Second))
|
speed := float64(currentBlock-prevBlock) / (float64(interval) / float64(time.Second))
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
mapset "github.com/deckarep/golang-set/v2"
|
mapset "github.com/deckarep/golang-set/v2"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
"github.com/ledgerwatch/erigon-lib/kv/membatch"
|
||||||
"github.com/ledgerwatch/log/v3"
|
"github.com/ledgerwatch/log/v3"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
@ -17,7 +18,6 @@ import (
|
|||||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||||
"github.com/ledgerwatch/erigon-lib/common/fixedgas"
|
"github.com/ledgerwatch/erigon-lib/common/fixedgas"
|
||||||
"github.com/ledgerwatch/erigon-lib/kv"
|
"github.com/ledgerwatch/erigon-lib/kv"
|
||||||
"github.com/ledgerwatch/erigon-lib/kv/memdb"
|
|
||||||
types2 "github.com/ledgerwatch/erigon-lib/types"
|
types2 "github.com/ledgerwatch/erigon-lib/types"
|
||||||
|
|
||||||
"github.com/ledgerwatch/erigon/consensus"
|
"github.com/ledgerwatch/erigon/consensus"
|
||||||
@ -115,8 +115,11 @@ func SpawnMiningExecStage(s *StageState, tx kv.RwTx, cfg MiningExecCfg, quit <-c
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
yielded := mapset.NewSet[[32]byte]()
|
yielded := mapset.NewSet[[32]byte]()
|
||||||
simulationTx := memdb.NewMemoryBatch(tx, cfg.tmpdir)
|
var simulationTx kv.StatelessRwTx
|
||||||
defer simulationTx.Rollback()
|
m := membatch.NewHashBatch(tx, quit, cfg.tmpdir, logger)
|
||||||
|
defer m.Close()
|
||||||
|
simulationTx = m
|
||||||
|
|
||||||
executionAt, err := s.ExecutionAt(tx)
|
executionAt, err := s.ExecutionAt(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -180,7 +183,7 @@ func getNextTransactions(
|
|||||||
header *types.Header,
|
header *types.Header,
|
||||||
amount uint16,
|
amount uint16,
|
||||||
executionAt uint64,
|
executionAt uint64,
|
||||||
simulationTx *memdb.MemoryMutation,
|
simulationTx kv.StatelessRwTx,
|
||||||
alreadyYielded mapset.Set[[32]byte],
|
alreadyYielded mapset.Set[[32]byte],
|
||||||
logger log.Logger,
|
logger log.Logger,
|
||||||
) (types.TransactionsStream, int, error) {
|
) (types.TransactionsStream, int, error) {
|
||||||
@ -237,7 +240,7 @@ func getNextTransactions(
|
|||||||
return types.NewTransactionsFixedOrder(txs), count, nil
|
return types.NewTransactionsFixedOrder(txs), count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterBadTransactions(transactions []types.Transaction, config chain.Config, blockNumber uint64, baseFee *big.Int, simulationTx *memdb.MemoryMutation, logger log.Logger) ([]types.Transaction, error) {
|
func filterBadTransactions(transactions []types.Transaction, config chain.Config, blockNumber uint64, baseFee *big.Int, simulationTx kv.StatelessRwTx, logger log.Logger) ([]types.Transaction, error) {
|
||||||
initialCnt := len(transactions)
|
initialCnt := len(transactions)
|
||||||
var filtered []types.Transaction
|
var filtered []types.Transaction
|
||||||
gasBailout := false
|
gasBailout := false
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package ethdb
|
package ethdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/ledgerwatch/erigon-lib/kv"
|
"github.com/ledgerwatch/erigon-lib/kv"
|
||||||
@ -28,85 +27,6 @@ import (
|
|||||||
// ErrKeyNotFound is returned when key isn't found in the database.
|
// ErrKeyNotFound is returned when key isn't found in the database.
|
||||||
var ErrKeyNotFound = errors.New("db: key not found")
|
var ErrKeyNotFound = errors.New("db: key not found")
|
||||||
|
|
||||||
type TxFlags uint
|
|
||||||
|
|
||||||
const (
|
|
||||||
RW TxFlags = 0x00 // default
|
|
||||||
RO TxFlags = 0x02
|
|
||||||
)
|
|
||||||
|
|
||||||
// DBGetter wraps the database read operations.
|
|
||||||
type DBGetter interface {
|
|
||||||
kv.Getter
|
|
||||||
|
|
||||||
// Get returns the value for a given key if it's present.
|
|
||||||
Get(bucket string, key []byte) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Database wraps all database operations. All methods are safe for concurrent use.
|
|
||||||
type Database interface {
|
|
||||||
DBGetter
|
|
||||||
kv.Putter
|
|
||||||
kv.Deleter
|
|
||||||
kv.Closer
|
|
||||||
|
|
||||||
Begin(ctx context.Context, flags TxFlags) (DbWithPendingMutations, error) // starts db transaction
|
|
||||||
Last(bucket string) ([]byte, []byte, error)
|
|
||||||
|
|
||||||
IncrementSequence(bucket string, amount uint64) (uint64, error)
|
|
||||||
ReadSequence(bucket string) (uint64, error)
|
|
||||||
RwKV() kv.RwDB
|
|
||||||
}
|
|
||||||
|
|
||||||
// MinDatabase is a minimalistic version of the Database interface.
|
|
||||||
type MinDatabase interface {
|
|
||||||
Get(bucket string, key []byte) ([]byte, error)
|
|
||||||
Put(table string, k, v []byte) error
|
|
||||||
Delete(table string, k []byte) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// DbWithPendingMutations is an extended version of the Database,
|
|
||||||
// where all changes are first made in memory.
|
|
||||||
// Later they can either be committed to the database or rolled back.
|
|
||||||
type DbWithPendingMutations interface {
|
|
||||||
Database
|
|
||||||
|
|
||||||
// Commit - commits transaction (or flush data into underlying db object in case of `mutation`)
|
|
||||||
//
|
|
||||||
// Common pattern:
|
|
||||||
//
|
|
||||||
// tx := db.Begin()
|
|
||||||
// defer tx.Rollback()
|
|
||||||
// ... some calculations on `tx`
|
|
||||||
// tx.Commit()
|
|
||||||
//
|
|
||||||
Commit() error
|
|
||||||
|
|
||||||
Rollback()
|
|
||||||
BatchSize() int
|
|
||||||
}
|
|
||||||
|
|
||||||
type HasRwKV interface {
|
|
||||||
RwKV() kv.RwDB
|
|
||||||
SetRwKV(kv kv.RwDB)
|
|
||||||
}
|
|
||||||
|
|
||||||
type HasTx interface {
|
type HasTx interface {
|
||||||
Tx() kv.Tx
|
Tx() kv.Tx
|
||||||
}
|
}
|
||||||
|
|
||||||
type BucketsMigrator interface {
|
|
||||||
BucketExists(bucket string) (bool, error) // makes them empty
|
|
||||||
ClearBuckets(buckets ...string) error // makes them empty
|
|
||||||
DropBuckets(buckets ...string) error // drops them, use of them after drop will panic
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetOneWrapper(dat []byte, err error) ([]byte, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if dat == nil {
|
|
||||||
return nil, ErrKeyNotFound
|
|
||||||
}
|
|
||||||
return dat, nil
|
|
||||||
}
|
|
||||||
|
@ -1,345 +0,0 @@
|
|||||||
package olddb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/google/btree"
|
|
||||||
"github.com/ledgerwatch/erigon-lib/common"
|
|
||||||
"github.com/ledgerwatch/erigon-lib/kv"
|
|
||||||
"github.com/ledgerwatch/erigon/ethdb"
|
|
||||||
"github.com/ledgerwatch/log/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mutation struct {
|
|
||||||
puts *btree.BTree
|
|
||||||
db kv.RwTx
|
|
||||||
quit <-chan struct{}
|
|
||||||
clean func()
|
|
||||||
searchItem MutationItem
|
|
||||||
mu sync.RWMutex
|
|
||||||
size int
|
|
||||||
}
|
|
||||||
|
|
||||||
type MutationItem struct {
|
|
||||||
table string
|
|
||||||
key []byte
|
|
||||||
value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBatch - starts in-mem batch
|
|
||||||
//
|
|
||||||
// Common pattern:
|
|
||||||
//
|
|
||||||
// batch := db.NewBatch()
|
|
||||||
// defer batch.Rollback()
|
|
||||||
// ... some calculations on `batch`
|
|
||||||
// batch.Commit()
|
|
||||||
func NewBatch(tx kv.RwTx, quit <-chan struct{}) *mutation {
|
|
||||||
clean := func() {}
|
|
||||||
if quit == nil {
|
|
||||||
ch := make(chan struct{})
|
|
||||||
clean = func() { close(ch) }
|
|
||||||
quit = ch
|
|
||||||
}
|
|
||||||
return &mutation{
|
|
||||||
db: tx,
|
|
||||||
puts: btree.New(32),
|
|
||||||
quit: quit,
|
|
||||||
clean: clean,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mi *MutationItem) Less(than btree.Item) bool {
|
|
||||||
i, ok := than.(*MutationItem)
|
|
||||||
if !ok {
|
|
||||||
log.Warn("Failed to convert btree.Item to MutationItem pointer")
|
|
||||||
}
|
|
||||||
c := strings.Compare(mi.table, i.table)
|
|
||||||
if c != 0 {
|
|
||||||
return c < 0
|
|
||||||
}
|
|
||||||
return bytes.Compare(mi.key, i.key) < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) ReadOnly() bool { return false }
|
|
||||||
func (m *mutation) RwKV() kv.RwDB {
|
|
||||||
if casted, ok := m.db.(ethdb.HasRwKV); ok {
|
|
||||||
return casted.RwKV()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) getMem(table string, key []byte) ([]byte, bool) {
|
|
||||||
m.mu.RLock()
|
|
||||||
defer m.mu.RUnlock()
|
|
||||||
m.searchItem.table = table
|
|
||||||
m.searchItem.key = key
|
|
||||||
i := m.puts.Get(&m.searchItem)
|
|
||||||
if i == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
return i.(*MutationItem).value, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) IncrementSequence(bucket string, amount uint64) (res uint64, err error) {
|
|
||||||
v, ok := m.getMem(kv.Sequence, []byte(bucket))
|
|
||||||
if !ok && m.db != nil {
|
|
||||||
v, err = m.db.GetOne(kv.Sequence, []byte(bucket))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentV uint64 = 0
|
|
||||||
if len(v) > 0 {
|
|
||||||
currentV = binary.BigEndian.Uint64(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
newVBytes := make([]byte, 8)
|
|
||||||
binary.BigEndian.PutUint64(newVBytes, currentV+amount)
|
|
||||||
if err = m.Put(kv.Sequence, []byte(bucket), newVBytes); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentV, nil
|
|
||||||
}
|
|
||||||
func (m *mutation) ReadSequence(bucket string) (res uint64, err error) {
|
|
||||||
v, ok := m.getMem(kv.Sequence, []byte(bucket))
|
|
||||||
if !ok && m.db != nil {
|
|
||||||
v, err = m.db.GetOne(kv.Sequence, []byte(bucket))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var currentV uint64 = 0
|
|
||||||
if len(v) > 0 {
|
|
||||||
currentV = binary.BigEndian.Uint64(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentV, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can only be called from the worker thread
|
|
||||||
func (m *mutation) GetOne(table string, key []byte) ([]byte, error) {
|
|
||||||
if value, ok := m.getMem(table, key); ok {
|
|
||||||
if value == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
if m.db != nil {
|
|
||||||
// TODO: simplify when tx can no longer be parent of mutation
|
|
||||||
value, err := m.db.GetOne(table, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can only be called from the worker thread
|
|
||||||
func (m *mutation) Get(table string, key []byte) ([]byte, error) {
|
|
||||||
value, err := m.GetOne(table, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if value == nil {
|
|
||||||
return nil, ethdb.ErrKeyNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Last(table string) ([]byte, []byte, error) {
|
|
||||||
c, err := m.db.Cursor(table)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
defer c.Close()
|
|
||||||
return c.Last()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) hasMem(table string, key []byte) bool {
|
|
||||||
m.mu.RLock()
|
|
||||||
defer m.mu.RUnlock()
|
|
||||||
m.searchItem.table = table
|
|
||||||
m.searchItem.key = key
|
|
||||||
return m.puts.Has(&m.searchItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Has(table string, key []byte) (bool, error) {
|
|
||||||
if m.hasMem(table, key) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if m.db != nil {
|
|
||||||
return m.db.Has(table, key)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Put(table string, k, v []byte) error {
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
|
|
||||||
newMi := &MutationItem{table: table, key: k, value: v}
|
|
||||||
i := m.puts.ReplaceOrInsert(newMi)
|
|
||||||
m.size += int(unsafe.Sizeof(newMi)) + len(k) + len(v)
|
|
||||||
if i != nil {
|
|
||||||
oldMi := i.(*MutationItem)
|
|
||||||
m.size -= int(unsafe.Sizeof(oldMi)) + len(oldMi.key) + len(oldMi.value)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Append(table string, key []byte, value []byte) error {
|
|
||||||
return m.Put(table, key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) AppendDup(table string, key []byte, value []byte) error {
|
|
||||||
return m.Put(table, key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) BatchSize() int {
|
|
||||||
m.mu.RLock()
|
|
||||||
defer m.mu.RUnlock()
|
|
||||||
return m.size
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) ForEach(bucket string, fromPrefix []byte, walker func(k, v []byte) error) error {
|
|
||||||
m.panicOnEmptyDB()
|
|
||||||
return m.db.ForEach(bucket, fromPrefix, walker)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) ForPrefix(bucket string, prefix []byte, walker func(k, v []byte) error) error {
|
|
||||||
m.panicOnEmptyDB()
|
|
||||||
return m.db.ForPrefix(bucket, prefix, walker)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) ForAmount(bucket string, prefix []byte, amount uint32, walker func(k, v []byte) error) error {
|
|
||||||
m.panicOnEmptyDB()
|
|
||||||
return m.db.ForAmount(bucket, prefix, amount, walker)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Delete(table string, k []byte) error {
|
|
||||||
//m.puts.Delete(table, k)
|
|
||||||
return m.Put(table, k, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) doCommit(tx kv.RwTx) error {
|
|
||||||
var prevTable string
|
|
||||||
var c kv.RwCursor
|
|
||||||
var innerErr error
|
|
||||||
var isEndOfBucket bool
|
|
||||||
logEvery := time.NewTicker(30 * time.Second)
|
|
||||||
defer logEvery.Stop()
|
|
||||||
count := 0
|
|
||||||
total := float64(m.puts.Len())
|
|
||||||
|
|
||||||
m.puts.Ascend(func(i btree.Item) bool {
|
|
||||||
mi := i.(*MutationItem)
|
|
||||||
if mi.table != prevTable {
|
|
||||||
if c != nil {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
c, err = tx.RwCursor(mi.table)
|
|
||||||
if err != nil {
|
|
||||||
innerErr = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
prevTable = mi.table
|
|
||||||
firstKey, _, err := c.Seek(mi.key)
|
|
||||||
if err != nil {
|
|
||||||
innerErr = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
isEndOfBucket = firstKey == nil
|
|
||||||
}
|
|
||||||
if isEndOfBucket {
|
|
||||||
if len(mi.value) > 0 {
|
|
||||||
if err := c.Append(mi.key, mi.value); err != nil {
|
|
||||||
innerErr = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if len(mi.value) == 0 {
|
|
||||||
if err := c.Delete(mi.key); err != nil {
|
|
||||||
innerErr = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := c.Put(mi.key, mi.value); err != nil {
|
|
||||||
innerErr = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count++
|
|
||||||
|
|
||||||
select {
|
|
||||||
default:
|
|
||||||
case <-logEvery.C:
|
|
||||||
progress := fmt.Sprintf("%.1fM/%.1fM", float64(count)/1_000_000, total/1_000_000)
|
|
||||||
log.Info("Write to db", "progress", progress, "current table", mi.table)
|
|
||||||
tx.CollectMetrics()
|
|
||||||
case <-m.quit:
|
|
||||||
innerErr = common.ErrStopped
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
tx.CollectMetrics()
|
|
||||||
return innerErr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Commit() error {
|
|
||||||
if m.db == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
if err := m.doCommit(m.db); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.puts.Clear(false /* addNodesToFreelist */)
|
|
||||||
m.size = 0
|
|
||||||
m.clean()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Rollback() {
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
m.puts.Clear(false /* addNodesToFreelist */)
|
|
||||||
m.size = 0
|
|
||||||
m.clean()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Close() {
|
|
||||||
m.Rollback()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) Begin(ctx context.Context, flags ethdb.TxFlags) (ethdb.DbWithPendingMutations, error) {
|
|
||||||
panic("mutation can't start transaction, because doesn't own it")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) panicOnEmptyDB() {
|
|
||||||
if m.db == nil {
|
|
||||||
panic("Not implemented")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mutation) SetRwKV(kv kv.RwDB) {
|
|
||||||
m.db.(ethdb.HasRwKV).SetRwKV(kv)
|
|
||||||
}
|
|
@ -1,248 +0,0 @@
|
|||||||
// Copyright 2014 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Package ethdb defines the interfaces for an Ethereum data store.
|
|
||||||
package olddb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ledgerwatch/erigon-lib/kv"
|
|
||||||
"github.com/ledgerwatch/erigon/common"
|
|
||||||
"github.com/ledgerwatch/erigon/ethdb"
|
|
||||||
"github.com/ledgerwatch/log/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ObjectDatabase - is an object-style interface of DB accessing
|
|
||||||
type ObjectDatabase struct {
|
|
||||||
kv kv.RwDB
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewObjectDatabase returns a AbstractDB wrapper.
|
|
||||||
// Deprecated
|
|
||||||
func NewObjectDatabase(kv kv.RwDB) *ObjectDatabase {
|
|
||||||
return &ObjectDatabase{
|
|
||||||
kv: kv,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put inserts or updates a single entry.
|
|
||||||
func (db *ObjectDatabase) Put(table string, k, v []byte) error {
|
|
||||||
err := db.kv.Update(context.Background(), func(tx kv.RwTx) error {
|
|
||||||
return tx.Put(table, k, v)
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append appends a single entry to the end of the bucket.
|
|
||||||
func (db *ObjectDatabase) Append(bucket string, key []byte, value []byte) error {
|
|
||||||
err := db.kv.Update(context.Background(), func(tx kv.RwTx) error {
|
|
||||||
c, err := tx.RwCursor(bucket)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Append(key, value)
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendDup appends a single entry to the end of the bucket.
|
|
||||||
func (db *ObjectDatabase) AppendDup(bucket string, key []byte, value []byte) error {
|
|
||||||
err := db.kv.Update(context.Background(), func(tx kv.RwTx) error {
|
|
||||||
c, err := tx.RwCursorDupSort(bucket)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.AppendDup(key, value)
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) Has(bucket string, key []byte) (bool, error) {
|
|
||||||
var has bool
|
|
||||||
err := db.kv.View(context.Background(), func(tx kv.Tx) error {
|
|
||||||
v, err := tx.GetOne(bucket, key)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
has = v != nil
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return has, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) IncrementSequence(bucket string, amount uint64) (res uint64, err error) {
|
|
||||||
err = db.kv.Update(context.Background(), func(tx kv.RwTx) error {
|
|
||||||
res, err = tx.IncrementSequence(bucket, amount)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
func (db *ObjectDatabase) ReadSequence(bucket string) (res uint64, err error) {
|
|
||||||
err = db.kv.View(context.Background(), func(tx kv.Tx) error {
|
|
||||||
res, err = tx.ReadSequence(bucket)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the value for a given key if it's present.
|
|
||||||
func (db *ObjectDatabase) GetOne(bucket string, key []byte) ([]byte, error) {
|
|
||||||
var dat []byte
|
|
||||||
err := db.kv.View(context.Background(), func(tx kv.Tx) error {
|
|
||||||
v, err := tx.GetOne(bucket, key)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if v != nil {
|
|
||||||
dat = make([]byte, len(v))
|
|
||||||
copy(dat, v)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return dat, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) Get(bucket string, key []byte) ([]byte, error) {
|
|
||||||
dat, err := db.GetOne(bucket, key)
|
|
||||||
return ethdb.GetOneWrapper(dat, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) Last(bucket string) ([]byte, []byte, error) {
|
|
||||||
var key, value []byte
|
|
||||||
if err := db.kv.View(context.Background(), func(tx kv.Tx) error {
|
|
||||||
c, err := tx.Cursor(bucket)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
k, v, err := c.Last()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if k != nil {
|
|
||||||
key, value = common.CopyBytes(k), common.CopyBytes(v)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return key, value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) ForEach(bucket string, fromPrefix []byte, walker func(k, v []byte) error) error {
|
|
||||||
return db.kv.View(context.Background(), func(tx kv.Tx) error {
|
|
||||||
return tx.ForEach(bucket, fromPrefix, walker)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
func (db *ObjectDatabase) ForAmount(bucket string, fromPrefix []byte, amount uint32, walker func(k, v []byte) error) error {
|
|
||||||
return db.kv.View(context.Background(), func(tx kv.Tx) error {
|
|
||||||
return tx.ForAmount(bucket, fromPrefix, amount, walker)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) ForPrefix(bucket string, prefix []byte, walker func(k, v []byte) error) error {
|
|
||||||
return db.kv.View(context.Background(), func(tx kv.Tx) error {
|
|
||||||
return tx.ForPrefix(bucket, prefix, walker)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete deletes the key from the queue and database
|
|
||||||
func (db *ObjectDatabase) Delete(table string, k []byte) error {
|
|
||||||
// Execute the actual operation
|
|
||||||
err := db.kv.Update(context.Background(), func(tx kv.RwTx) error {
|
|
||||||
return tx.Delete(table, k)
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) BucketExists(name string) (bool, error) {
|
|
||||||
exists := false
|
|
||||||
if err := db.kv.View(context.Background(), func(tx kv.Tx) (err error) {
|
|
||||||
migrator, ok := tx.(kv.BucketMigrator)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", db.kv)
|
|
||||||
}
|
|
||||||
exists, err = migrator.ExistsBucket(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return exists, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) ClearBuckets(buckets ...string) error {
|
|
||||||
for i := range buckets {
|
|
||||||
name := buckets[i]
|
|
||||||
if err := db.kv.Update(context.Background(), func(tx kv.RwTx) error {
|
|
||||||
migrator, ok := tx.(kv.BucketMigrator)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", db.kv)
|
|
||||||
}
|
|
||||||
if err := migrator.ClearBucket(name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) DropBuckets(buckets ...string) error {
|
|
||||||
for i := range buckets {
|
|
||||||
name := buckets[i]
|
|
||||||
log.Info("Dropping bucket", "name", name)
|
|
||||||
if err := db.kv.Update(context.Background(), func(tx kv.RwTx) error {
|
|
||||||
migrator, ok := tx.(kv.BucketMigrator)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", db.kv)
|
|
||||||
}
|
|
||||||
if err := migrator.DropBucket(name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) Close() {
|
|
||||||
db.kv.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) RwKV() kv.RwDB {
|
|
||||||
return db.kv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) SetRwKV(kv kv.RwDB) {
|
|
||||||
db.kv = kv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ObjectDatabase) Begin(ctx context.Context, flags ethdb.TxFlags) (ethdb.DbWithPendingMutations, error) {
|
|
||||||
batch := &TxDb{db: db}
|
|
||||||
if err := batch.begin(ctx, flags); err != nil {
|
|
||||||
return batch, err
|
|
||||||
}
|
|
||||||
return batch, nil
|
|
||||||
}
|
|
@ -1,238 +0,0 @@
|
|||||||
package olddb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ledgerwatch/erigon-lib/kv"
|
|
||||||
"github.com/ledgerwatch/erigon/ethdb"
|
|
||||||
"github.com/ledgerwatch/log/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TxDb - provides Database interface around ethdb.Tx
|
|
||||||
// It's not thread-safe!
|
|
||||||
// TxDb not usable after .Commit()/.Rollback() call, but usable after .CommitAndBegin() call
|
|
||||||
// you can put unlimited amount of data into this class
|
|
||||||
// Walk and MultiWalk methods - work outside of Tx object yet, will implement it later
|
|
||||||
// Deprecated
|
|
||||||
// nolint
|
|
||||||
type TxDb struct {
|
|
||||||
db ethdb.Database
|
|
||||||
tx kv.Tx
|
|
||||||
cursors map[string]kv.Cursor
|
|
||||||
txFlags ethdb.TxFlags
|
|
||||||
len uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// nolint
|
|
||||||
func WrapIntoTxDB(tx kv.RwTx) *TxDb {
|
|
||||||
return &TxDb{tx: tx, cursors: map[string]kv.Cursor{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Close() {
|
|
||||||
panic("don't call me")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Begin(ctx context.Context, flags ethdb.TxFlags) (ethdb.DbWithPendingMutations, error) {
|
|
||||||
batch := m
|
|
||||||
if m.tx != nil {
|
|
||||||
panic("nested transactions not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := batch.begin(ctx, flags); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return batch, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) cursor(bucket string) (kv.Cursor, error) {
|
|
||||||
c, ok := m.cursors[bucket]
|
|
||||||
if !ok {
|
|
||||||
var err error
|
|
||||||
c, err = m.tx.Cursor(bucket)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
m.cursors[bucket] = c
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) IncrementSequence(bucket string, amount uint64) (res uint64, err error) {
|
|
||||||
return m.tx.(kv.RwTx).IncrementSequence(bucket, amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) ReadSequence(bucket string) (res uint64, err error) {
|
|
||||||
return m.tx.ReadSequence(bucket)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Put(table string, k, v []byte) error {
|
|
||||||
m.len += uint64(len(k) + len(v))
|
|
||||||
c, err := m.cursor(table)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.(kv.RwCursor).Put(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Append(bucket string, key []byte, value []byte) error {
|
|
||||||
m.len += uint64(len(key) + len(value))
|
|
||||||
c, err := m.cursor(bucket)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.(kv.RwCursor).Append(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) AppendDup(bucket string, key []byte, value []byte) error {
|
|
||||||
m.len += uint64(len(key) + len(value))
|
|
||||||
c, err := m.cursor(bucket)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.(kv.RwCursorDupSort).AppendDup(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Delete(table string, k []byte) error {
|
|
||||||
m.len += uint64(len(k))
|
|
||||||
c, err := m.cursor(table)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.(kv.RwCursor).Delete(k)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) begin(ctx context.Context, flags ethdb.TxFlags) error {
|
|
||||||
db := m.db.(ethdb.HasRwKV).RwKV()
|
|
||||||
|
|
||||||
var tx kv.Tx
|
|
||||||
var err error
|
|
||||||
if flagsðdb.RO != 0 {
|
|
||||||
tx, err = db.BeginRo(ctx)
|
|
||||||
} else {
|
|
||||||
tx, err = db.BeginRw(ctx)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.tx = tx
|
|
||||||
m.cursors = make(map[string]kv.Cursor, 16)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) RwKV() kv.RwDB {
|
|
||||||
panic("not allowed to get KV interface because you will loose transaction, please use .Tx() method")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Last can only be called from the transaction thread
|
|
||||||
func (m *TxDb) Last(bucket string) ([]byte, []byte, error) {
|
|
||||||
c, err := m.cursor(bucket)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, nil, err
|
|
||||||
}
|
|
||||||
return c.Last()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) GetOne(bucket string, key []byte) ([]byte, error) {
|
|
||||||
c, err := m.cursor(bucket)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, v, err := c.SeekExact(key)
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Get(bucket string, key []byte) ([]byte, error) {
|
|
||||||
dat, err := m.GetOne(bucket, key)
|
|
||||||
return ethdb.GetOneWrapper(dat, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Has(bucket string, key []byte) (bool, error) {
|
|
||||||
v, err := m.Get(bucket, key)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return v != nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) BatchSize() int {
|
|
||||||
return int(m.len)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) ForEach(bucket string, fromPrefix []byte, walker func(k, v []byte) error) error {
|
|
||||||
return m.tx.ForEach(bucket, fromPrefix, walker)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) ForPrefix(bucket string, prefix []byte, walker func(k, v []byte) error) error {
|
|
||||||
return m.tx.ForPrefix(bucket, prefix, walker)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) ForAmount(bucket string, prefix []byte, amount uint32, walker func(k, v []byte) error) error {
|
|
||||||
return m.tx.ForAmount(bucket, prefix, amount, walker)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Commit() error {
|
|
||||||
if m.tx == nil {
|
|
||||||
return fmt.Errorf("second call .Commit() on same transaction")
|
|
||||||
}
|
|
||||||
if err := m.tx.Commit(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.tx = nil
|
|
||||||
m.cursors = nil
|
|
||||||
m.len = 0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Rollback() {
|
|
||||||
if m.tx == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.tx.Rollback()
|
|
||||||
m.cursors = nil
|
|
||||||
m.tx = nil
|
|
||||||
m.len = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) Tx() kv.Tx {
|
|
||||||
return m.tx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) BucketExists(name string) (bool, error) {
|
|
||||||
migrator, ok := m.tx.(kv.BucketMigrator)
|
|
||||||
if !ok {
|
|
||||||
return false, fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", m.tx)
|
|
||||||
}
|
|
||||||
return migrator.ExistsBucket(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) ClearBuckets(buckets ...string) error {
|
|
||||||
for i := range buckets {
|
|
||||||
name := buckets[i]
|
|
||||||
|
|
||||||
migrator, ok := m.tx.(kv.BucketMigrator)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", m.tx)
|
|
||||||
}
|
|
||||||
if err := migrator.ClearBucket(name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TxDb) DropBuckets(buckets ...string) error {
|
|
||||||
for i := range buckets {
|
|
||||||
name := buckets[i]
|
|
||||||
log.Info("Dropping bucket", "name", name)
|
|
||||||
migrator, ok := m.tx.(kv.BucketMigrator)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", m.tx)
|
|
||||||
}
|
|
||||||
if err := migrator.DropBucket(name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user