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
|
containsProc: ContainsProc
|
||||||
mostInnerTransaction: DbTransaction
|
mostInnerTransaction: DbTransaction
|
||||||
|
|
||||||
|
TransactionFlags = enum
|
||||||
|
Committed
|
||||||
|
RolledBack
|
||||||
|
|
||||||
DbTransaction* = ref object
|
DbTransaction* = ref object
|
||||||
db: TrieDatabaseRef
|
db: TrieDatabaseRef
|
||||||
parentTransaction: DbTransaction
|
parentTransaction: DbTransaction
|
||||||
modifications: MemoryLayer
|
modifications: MemoryLayer
|
||||||
committed: bool
|
flags: set[TransactionFlags]
|
||||||
|
|
||||||
proc put*(db: TrieDatabaseRef, key, val: openarray[byte]) {.gcsafe.}
|
proc put*(db: TrieDatabaseRef, key, val: openarray[byte]) {.gcsafe.}
|
||||||
proc get*(db: TrieDatabaseRef, key: openarray[byte]): Bytes {.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.
|
# Transactions should be handled in a strictly nested fashion.
|
||||||
# Any child transaction must be committed or rolled-back before
|
# Any child transaction must be committed or rolled-back before
|
||||||
# its parent transactions:
|
# 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.db.mostInnerTransaction = t.parentTransaction
|
||||||
|
t.flags.incl RolledBack
|
||||||
|
|
||||||
proc commit*(t: DbTransaction) =
|
proc commit*(t: DbTransaction) =
|
||||||
# Transactions should be handled in a strictly nested fashion.
|
# Transactions should be handled in a strictly nested fashion.
|
||||||
# Any child transaction must be committed or rolled-back before
|
# Any child transaction must be committed or rolled-back before
|
||||||
# its parent transactions:
|
# 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.db.mostInnerTransaction = t.parentTransaction
|
||||||
t.modifications.commit(t.db)
|
t.modifications.commit(t.db)
|
||||||
t.committed = true
|
t.flags.incl Committed
|
||||||
|
|
||||||
proc dispose*(t: DbTransaction) {.inline.} =
|
proc dispose*(t: DbTransaction) {.inline.} =
|
||||||
if not t.committed:
|
if Committed notin t.flags and
|
||||||
|
RolledBack notin t.flags:
|
||||||
t.rollback()
|
t.rollback()
|
||||||
|
|
||||||
proc safeDispose*(t: DbTransaction) {.inline.} =
|
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()
|
t.rollback()
|
||||||
|
|
||||||
proc putImpl[T](db: RootRef, key, val: openarray[byte]) =
|
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:
|
for i in 0..<len:
|
||||||
result[i] = rand(255).char
|
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 =
|
proc toBytesRange*(str: string): BytesRange =
|
||||||
var s: seq[byte]
|
var s: seq[byte]
|
||||||
if str[0] == '0' and str[1] == 'x':
|
if str[0] == '0' and str[1] == 'x':
|
||||||
|
@ -44,6 +49,8 @@ proc randPrimitives*[T](val: int): T =
|
||||||
result = val
|
result = val
|
||||||
elif T is BytesRange:
|
elif T is BytesRange:
|
||||||
result = randString(val).toRange
|
result = randString(val).toRange
|
||||||
|
elif T is Bytes:
|
||||||
|
result = randBytes(val)
|
||||||
|
|
||||||
proc randList*(T: typedesc, strGen, listGen: RandGen, unique: bool = true): seq[T] =
|
proc randList*(T: typedesc, strGen, listGen: RandGen, unique: bool = true): seq[T] =
|
||||||
let listLen = listGen.getVal()
|
let listLen = listGen.getVal()
|
||||||
|
@ -82,4 +89,3 @@ proc genBitVec*(len: int): BitRange =
|
||||||
result = bits(s, len)
|
result = bits(s, len)
|
||||||
for i in 0..<len:
|
for i in 0..<len:
|
||||||
result[i] = rand(2) == 1
|
result[i] = rand(2) == 1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue