github.com/amazechain/amc@v0.1.3/modules/ethdb/olddb/tx_db.go (about)

     1  package olddb
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/amazechain/amc/modules/ethdb"
     8  	"github.com/ledgerwatch/erigon-lib/kv"
     9  	"github.com/ledgerwatch/log/v3"
    10  )
    11  
    12  // TxDb - provides Database interface around ethdb.Tx
    13  // It's not thread-safe!
    14  // TxDb not usable after .Commit()/.Rollback() call, but usable after .CommitAndBegin() call
    15  // you can put unlimited amount of data into this class
    16  // Walk and MultiWalk methods - work outside of Tx object yet, will implement it later
    17  // Deprecated
    18  // nolint
    19  type TxDb struct {
    20  	db      ethdb.Database
    21  	tx      kv.Tx
    22  	cursors map[string]kv.Cursor
    23  	txFlags ethdb.TxFlags
    24  	len     uint64
    25  }
    26  
    27  // nolint
    28  func WrapIntoTxDB(tx kv.RwTx) *TxDb {
    29  	return &TxDb{tx: tx, cursors: map[string]kv.Cursor{}}
    30  }
    31  
    32  func (m *TxDb) Close() {
    33  	panic("don't call me")
    34  }
    35  
    36  func (m *TxDb) Begin(ctx context.Context, flags ethdb.TxFlags) (ethdb.DbWithPendingMutations, error) {
    37  	batch := m
    38  	if m.tx != nil {
    39  		panic("nested transactions not supported")
    40  	}
    41  
    42  	if err := batch.begin(ctx, flags); err != nil {
    43  		return nil, err
    44  	}
    45  	return batch, nil
    46  }
    47  
    48  func (m *TxDb) cursor(bucket string) (kv.Cursor, error) {
    49  	c, ok := m.cursors[bucket]
    50  	if !ok {
    51  		var err error
    52  		c, err = m.tx.Cursor(bucket)
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  		m.cursors[bucket] = c
    57  	}
    58  	return c, nil
    59  }
    60  
    61  func (m *TxDb) IncrementSequence(bucket string, amount uint64) (res uint64, err error) {
    62  	return m.tx.(kv.RwTx).IncrementSequence(bucket, amount)
    63  }
    64  
    65  func (m *TxDb) ReadSequence(bucket string) (res uint64, err error) {
    66  	return m.tx.ReadSequence(bucket)
    67  }
    68  
    69  func (m *TxDb) Put(table string, k, v []byte) error {
    70  	m.len += uint64(len(k) + len(v))
    71  	c, err := m.cursor(table)
    72  	if err != nil {
    73  		return err
    74  	}
    75  	return c.(kv.RwCursor).Put(k, v)
    76  }
    77  
    78  func (m *TxDb) Append(bucket string, key []byte, value []byte) error {
    79  	m.len += uint64(len(key) + len(value))
    80  	c, err := m.cursor(bucket)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	return c.(kv.RwCursor).Append(key, value)
    85  }
    86  
    87  func (m *TxDb) AppendDup(bucket string, key []byte, value []byte) error {
    88  	m.len += uint64(len(key) + len(value))
    89  	c, err := m.cursor(bucket)
    90  	if err != nil {
    91  		return err
    92  	}
    93  	return c.(kv.RwCursorDupSort).AppendDup(key, value)
    94  }
    95  
    96  func (m *TxDb) Delete(table string, k []byte) error {
    97  	m.len += uint64(len(k))
    98  	c, err := m.cursor(table)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	return c.(kv.RwCursor).Delete(k)
   103  }
   104  
   105  func (m *TxDb) begin(ctx context.Context, flags ethdb.TxFlags) error {
   106  	db := m.db.(ethdb.HasRwKV).RwKV()
   107  
   108  	var tx kv.Tx
   109  	var err error
   110  	if flags&ethdb.RO != 0 {
   111  		tx, err = db.BeginRo(ctx)
   112  	} else {
   113  		tx, err = db.BeginRw(ctx)
   114  	}
   115  	if err != nil {
   116  		return err
   117  	}
   118  	m.tx = tx
   119  	m.cursors = make(map[string]kv.Cursor, 16)
   120  	return nil
   121  }
   122  
   123  func (m *TxDb) RwKV() kv.RwDB {
   124  	panic("not allowed to get KV interface because you will loose transaction, please use .Tx() method")
   125  }
   126  
   127  // Last can only be called from the transaction thread
   128  func (m *TxDb) Last(bucket string) ([]byte, []byte, error) {
   129  	c, err := m.cursor(bucket)
   130  	if err != nil {
   131  		return []byte{}, nil, err
   132  	}
   133  	return c.Last()
   134  }
   135  
   136  func (m *TxDb) GetOne(bucket string, key []byte) ([]byte, error) {
   137  	c, err := m.cursor(bucket)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	_, v, err := c.SeekExact(key)
   142  	return v, err
   143  }
   144  
   145  func (m *TxDb) Get(bucket string, key []byte) ([]byte, error) {
   146  	dat, err := m.GetOne(bucket, key)
   147  	return ethdb.GetOneWrapper(dat, err)
   148  }
   149  
   150  func (m *TxDb) Has(bucket string, key []byte) (bool, error) {
   151  	v, err := m.Get(bucket, key)
   152  	if err != nil {
   153  		return false, err
   154  	}
   155  	return v != nil, nil
   156  }
   157  
   158  func (m *TxDb) BatchSize() int {
   159  	return int(m.len)
   160  }
   161  
   162  func (m *TxDb) ForEach(bucket string, fromPrefix []byte, walker func(k, v []byte) error) error {
   163  	return m.tx.ForEach(bucket, fromPrefix, walker)
   164  }
   165  
   166  func (m *TxDb) ForPrefix(bucket string, prefix []byte, walker func(k, v []byte) error) error {
   167  	return m.tx.ForPrefix(bucket, prefix, walker)
   168  }
   169  
   170  func (m *TxDb) ForAmount(bucket string, prefix []byte, amount uint32, walker func(k, v []byte) error) error {
   171  	return m.tx.ForAmount(bucket, prefix, amount, walker)
   172  }
   173  
   174  func (m *TxDb) Commit() error {
   175  	if m.tx == nil {
   176  		return fmt.Errorf("second call .Commit() on same transaction")
   177  	}
   178  	if err := m.tx.Commit(); err != nil {
   179  		return err
   180  	}
   181  	m.tx = nil
   182  	m.cursors = nil
   183  	m.len = 0
   184  	return nil
   185  }
   186  
   187  func (m *TxDb) Rollback() {
   188  	if m.tx == nil {
   189  		return
   190  	}
   191  	m.tx.Rollback()
   192  	m.cursors = nil
   193  	m.tx = nil
   194  	m.len = 0
   195  }
   196  
   197  func (m *TxDb) Tx() kv.Tx {
   198  	return m.tx
   199  }
   200  
   201  func (m *TxDb) BucketExists(name string) (bool, error) {
   202  	migrator, ok := m.tx.(kv.BucketMigrator)
   203  	if !ok {
   204  		return false, fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", m.tx)
   205  	}
   206  	return migrator.ExistsBucket(name)
   207  }
   208  
   209  func (m *TxDb) ClearBuckets(buckets ...string) error {
   210  	for i := range buckets {
   211  		name := buckets[i]
   212  
   213  		migrator, ok := m.tx.(kv.BucketMigrator)
   214  		if !ok {
   215  			return fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", m.tx)
   216  		}
   217  		if err := migrator.ClearBucket(name); err != nil {
   218  			return err
   219  		}
   220  	}
   221  
   222  	return nil
   223  }
   224  
   225  func (m *TxDb) DropBuckets(buckets ...string) error {
   226  	for i := range buckets {
   227  		name := buckets[i]
   228  		log.Info("Dropping bucket", "name", name)
   229  		migrator, ok := m.tx.(kv.BucketMigrator)
   230  		if !ok {
   231  			return fmt.Errorf("%T doesn't implement ethdb.TxMigrator interface", m.tx)
   232  		}
   233  		if err := migrator.DropBucket(name); err != nil {
   234  			return err
   235  		}
   236  	}
   237  	return nil
   238  }