2021-07-28 02:47:38 +00:00
|
|
|
package olddb
|
2020-08-17 06:45:52 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
2021-07-29 11:53:13 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
2021-06-19 08:21:53 +00:00
|
|
|
"github.com/ledgerwatch/erigon/ethdb"
|
2021-07-29 10:23:23 +00:00
|
|
|
"github.com/ledgerwatch/log/v3"
|
2020-08-17 06:45:52 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// TxDb - provides Database interface around ethdb.Tx
|
|
|
|
// It's not thread-safe!
|
2020-08-24 11:07:59 +00:00
|
|
|
// TxDb not usable after .Commit()/.Rollback() call, but usable after .CommitAndBegin() call
|
2021-03-22 06:47:01 +00:00
|
|
|
// you can put unlimited amount of data into this class
|
2020-08-17 06:45:52 +00:00
|
|
|
// Walk and MultiWalk methods - work outside of Tx object yet, will implement it later
|
2022-08-10 12:04:13 +00:00
|
|
|
// Deprecated
|
|
|
|
// nolint
|
2020-08-17 06:45:52 +00:00
|
|
|
type TxDb struct {
|
2021-06-19 08:21:53 +00:00
|
|
|
db ethdb.Database
|
2021-07-28 02:47:38 +00:00
|
|
|
tx kv.Tx
|
|
|
|
cursors map[string]kv.Cursor
|
2021-06-19 08:21:53 +00:00
|
|
|
txFlags ethdb.TxFlags
|
2021-02-10 17:04:22 +00:00
|
|
|
len uint64
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
|
|
|
|
2022-08-10 12:04:13 +00:00
|
|
|
// nolint
|
2021-07-28 02:47:38 +00:00
|
|
|
func WrapIntoTxDB(tx kv.RwTx) *TxDb {
|
|
|
|
return &TxDb{tx: tx, cursors: map[string]kv.Cursor{}}
|
2021-05-01 07:42:23 +00:00
|
|
|
}
|
|
|
|
|
2020-08-17 06:45:52 +00:00
|
|
|
func (m *TxDb) Close() {
|
|
|
|
panic("don't call me")
|
|
|
|
}
|
|
|
|
|
2021-06-19 08:21:53 +00:00
|
|
|
func (m *TxDb) Begin(ctx context.Context, flags ethdb.TxFlags) (ethdb.DbWithPendingMutations, error) {
|
2020-08-26 06:02:10 +00:00
|
|
|
batch := m
|
|
|
|
if m.tx != nil {
|
2021-02-10 17:04:22 +00:00
|
|
|
panic("nested transactions not supported")
|
2020-08-26 06:02:10 +00:00
|
|
|
}
|
|
|
|
|
2021-02-10 17:04:22 +00:00
|
|
|
if err := batch.begin(ctx, flags); err != nil {
|
2020-08-17 06:45:52 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return batch, nil
|
|
|
|
}
|
|
|
|
|
2021-07-28 02:47:38 +00:00
|
|
|
func (m *TxDb) cursor(bucket string) (kv.Cursor, error) {
|
2021-01-15 09:38:09 +00:00
|
|
|
c, ok := m.cursors[bucket]
|
|
|
|
if !ok {
|
2021-04-02 06:36:49 +00:00
|
|
|
var err error
|
|
|
|
c, err = m.tx.Cursor(bucket)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-01-15 09:38:09 +00:00
|
|
|
m.cursors[bucket] = c
|
|
|
|
}
|
2021-04-02 06:36:49 +00:00
|
|
|
return c, nil
|
2021-01-15 09:38:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-20 14:12:54 +00:00
|
|
|
func (m *TxDb) IncrementSequence(bucket string, amount uint64) (res uint64, err error) {
|
2021-07-28 02:47:38 +00:00
|
|
|
return m.tx.(kv.RwTx).IncrementSequence(bucket, amount)
|
2021-03-20 14:12:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *TxDb) ReadSequence(bucket string) (res uint64, err error) {
|
|
|
|
return m.tx.ReadSequence(bucket)
|
2020-11-14 13:48:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-26 05:47:05 +00:00
|
|
|
func (m *TxDb) Put(table string, k, v []byte) error {
|
|
|
|
m.len += uint64(len(k) + len(v))
|
|
|
|
c, err := m.cursor(table)
|
2021-04-02 06:36:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-07-26 05:47:05 +00:00
|
|
|
return c.(kv.RwCursor).Put(k, v)
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *TxDb) Append(bucket string, key []byte, value []byte) error {
|
|
|
|
m.len += uint64(len(key) + len(value))
|
2021-04-02 06:36:49 +00:00
|
|
|
c, err := m.cursor(bucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-07-28 02:47:38 +00:00
|
|
|
return c.(kv.RwCursor).Append(key, value)
|
2020-11-28 14:24:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *TxDb) AppendDup(bucket string, key []byte, value []byte) error {
|
|
|
|
m.len += uint64(len(key) + len(value))
|
2021-04-02 06:36:49 +00:00
|
|
|
c, err := m.cursor(bucket)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-07-28 02:47:38 +00:00
|
|
|
return c.(kv.RwCursorDupSort).AppendDup(key, value)
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
|
|
|
|
2022-07-26 05:47:05 +00:00
|
|
|
func (m *TxDb) Delete(table string, k []byte) error {
|
2020-10-29 13:19:31 +00:00
|
|
|
m.len += uint64(len(k))
|
2022-07-26 05:47:05 +00:00
|
|
|
c, err := m.cursor(table)
|
2021-04-02 06:36:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-07-26 05:47:05 +00:00
|
|
|
return c.(kv.RwCursor).Delete(k)
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
|
|
|
|
2021-06-19 08:21:53 +00:00
|
|
|
func (m *TxDb) begin(ctx context.Context, flags ethdb.TxFlags) error {
|
2021-07-28 02:47:38 +00:00
|
|
|
db := m.db.(ethdb.HasRwKV).RwKV()
|
2021-03-21 13:15:25 +00:00
|
|
|
|
2021-07-28 02:47:38 +00:00
|
|
|
var tx kv.Tx
|
2021-03-21 13:15:25 +00:00
|
|
|
var err error
|
2021-06-19 08:21:53 +00:00
|
|
|
if flagsðdb.RO != 0 {
|
2021-07-28 02:47:38 +00:00
|
|
|
tx, err = db.BeginRo(ctx)
|
2021-03-21 13:15:25 +00:00
|
|
|
} else {
|
2021-07-28 02:47:38 +00:00
|
|
|
tx, err = db.BeginRw(ctx)
|
2021-03-21 13:15:25 +00:00
|
|
|
}
|
2020-08-17 06:45:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-26 06:02:10 +00:00
|
|
|
m.tx = tx
|
2021-07-28 02:47:38 +00:00
|
|
|
m.cursors = make(map[string]kv.Cursor, 16)
|
2020-08-17 06:45:52 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-07-28 02:47:38 +00:00
|
|
|
func (m *TxDb) RwKV() kv.RwDB {
|
2020-08-26 06:02:10 +00:00
|
|
|
panic("not allowed to get KV interface because you will loose transaction, please use .Tx() method")
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
|
|
|
|
2021-02-28 04:11:28 +00:00
|
|
|
// Last can only be called from the transaction thread
|
2020-08-17 06:45:52 +00:00
|
|
|
func (m *TxDb) Last(bucket string) ([]byte, []byte, error) {
|
2021-04-02 06:36:49 +00:00
|
|
|
c, err := m.cursor(bucket)
|
|
|
|
if err != nil {
|
|
|
|
return []byte{}, nil, err
|
|
|
|
}
|
|
|
|
return c.Last()
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
|
|
|
|
2021-04-05 13:04:58 +00:00
|
|
|
func (m *TxDb) GetOne(bucket string, key []byte) ([]byte, error) {
|
2021-04-02 06:36:49 +00:00
|
|
|
c, err := m.cursor(bucket)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_, v, err := c.SeekExact(key)
|
2021-04-05 13:04:58 +00:00
|
|
|
return v, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *TxDb) Get(bucket string, key []byte) ([]byte, error) {
|
|
|
|
dat, err := m.GetOne(bucket, key)
|
2021-06-19 08:21:53 +00:00
|
|
|
return ethdb.GetOneWrapper(dat, err)
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2021-06-05 15:17:04 +00:00
|
|
|
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)
|
|
|
|
}
|
2020-08-17 06:45:52 +00:00
|
|
|
|
2021-03-22 12:41:52 +00:00
|
|
|
func (m *TxDb) Commit() error {
|
2020-08-26 06:02:10 +00:00
|
|
|
if m.tx == nil {
|
2021-03-22 12:41:52 +00:00
|
|
|
return fmt.Errorf("second call .Commit() on same transaction")
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
2021-04-03 06:26:00 +00:00
|
|
|
if err := m.tx.Commit(); err != nil {
|
2021-03-22 12:41:52 +00:00
|
|
|
return err
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
2020-08-26 06:02:10 +00:00
|
|
|
m.tx = nil
|
2020-08-17 06:45:52 +00:00
|
|
|
m.cursors = nil
|
|
|
|
m.len = 0
|
2021-03-22 12:41:52 +00:00
|
|
|
return nil
|
2020-08-17 06:45:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *TxDb) Rollback() {
|
2020-08-26 06:02:10 +00:00
|
|
|
if m.tx == nil {
|
2020-08-17 06:45:52 +00:00
|
|
|
return
|
|
|
|
}
|
2020-08-26 06:02:10 +00:00
|
|
|
m.tx.Rollback()
|
2020-08-17 06:45:52 +00:00
|
|
|
m.cursors = nil
|
2020-08-26 06:02:10 +00:00
|
|
|
m.tx = nil
|
2020-08-17 06:45:52 +00:00
|
|
|
m.len = 0
|
|
|
|
}
|
|
|
|
|
2021-07-28 02:47:38 +00:00
|
|
|
func (m *TxDb) Tx() kv.Tx {
|
2020-08-26 06:02:10 +00:00
|
|
|
return m.tx
|
|
|
|
}
|
|
|
|
|
2020-09-08 19:39:43 +00:00
|
|
|
func (m *TxDb) BucketExists(name string) (bool, error) {
|
2021-07-28 02:47:38 +00:00
|
|
|
migrator, ok := m.tx.(kv.BucketMigrator)
|
2020-09-08 19:39:43 +00:00
|
|
|
if !ok {
|
|
|
|
return false, fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", m.tx)
|
|
|
|
}
|
2021-07-24 04:28:05 +00:00
|
|
|
return migrator.ExistsBucket(name)
|
2020-09-08 19:39:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *TxDb) ClearBuckets(buckets ...string) error {
|
|
|
|
for i := range buckets {
|
|
|
|
name := buckets[i]
|
|
|
|
|
2021-07-28 02:47:38 +00:00
|
|
|
migrator, ok := m.tx.(kv.BucketMigrator)
|
2020-09-08 19:39:43 +00:00
|
|
|
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)
|
2021-07-28 02:47:38 +00:00
|
|
|
migrator, ok := m.tx.(kv.BucketMigrator)
|
2020-09-08 19:39:43 +00:00
|
|
|
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
|
|
|
|
}
|