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ðdb.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 }