mirror of https://github.com/status-im/nim-eth.git
more robust dbtx dispose
This commit is contained in:
parent
7079efcae3
commit
96f29a971d
|
@ -34,11 +34,15 @@ type
|
|||
containsProc: ContainsProc
|
||||
mostInnerTransaction: DbTransaction
|
||||
|
||||
TransactionFlags = enum
|
||||
Committed
|
||||
RolledBack
|
||||
|
||||
DbTransaction* = ref object
|
||||
db: TrieDatabaseRef
|
||||
parentTransaction: DbTransaction
|
||||
modifications: MemoryLayer
|
||||
committed: bool
|
||||
flags: set[TransactionFlags]
|
||||
|
||||
proc put*(db: TrieDatabaseRef, key, val: openarray[byte]) {.gcsafe.}
|
||||
proc get*(db: TrieDatabaseRef, key: openarray[byte]): Bytes {.gcsafe.}
|
||||
|
@ -137,24 +141,32 @@ proc rollback*(t: DbTransaction) =
|
|||
# Transactions should be handled in a strictly nested fashion.
|
||||
# Any child transaction must be committed or rolled-back before
|
||||
# its parent transactions:
|
||||
doAssert t.db.mostInnerTransaction == t and not t.committed
|
||||
doAssert t.db.mostInnerTransaction == t and
|
||||
Committed notin t.flags and
|
||||
RolledBack notin t.flags
|
||||
t.db.mostInnerTransaction = t.parentTransaction
|
||||
t.flags.incl RolledBack
|
||||
|
||||
proc commit*(t: DbTransaction) =
|
||||
# Transactions should be handled in a strictly nested fashion.
|
||||
# Any child transaction must be committed or rolled-back before
|
||||
# its parent transactions:
|
||||
doAssert t.db.mostInnerTransaction == t and not t.committed
|
||||
doAssert t.db.mostInnerTransaction == t and
|
||||
Committed notin t.flags and
|
||||
RolledBack notin t.flags
|
||||
t.db.mostInnerTransaction = t.parentTransaction
|
||||
t.modifications.commit(t.db)
|
||||
t.committed = true
|
||||
t.flags.incl Committed
|
||||
|
||||
proc dispose*(t: DbTransaction) {.inline.} =
|
||||
if not t.committed:
|
||||
if Committed notin t.flags and
|
||||
RolledBack notin t.flags:
|
||||
t.rollback()
|
||||
|
||||
proc safeDispose*(t: DbTransaction) {.inline.} =
|
||||
if t != nil and not t.committed:
|
||||
if t != nil and
|
||||
Committed notin t.flags and
|
||||
RolledBack notin t.flags:
|
||||
t.rollback()
|
||||
|
||||
proc putImpl[T](db: RootRef, key, val: openarray[byte]) =
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
import
|
||||
unittest, strutils, sequtils, os,
|
||||
eth/trie/[db, trie_defs], ./testutils,
|
||||
eth/rlp/types as rlpTypes
|
||||
|
||||
suite "transaction db":
|
||||
setup:
|
||||
const
|
||||
listLength = 30
|
||||
|
||||
var
|
||||
keysA = randList(Bytes, randGen(3, 33), randGen(listLength))
|
||||
valuesA = randList(Bytes, randGen(5, 77), randGen(listLength))
|
||||
keysB = randList(Bytes, randGen(3, 33), randGen(listLength))
|
||||
valuesB = randList(Bytes, randGen(5, 77), randGen(listLength))
|
||||
|
||||
proc populateA(db: TrieDatabaseRef) =
|
||||
for i in 0 ..< listLength:
|
||||
db.put(keysA[i], valuesA[i])
|
||||
|
||||
proc checkContentsA(db: TrieDatabaseRef): bool =
|
||||
for i in 0 ..< listLength:
|
||||
let v = db.get(keysA[i])
|
||||
if v != valuesA[i]: return false
|
||||
result = true
|
||||
|
||||
proc checkEmptyContentsA(db: TrieDatabaseRef): bool {.used.} =
|
||||
for i in 0 ..< listLength:
|
||||
let v = db.get(keysA[i])
|
||||
if v.len != 0: return false
|
||||
result = true
|
||||
|
||||
proc populateB(db: TrieDatabaseRef) {.used.} =
|
||||
for i in 0 ..< listLength:
|
||||
db.put(keysB[i], valuesB[i])
|
||||
|
||||
proc checkContentsB(db: TrieDatabaseRef): bool {.used.} =
|
||||
for i in 0 ..< listLength:
|
||||
let v = db.get(keysB[i])
|
||||
if v != valuesB[i]: return false
|
||||
result = true
|
||||
|
||||
proc checkEmptyContentsB(db: TrieDatabaseRef): bool {.used.} =
|
||||
for i in 0 ..< listLength:
|
||||
let v = db.get(keysB[i])
|
||||
if v.len != 0: return false
|
||||
result = true
|
||||
|
||||
test "commit":
|
||||
var db = newMemoryDB()
|
||||
var tx = db.beginTransaction()
|
||||
db.populateA()
|
||||
check checkContentsA(db)
|
||||
tx.commit()
|
||||
check checkContentsA(db)
|
||||
|
||||
test "rollback":
|
||||
var db = newMemoryDB()
|
||||
var tx = db.beginTransaction()
|
||||
db.populateA()
|
||||
check checkContentsA(db)
|
||||
tx.rollback()
|
||||
check checkEmptyContentsA(db)
|
||||
|
||||
test "dispose":
|
||||
var db = newMemoryDB()
|
||||
var tx = db.beginTransaction()
|
||||
db.populateA()
|
||||
check checkContentsA(db)
|
||||
tx.dispose()
|
||||
check checkEmptyContentsA(db)
|
||||
|
||||
test "commit dispose":
|
||||
var db = newMemoryDB()
|
||||
var tx = db.beginTransaction()
|
||||
db.populateA()
|
||||
check checkContentsA(db)
|
||||
tx.commit()
|
||||
tx.dispose()
|
||||
check checkContentsA(db)
|
||||
|
||||
test "rollback dispose":
|
||||
var db = newMemoryDB()
|
||||
var tx = db.beginTransaction()
|
||||
db.populateA()
|
||||
check checkContentsA(db)
|
||||
tx.rollback()
|
||||
tx.dispose()
|
||||
check checkEmptyContentsA(db)
|
||||
|
||||
test "dispose dispose":
|
||||
var db = newMemoryDB()
|
||||
var tx = db.beginTransaction()
|
||||
db.populateA()
|
||||
check checkContentsA(db)
|
||||
tx.dispose()
|
||||
tx.dispose()
|
||||
check checkEmptyContentsA(db)
|
||||
|
||||
test "commit commit":
|
||||
var db = newMemoryDB()
|
||||
var txA = db.beginTransaction()
|
||||
db.populateA()
|
||||
var txB = db.beginTransaction()
|
||||
db.populateB()
|
||||
|
||||
check checkContentsA(db)
|
||||
check checkContentsB(db)
|
||||
|
||||
txB.commit()
|
||||
txA.commit()
|
||||
|
||||
check checkContentsA(db)
|
||||
check checkContentsB(db)
|
||||
|
||||
test "commit rollback":
|
||||
var db = newMemoryDB()
|
||||
var txA = db.beginTransaction()
|
||||
db.populateA()
|
||||
var txB = db.beginTransaction()
|
||||
db.populateB()
|
||||
|
||||
check checkContentsA(db)
|
||||
check checkContentsB(db)
|
||||
|
||||
txB.rollback()
|
||||
txA.commit()
|
||||
|
||||
check checkContentsA(db)
|
||||
check checkEmptyContentsB(db)
|
||||
|
||||
test "rollback commit":
|
||||
var db = newMemoryDB()
|
||||
var txA = db.beginTransaction()
|
||||
db.populateA()
|
||||
var txB = db.beginTransaction()
|
||||
db.populateB()
|
||||
|
||||
check checkContentsA(db)
|
||||
check checkContentsB(db)
|
||||
|
||||
txB.commit()
|
||||
txA.rollback()
|
||||
|
||||
check checkEmptyContentsB(db)
|
||||
check checkEmptyContentsA(db)
|
||||
|
||||
test "rollback rollback":
|
||||
var db = newMemoryDB()
|
||||
var txA = db.beginTransaction()
|
||||
db.populateA()
|
||||
var txB = db.beginTransaction()
|
||||
db.populateB()
|
||||
|
||||
check checkContentsA(db)
|
||||
check checkContentsB(db)
|
||||
|
||||
txB.rollback()
|
||||
txA.rollback()
|
||||
|
||||
check checkEmptyContentsB(db)
|
||||
check checkEmptyContentsA(db)
|
||||
|
||||
test "commit rollback dispose":
|
||||
var db = newMemoryDB()
|
||||
var txA = db.beginTransaction()
|
||||
db.populateA()
|
||||
var txB = db.beginTransaction()
|
||||
db.populateB()
|
||||
|
||||
check checkContentsA(db)
|
||||
check checkContentsB(db)
|
||||
|
||||
txB.rollback()
|
||||
txA.commit()
|
||||
txA.dispose()
|
||||
|
||||
check checkContentsA(db)
|
||||
check checkEmptyContentsB(db)
|
|
@ -27,6 +27,11 @@ proc randString*(len: int): string =
|
|||
for i in 0..<len:
|
||||
result[i] = rand(255).char
|
||||
|
||||
proc randBytes*(len: int): Bytes =
|
||||
result = newSeq[byte](len)
|
||||
for i in 0..<len:
|
||||
result[i] = rand(255).byte
|
||||
|
||||
proc toBytesRange*(str: string): BytesRange =
|
||||
var s: seq[byte]
|
||||
if str[0] == '0' and str[1] == 'x':
|
||||
|
@ -44,6 +49,8 @@ proc randPrimitives*[T](val: int): T =
|
|||
result = val
|
||||
elif T is BytesRange:
|
||||
result = randString(val).toRange
|
||||
elif T is Bytes:
|
||||
result = randBytes(val)
|
||||
|
||||
proc randList*(T: typedesc, strGen, listGen: RandGen, unique: bool = true): seq[T] =
|
||||
let listLen = listGen.getVal()
|
||||
|
@ -82,4 +89,3 @@ proc genBitVec*(len: int): BitRange =
|
|||
result = bits(s, len)
|
||||
for i in 0..<len:
|
||||
result[i] = rand(2) == 1
|
||||
|
||||
|
|
Loading…
Reference in New Issue