github.com/amazechain/amc@v0.1.3/internal/amcdb/lmdb/snapshot_rw.go (about) 1 // Copyright 2022 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The AmazeChain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package lmdb 18 19 import ( 20 "context" 21 "github.com/erigontech/mdbx-go/mdbx" 22 "sync" 23 ) 24 25 type DBISnapshot struct { 26 ctx context.Context 27 txn *mdbx.Txn 28 ok bool 29 30 lock sync.RWMutex 31 once sync.Once 32 33 dbi map[string]mdbx.DBI 34 dbiLock sync.RWMutex 35 } 36 37 func newSnapshot(ctx context.Context, parent *mdbx.Txn, env *mdbx.Env) (*DBISnapshot, error) { 38 txn, err := env.BeginTxn(nil, 0) 39 if err != nil { 40 return nil, err 41 } 42 43 return &DBISnapshot{ 44 ctx: ctx, 45 txn: txn, 46 ok: true, 47 dbi: make(map[string]mdbx.DBI), 48 }, nil 49 } 50 51 func (db *DBISnapshot) IsRunning() bool { 52 return db.ok 53 } 54 55 func (db *DBISnapshot) Get(dbName string, key []byte) (value []byte, err error) { 56 if !db.IsRunning() { 57 return nil, errorSnapshotIsClose 58 } 59 db.lock.RLock() 60 defer db.lock.RUnlock() 61 62 dbi, err := db.openDBI(dbName) 63 if err != nil { 64 return nil, err 65 } 66 67 return db.txn.Get(*dbi, key) 68 } 69 70 //func (db *DBISnapshot) GetIterator(dbName string, key []byte) (iterator db.IIterator, err error) { 71 // if !db.IsRunning() { 72 // return nil, errorSnapshotIsClose 73 // } 74 // 75 // dbi, err := db.openDBI(dbName) 76 // if err != nil { 77 // return nil, err 78 // } 79 // 80 // return newIterator(dbi, key) 81 //} 82 83 func (db *DBISnapshot) Put(dbName string, key []byte, value []byte) (err error) { 84 if !db.IsRunning() { 85 return errorSnapshotIsClose 86 } 87 db.lock.RLock() 88 defer db.lock.RUnlock() 89 90 dbi, err := db.openDBI(dbName) 91 if err != nil { 92 return err 93 } 94 95 return db.txn.Put(*dbi, key, value, 0) 96 } 97 98 func (db *DBISnapshot) Commit() error { 99 var err error 100 db.once.Do(func() { 101 if !db.IsRunning() { 102 err = errorSnapshotIsClose 103 } 104 db.lock.Lock() 105 defer db.lock.Unlock() 106 db.ok = false 107 _, err = db.txn.Commit() 108 }) 109 110 return err 111 } 112 113 func (db *DBISnapshot) Rollback() { 114 db.once.Do(func() { 115 if db.IsRunning() { 116 db.lock.Lock() 117 defer db.lock.Unlock() 118 db.ok = false 119 db.txn.Abort() 120 } 121 }) 122 } 123 124 func (db *DBISnapshot) openDBI(name string) (*mdbx.DBI, error) { 125 if !db.IsRunning() { 126 return nil, errorSnapshotIsClose 127 } 128 129 db.dbiLock.Lock() 130 defer db.dbiLock.Unlock() 131 132 if dbi, ok := db.dbi[name]; ok { 133 return &dbi, nil 134 } 135 136 dbi, err := db.txn.OpenDBI(name, mdbx.Create, nil, nil) 137 if err != nil { 138 return nil, err 139 } 140 141 db.dbi[name] = dbi 142 return &dbi, nil 143 }