reduce tx naming overload (#2952)

* if it's a db function, use `txFrame...`
* if it's not a db function, don't use `txFrame...`
This commit is contained in:
Jacek Sieka 2024-12-18 17:03:51 +01:00 committed by GitHub
parent 7bbb0f4421
commit d45d03ce0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 147 additions and 342 deletions

View File

@ -42,7 +42,7 @@ proc processBlock(
## implementations (but can be savely removed, as well.) ## implementations (but can be savely removed, as well.)
## variant of `processBlock()` where the `header` argument is explicitely set. ## variant of `processBlock()` where the `header` argument is explicitely set.
template header: Header = blk.header template header: Header = blk.header
var dbTx = vmState.com.db.ctx.newTransaction() var dbTx = vmState.com.db.ctx.txFrameBegin()
defer: dbTx.dispose() defer: dbTx.dispose()
let com = vmState.com let com = vmState.com
@ -89,7 +89,7 @@ proc getVmState(c: ChainRef, header: Header):
# intended to accepts invalid block # intended to accepts invalid block
proc setBlock*(c: ChainRef; blk: Block): Result[void, string] = proc setBlock*(c: ChainRef; blk: Block): Result[void, string] =
template header: Header = blk.header template header: Header = blk.header
let dbTx = c.db.ctx.newTransaction() let dbTx = c.db.ctx.txFrameBegin()
defer: dbTx.dispose() defer: dbTx.dispose()
# Needed for figuring out whether KVT cleanup is due (see at the end) # Needed for figuring out whether KVT cleanup is due (see at the end)

View File

@ -140,7 +140,7 @@ proc validateBlock(c: ForkedChainRef,
parent: Header, parent: Header,
blk: Block, blk: Block,
updateCursor: bool = true): Result[void, string] = updateCursor: bool = true): Result[void, string] =
let dbTx = c.db.ctx.newTransaction() let dbTx = c.db.ctx.txFrameBegin()
defer: defer:
dbTx.dispose() dbTx.dispose()
@ -170,7 +170,7 @@ proc replaySegment*(c: ForkedChainRef, target: Hash32) =
prevHash = chain[^1].header.parentHash prevHash = chain[^1].header.parentHash
c.stagingTx.rollback() c.stagingTx.rollback()
c.stagingTx = c.db.ctx.newTransaction() c.stagingTx = c.db.ctx.txFrameBegin()
c.cursorHeader = c.baseHeader c.cursorHeader = c.baseHeader
for i in countdown(chain.high, chain.low): for i in countdown(chain.high, chain.low):
c.validateBlock(c.cursorHeader, chain[i], c.validateBlock(c.cursorHeader, chain[i],
@ -432,7 +432,7 @@ proc updateHeadIfNecessary(c: ForkedChainRef, pvarc: PivotArc) =
if c.cursorHash != pvarc.cursor.hash: if c.cursorHash != pvarc.cursor.hash:
if not c.stagingTx.isNil: if not c.stagingTx.isNil:
c.stagingTx.rollback() c.stagingTx.rollback()
c.stagingTx = c.db.ctx.newTransaction() c.stagingTx = c.db.ctx.txFrameBegin()
c.replaySegment(pvarc.pvHash) c.replaySegment(pvarc.pvHash)
c.trimCursorArc(pvarc) c.trimCursorArc(pvarc)
@ -442,7 +442,7 @@ proc updateHeadIfNecessary(c: ForkedChainRef, pvarc: PivotArc) =
if c.stagingTx.isNil: if c.stagingTx.isNil:
# setHead below don't go straight to db # setHead below don't go straight to db
c.stagingTx = c.db.ctx.newTransaction() c.stagingTx = c.db.ctx.txFrameBegin()
c.setHead(pvarc) c.setHead(pvarc)
@ -511,7 +511,7 @@ proc importBlock*(c: ForkedChainRef, blk: Block): Result[void, string] =
# Try to import block to canonical or side chain. # Try to import block to canonical or side chain.
# return error if the block is invalid # return error if the block is invalid
if c.stagingTx.isNil: if c.stagingTx.isNil:
c.stagingTx = c.db.ctx.newTransaction() c.stagingTx = c.db.ctx.txFrameBegin()
template header(): Header = template header(): Header =
blk.header blk.header
@ -521,7 +521,7 @@ proc importBlock*(c: ForkedChainRef, blk: Block): Result[void, string] =
if header.parentHash == c.baseHash: if header.parentHash == c.baseHash:
c.stagingTx.rollback() c.stagingTx.rollback()
c.stagingTx = c.db.ctx.newTransaction() c.stagingTx = c.db.ctx.txFrameBegin()
return c.validateBlock(c.baseHeader, blk) return c.validateBlock(c.baseHeader, blk)
if header.parentHash notin c.blocks: if header.parentHash notin c.blocks:
@ -601,7 +601,7 @@ proc forkChoice*(c: ForkedChainRef,
# Write segment from base+1 to newBase into database # Write segment from base+1 to newBase into database
c.stagingTx.rollback() c.stagingTx.rollback()
c.stagingTx = c.db.ctx.newTransaction() c.stagingTx = c.db.ctx.txFrameBegin()
if newBase.pvNumber > c.baseHeader.number: if newBase.pvNumber > c.baseHeader.number:
c.replaySegment(newBase.pvHash) c.replaySegment(newBase.pvHash)
@ -616,7 +616,7 @@ proc forkChoice*(c: ForkedChainRef,
if c.stagingTx.isNil: if c.stagingTx.isNil:
# replaySegment or setHead below don't # replaySegment or setHead below don't
# go straight to db # go straight to db
c.stagingTx = c.db.ctx.newTransaction() c.stagingTx = c.db.ctx.txFrameBegin()
# Move chain state forward to current head # Move chain state forward to current head
if newBase.pvNumber < pvarc.pvNumber: if newBase.pvNumber < pvarc.pvNumber:

View File

@ -117,6 +117,9 @@ proc persistBlock*(p: var Persister, blk: Block): Result[void, string] =
let c = p.c let c = p.c
if p.dbTx == nil:
p.dbTx = p.c.db.ctx.txFrameBegin()
# Full validation means validating the state root at every block and # Full validation means validating the state root at every block and
# performing the more expensive hash computations on the block itself, ie # performing the more expensive hash computations on the block itself, ie
# verifying that the transaction and receipts roots are valid - when not # verifying that the transaction and receipts roots are valid - when not

View File

@ -292,7 +292,7 @@ proc packerVmExec*(xp: TxPoolRef): Result[TxPacker, string]
## Rebuild `packed` bucket by selection items from the `staged` bucket ## Rebuild `packed` bucket by selection items from the `staged` bucket
## after executing them in the VM. ## after executing them in the VM.
let db = xp.vmState.com.db let db = xp.vmState.com.db
let dbTx = db.ctx.newTransaction() let dbTx = db.ctx.txFrameBegin()
defer: dbTx.dispose() defer: dbTx.dispose()
var pst = xp.vmExecInit.valueOr: var pst = xp.vmExecInit.valueOr:

View File

@ -178,7 +178,7 @@ type
## Getter, returns `true` if the argument `tx` referes to the current ## Getter, returns `true` if the argument `tx` referes to the current
## top level transaction. ## top level transaction.
AristoApiLevelFn* = AristoApiTxFrameLevelFn* =
proc(db: AristoDbRef; proc(db: AristoDbRef;
): int ): int
{.noRaise.} {.noRaise.}
@ -310,7 +310,7 @@ type
## operations performed for this transactio. The previous transaction ## operations performed for this transactio. The previous transaction
## is returned if there was any. ## is returned if there was any.
AristoApiTxBeginFn* = AristoApiTxFrameBeginFn* =
proc(db: AristoDbRef; proc(db: AristoDbRef;
): Result[AristoTxRef,AristoError] ): Result[AristoTxRef,AristoError]
{.noRaise.} {.noRaise.}
@ -324,13 +324,7 @@ type
## ... continue using db ... ## ... continue using db ...
## tx.commit() ## tx.commit()
AristoApiTxLevelFn* = AristoApiTxFrameTopFn* =
proc(tx: AristoTxRef;
): int
{.noRaise.}
## Getter, positive nesting level of transaction argument `tx`
AristoApiTxTopFn* =
proc(db: AristoDbRef; proc(db: AristoDbRef;
): Result[AristoTxRef,AristoError] ): Result[AristoTxRef,AristoError]
{.noRaise.} {.noRaise.}
@ -358,7 +352,7 @@ type
hasStorageData*: AristoApiHasStorageDataFn hasStorageData*: AristoApiHasStorageDataFn
isTop*: AristoApiIsTopFn isTop*: AristoApiIsTopFn
level*: AristoApiLevelFn txFrameLevel*: AristoApiTxFrameLevelFn
mergeAccountRecord*: AristoApiMergeAccountRecordFn mergeAccountRecord*: AristoApiMergeAccountRecordFn
mergeStorageData*: AristoApiMergeStorageDataFn mergeStorageData*: AristoApiMergeStorageDataFn
@ -373,9 +367,8 @@ type
pathAsBlob*: AristoApiPathAsBlobFn pathAsBlob*: AristoApiPathAsBlobFn
persist*: AristoApiPersistFn persist*: AristoApiPersistFn
rollback*: AristoApiRollbackFn rollback*: AristoApiRollbackFn
txBegin*: AristoApiTxBeginFn txFrameBegin*: AristoApiTxFrameBeginFn
txLevel*: AristoApiTxLevelFn txFrameTop*: AristoApiTxFrameTopFn
txTop*: AristoApiTxTopFn
AristoApiProfNames* = enum AristoApiProfNames* = enum
@ -414,9 +407,8 @@ type
AristoApiProfPathAsBlobFn = "pathAsBlob" AristoApiProfPathAsBlobFn = "pathAsBlob"
AristoApiProfPersistFn = "persist" AristoApiProfPersistFn = "persist"
AristoApiProfRollbackFn = "rollback" AristoApiProfRollbackFn = "rollback"
AristoApiProfTxBeginFn = "txBegin" AristoApiProfTxFrameBeginFn = "txFrameBegin"
AristoApiProfTxLevelFn = "txLevel" AristoApiProfTxFrameTopFn = "txFrameTop"
AristoApiProfTxTopFn = "txTop"
AristoApiProfBeGetVtxFn = "be/getVtx" AristoApiProfBeGetVtxFn = "be/getVtx"
AristoApiProfBeGetKeyFn = "be/getKey" AristoApiProfBeGetKeyFn = "be/getKey"
@ -471,9 +463,8 @@ when AutoValidateApiHooks:
doAssert not api.pathAsBlob.isNil doAssert not api.pathAsBlob.isNil
doAssert not api.persist.isNil doAssert not api.persist.isNil
doAssert not api.rollback.isNil doAssert not api.rollback.isNil
doAssert not api.txBegin.isNil doAssert not api.txFrameBegin.isNil
doAssert not api.txLevel.isNil doAssert not api.txFrameTop.isNil
doAssert not api.txTop.isNil
proc validate(prf: AristoApiProfRef) = proc validate(prf: AristoApiProfRef) =
prf.AristoApiRef.validate prf.AristoApiRef.validate
@ -520,7 +511,7 @@ func init*(api: var AristoApiObj) =
api.hasStorageData = hasStorageData api.hasStorageData = hasStorageData
api.isTop = isTop api.isTop = isTop
api.level = level api.txFrameLevel = txFrameLevel
api.mergeAccountRecord = mergeAccountRecord api.mergeAccountRecord = mergeAccountRecord
api.mergeStorageData = mergeStorageData api.mergeStorageData = mergeStorageData
@ -533,9 +524,8 @@ func init*(api: var AristoApiObj) =
api.pathAsBlob = pathAsBlob api.pathAsBlob = pathAsBlob
api.persist = persist api.persist = persist
api.rollback = rollback api.rollback = rollback
api.txBegin = txBegin api.txFrameBegin = txFrameBegin
api.txLevel = txLevel api.txFrameTop = txFrameTop
api.txTop = txTop
when AutoValidateApiHooks: when AutoValidateApiHooks:
api.validate api.validate
@ -564,7 +554,7 @@ func dup*(api: AristoApiRef): AristoApiRef =
hasStorageData: api.hasStorageData, hasStorageData: api.hasStorageData,
isTop: api.isTop, isTop: api.isTop,
level: api.level, txFrameLevel: api.txFrameLevel,
mergeAccountRecord: api.mergeAccountRecord, mergeAccountRecord: api.mergeAccountRecord,
mergeStorageData: api.mergeStorageData, mergeStorageData: api.mergeStorageData,
@ -577,9 +567,8 @@ func dup*(api: AristoApiRef): AristoApiRef =
pathAsBlob: api.pathAsBlob, pathAsBlob: api.pathAsBlob,
persist: api.persist, persist: api.persist,
rollback: api.rollback, rollback: api.rollback,
txBegin: api.txBegin, txFrameBegin: api.txFrameBegin,
txLevel: api.txLevel, txFrameTop: api.txFrameTop)
txTop: api.txTop)
when AutoValidateApiHooks: when AutoValidateApiHooks:
result.validate result.validate
@ -730,20 +719,15 @@ func init*(
AristoApiProfRollbackFn.profileRunner: AristoApiProfRollbackFn.profileRunner:
result = api.rollback(a) result = api.rollback(a)
profApi.txBegin = profApi.txFrameBegin =
proc(a: AristoDbRef): auto = proc(a: AristoDbRef): auto =
AristoApiProfTxBeginFn.profileRunner: AristoApiProfTxFrameBeginFn.profileRunner:
result = api.txBegin(a) result = api.txFrameBegin(a)
profApi.txLevel = profApi.txFrameTop =
proc(a: AristoTxRef): auto =
AristoApiProfTxLevelFn.profileRunner:
result = api.txLevel(a)
profApi.txTop =
proc(a: AristoDbRef): auto = proc(a: AristoDbRef): auto =
AristoApiProfTxTopFn.profileRunner: AristoApiProfTxFrameTopFn.profileRunner:
result = api.txTop(a) result = api.txFrameTop(a)
let beDup = be.dup() let beDup = be.dup()
if beDup.isNil: if beDup.isNil:

View File

@ -232,8 +232,8 @@ type
TxArgStaleTx TxArgStaleTx
TxArgsUseless TxArgsUseless
TxBackendNotWritable TxBackendNotWritable
TxLevelTooDeep TxFrameLevelTooDeep
TxLevelUseless TxFrameLevelUseless
TxNoPendingTx TxNoPendingTx
TxNotFound TxNotFound
TxNotTopTx TxNotTopTx

View File

@ -18,26 +18,7 @@ import
./aristo_tx/[tx_frame, tx_stow], ./aristo_tx/[tx_frame, tx_stow],
./aristo_desc ./aristo_desc
# ------------------------------------------------------------------------------ export tx_frame
# Public functions, getters
# ------------------------------------------------------------------------------
func txTop*(db: AristoDbRef): Result[AristoTxRef,AristoError] =
## Getter, returns top level transaction if there is any.
db.txFrameTop()
func isTop*(tx: AristoTxRef): bool =
## Getter, returns `true` if the argument `tx` referes to the current top
## level transaction.
tx.txFrameIsTop()
func txLevel*(tx: AristoTxRef): int =
## Getter, positive nesting level of transaction argument `tx`
tx.txFrameLevel()
func level*(db: AristoDbRef): int =
## Getter, non-negative nesting level (i.e. number of pending transactions)
db.txFrameLevel()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions # Public functions
@ -51,51 +32,6 @@ func to*(tx: AristoTxRef; T: type[AristoDbRef]): T =
# Public functions: Transaction frame # Public functions: Transaction frame
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc txBegin*(db: AristoDbRef): Result[AristoTxRef,AristoError] =
## Starts a new transaction.
##
## Example:
## ::
## proc doSomething(db: AristoDbRef) =
## let tx = db.begin
## defer: tx.rollback()
## ... continue using db ...
## tx.commit()
##
db.txFrameBegin()
proc rollback*(
tx: AristoTxRef; # Top transaction on database
): Result[void,AristoError] =
## Given a *top level* handle, this function discards all database operations
## performed for this transactio. The previous transaction is returned if
## there was any.
##
tx.txFrameRollback()
proc commit*(
tx: AristoTxRef; # Top transaction on database
): Result[void,AristoError] =
## Given a *top level* handle, this function accepts all database operations
## performed through this handle and merges it to the previous layer. The
## previous transaction is returned if there was any.
##
tx.txFrameCommit()
proc collapse*(
tx: AristoTxRef; # Top transaction on database
commit: bool; # Commit if `true`, otherwise roll back
): Result[void,AristoError] =
## Iterated application of `commit()` or `rollback()` performing the
## something similar to
## ::
## while true:
## discard tx.commit() # ditto for rollback()
## if db.txTop.isErr: break
## tx = db.txTop.value
##
tx.txFrameCollapse commit
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions: save to database # Public functions: save to database
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -119,20 +55,7 @@ proc persist*(
## next recovery journal record. If non-zero, this ID must be greater than ## next recovery journal record. If non-zero, this ID must be greater than
## all previous IDs (e.g. block number when stowing after block execution.) ## all previous IDs (e.g. block number when stowing after block execution.)
## ##
db.txStow(nxtSid, persistent=true) db.txPersist(nxtSid)
proc stow*(
db: AristoDbRef; # Database
): Result[void,AristoError] =
## This function is similar to `persist()` stopping short of performing the
## final step storing on the persistent database. It fails if there is a
## pending transaction.
##
## The function merges all staged data from the top layer cache onto the
## backend stage area and leaves it there. This function can be seen as
## a sort of a bottom level transaction `commit()`.
##
db.txStow(nxtSid=0u64, persistent=false)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# End # End

View File

@ -17,14 +17,14 @@ import
results, results,
".."/[aristo_desc, aristo_layers] ".."/[aristo_desc, aristo_layers]
func txFrameIsTop*(tx: AristoTxRef): bool func isTop*(tx: AristoTxRef): bool
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Private helpers # Private helpers
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func getDbDescFromTopTx(tx: AristoTxRef): Result[AristoDbRef,AristoError] = func getDbDescFromTopTx(tx: AristoTxRef): Result[AristoDbRef,AristoError] =
if not tx.txFrameIsTop(): if not tx.isTop():
return err(TxNotTopTx) return err(TxNotTopTx)
let db = tx.db let db = tx.db
if tx.level != db.stack.len: if tx.level != db.stack.len:
@ -48,15 +48,11 @@ func txFrameTop*(db: AristoDbRef): Result[AristoTxRef,AristoError] =
else: else:
ok(db.txRef) ok(db.txRef)
func txFrameIsTop*(tx: AristoTxRef): bool = func isTop*(tx: AristoTxRef): bool =
## Getter, returns `true` if the argument `tx` referes to the current top ## Getter, returns `true` if the argument `tx` referes to the current top
## level transaction. ## level transaction.
tx.db.txRef == tx and tx.db.top.txUid == tx.txUid tx.db.txRef == tx and tx.db.top.txUid == tx.txUid
func txFrameLevel*(tx: AristoTxRef): int =
## Getter, positive nesting level of transaction argument `tx`
tx.level
func txFrameLevel*(db: AristoDbRef): int = func txFrameLevel*(db: AristoDbRef): int =
## Getter, non-negative nesting level (i.e. number of pending transactions) ## Getter, non-negative nesting level (i.e. number of pending transactions)
if not db.txRef.isNil: if not db.txRef.isNil:
@ -95,7 +91,7 @@ proc txFrameBegin*(db: AristoDbRef): Result[AristoTxRef,AristoError] =
ok db.txRef ok db.txRef
proc txFrameRollback*( proc rollback*(
tx: AristoTxRef; # Top transaction on database tx: AristoTxRef; # Top transaction on database
): Result[void,AristoError] = ): Result[void,AristoError] =
## Given a *top level* handle, this function discards all database operations ## Given a *top level* handle, this function discards all database operations
@ -112,7 +108,7 @@ proc txFrameRollback*(
ok() ok()
proc txFrameCommit*( proc commit*(
tx: AristoTxRef; # Top transaction on database tx: AristoTxRef; # Top transaction on database
): Result[void,AristoError] = ): Result[void,AristoError] =
## Given a *top level* handle, this function accepts all database operations ## Given a *top level* handle, this function accepts all database operations
@ -139,7 +135,7 @@ proc txFrameCommit*(
ok() ok()
proc txFrameCollapse*( proc collapse*(
tx: AristoTxRef; # Top transaction on database tx: AristoTxRef; # Top transaction on database
commit: bool; # Commit if `true`, otherwise roll back commit: bool; # Commit if `true`, otherwise roll back
): Result[void,AristoError] = ): Result[void,AristoError] =
@ -148,8 +144,8 @@ proc txFrameCollapse*(
## :: ## ::
## while true: ## while true:
## discard tx.commit() # ditto for rollback() ## discard tx.commit() # ditto for rollback()
## if db.txTop.isErr: break ## if db.txFrameTop.isErr: break
## tx = db.txTop.value ## tx = db.txFrameTop.value
## ##
let db = ? tx.getDbDescFromTopTx() let db = ? tx.getDbDescFromTopTx()
@ -162,7 +158,7 @@ proc txFrameCollapse*(
# Public iterators # Public iterators
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
iterator txFrameWalk*(tx: AristoTxRef): (int,AristoTxRef,LayerRef,AristoError) = iterator walk*(tx: AristoTxRef): (int,AristoTxRef,LayerRef,AristoError) =
## Walk down the transaction stack chain. ## Walk down the transaction stack chain.
let db = tx.db let db = tx.db
var tx = tx var tx = tx

View File

@ -8,7 +8,7 @@
# at your option. This file may not be copied, modified, or distributed # at your option. This file may not be copied, modified, or distributed
# except according to those terms. # except according to those terms.
## Aristo DB -- Transaction stow/save helper ## Aristo DB -- Transaction save helper
## ========================================= ## =========================================
## ##
{.push raises: [].} {.push raises: [].}
@ -22,15 +22,14 @@ import
# Private functions # Private functions
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc txStowOk*( proc txPersistOk*(
db: AristoDbRef; # Database db: AristoDbRef; # Database
persistent: bool; # Stage only unless `true`
): Result[void,AristoError] = ): Result[void,AristoError] =
if not db.txRef.isNil: if not db.txRef.isNil:
return err(TxPendingTx) return err(TxPendingTx)
if 0 < db.stack.len: if 0 < db.stack.len:
return err(TxStackGarbled) return err(TxStackGarbled)
if persistent and not db.deltaPersistentOk(): if not db.deltaPersistentOk():
return err(TxBackendNotWritable) return err(TxBackendNotWritable)
ok() ok()
@ -38,14 +37,13 @@ proc txStowOk*(
# Public functions # Public functions
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc txStow*( proc txPersist*(
db: AristoDbRef; # Database db: AristoDbRef; # Database
nxtSid: uint64; # Next state ID (aka block number) nxtSid: uint64; # Next state ID (aka block number)
persistent: bool; # Stage only unless `true`
): Result[void,AristoError] = ): Result[void,AristoError] =
## Worker for `stow()` and `persist()` variants. ## Worker for `persist()` variants.
## ##
? db.txStowOk persistent ? db.txPersistOk()
if not db.top.isEmpty(): if not db.top.isEmpty():
# Note that `deltaMerge()` will return the `db.top` argument if the # Note that `deltaMerge()` will return the `db.top` argument if the
@ -57,7 +55,6 @@ proc txStow*(
# New empty top layer # New empty top layer
db.top = LayerRef(vTop: db.balancer.vTop) db.top = LayerRef(vTop: db.balancer.vTop)
if persistent:
# Merge/move `balancer` into persistent tables (unless missing) # Merge/move `balancer` into persistent tables (unless missing)
? db.deltaPersistent nxtSid ? db.deltaPersistent nxtSid

View File

@ -107,7 +107,7 @@ proc persistent*(
if rc.isOk or rc.error == TxPersistDelayed: if rc.isOk or rc.error == TxPersistDelayed:
# The latter clause is OK: Piggybacking on `Aristo` backend # The latter clause is OK: Piggybacking on `Aristo` backend
discard discard
elif CoreDbKvtRef(db.ctx).call(level, db.ctx.kvt) != 0: elif CoreDbKvtRef(db.ctx).call(txFrameLevel, db.ctx.kvt) != 0:
result = err(rc.error.toError($api, TxPending)) result = err(rc.error.toError($api, TxPending))
break body break body
else: else:
@ -651,37 +651,30 @@ proc recast*(
# Public transaction related methods # Public transaction related methods
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc level*(db: CoreDbRef): int = proc txFrameLevel*(db: CoreDbRef): int =
## Retrieve transaction level (zero if there is no pending transaction). ## Retrieve transaction level (zero if there is no pending transaction).
## ##
db.setTrackNewApi BaseLevelFn db.setTrackNewApi BaseLevelFn
result = CoreDbAccRef(db.ctx).call(level, db.ctx.mpt) result = CoreDbAccRef(db.ctx).call(txFrameLevel, db.ctx.mpt)
db.ifTrackNewApi: debug logTxt, api, elapsed, result db.ifTrackNewApi: debug logTxt, api, elapsed, result
proc newTransaction*(ctx: CoreDbCtxRef): CoreDbTxRef = proc txFrameBegin*(ctx: CoreDbCtxRef): CoreDbTxRef =
## Constructor ## Constructor
## ##
ctx.setTrackNewApi BaseNewTxFn ctx.setTrackNewApi BaseNewTxFn
let let
kTx = CoreDbKvtRef(ctx).call(txBegin, ctx.kvt).valueOr: kTx = CoreDbKvtRef(ctx).call(txFrameBegin, ctx.kvt).valueOr:
raiseAssert $api & ": " & $error raiseAssert $api & ": " & $error
aTx = CoreDbAccRef(ctx).call(txBegin, ctx.mpt).valueOr: aTx = CoreDbAccRef(ctx).call(txFrameBegin, ctx.mpt).valueOr:
raiseAssert $api & ": " & $error raiseAssert $api & ": " & $error
result = ctx.bless CoreDbTxRef(kTx: kTx, aTx: aTx) result = ctx.bless CoreDbTxRef(kTx: kTx, aTx: aTx)
ctx.ifTrackNewApi: ctx.ifTrackNewApi:
let newLevel = CoreDbAccRef(ctx).call(level, ctx.mpt) let newLevel = CoreDbAccRef(ctx).call(level, ctx.mpt)
debug logTxt, api, elapsed, newLevel debug logTxt, api, elapsed, newLevel
proc level*(tx: CoreDbTxRef): int =
## Print positive transaction level for argument `tx`
##
tx.setTrackNewApi TxLevelFn
result = CoreDbAccRef(tx.ctx).call(txLevel, tx.aTx)
tx.ifTrackNewApi: debug logTxt, api, elapsed, result
proc commit*(tx: CoreDbTxRef) = proc commit*(tx: CoreDbTxRef) =
tx.setTrackNewApi TxCommitFn: tx.setTrackNewApi TxCommitFn:
let prvLevel {.used.} = CoreDbAccRef(tx.ctx).call(txLevel, tx.aTx) let prvLevel {.used.} = CoreDbAccRef(tx.ctx).call(level, tx.aTx)
CoreDbAccRef(tx.ctx).call(commit, tx.aTx).isOkOr: CoreDbAccRef(tx.ctx).call(commit, tx.aTx).isOkOr:
raiseAssert $api & ": " & $error raiseAssert $api & ": " & $error
CoreDbKvtRef(tx.ctx).call(commit, tx.kTx).isOkOr: CoreDbKvtRef(tx.ctx).call(commit, tx.kTx).isOkOr:
@ -690,7 +683,7 @@ proc commit*(tx: CoreDbTxRef) =
proc rollback*(tx: CoreDbTxRef) = proc rollback*(tx: CoreDbTxRef) =
tx.setTrackNewApi TxRollbackFn: tx.setTrackNewApi TxRollbackFn:
let prvLevel {.used.} = CoreDbAccRef(tx.ctx).call(txLevel, tx.aTx) let prvLevel {.used.} = CoreDbAccRef(tx.ctx).call(level, tx.aTx)
CoreDbAccRef(tx.ctx).call(rollback, tx.aTx).isOkOr: CoreDbAccRef(tx.ctx).call(rollback, tx.aTx).isOkOr:
raiseAssert $api & ": " & $error raiseAssert $api & ": " & $error
CoreDbKvtRef(tx.ctx).call(rollback, tx.kTx).isOkOr: CoreDbKvtRef(tx.ctx).call(rollback, tx.kTx).isOkOr:
@ -699,7 +692,7 @@ proc rollback*(tx: CoreDbTxRef) =
proc dispose*(tx: CoreDbTxRef) = proc dispose*(tx: CoreDbTxRef) =
tx.setTrackNewApi TxDisposeFn: tx.setTrackNewApi TxDisposeFn:
let prvLevel {.used.} = CoreDbAccRef(tx.ctx).call(txLevel, tx.aTx) let prvLevel {.used.} = CoreDbAccRef(tx.ctx).call(level, tx.aTx)
if CoreDbAccRef(tx.ctx).call(isTop, tx.aTx): if CoreDbAccRef(tx.ctx).call(isTop, tx.aTx):
CoreDbAccRef(tx.ctx).call(rollback, tx.aTx).isOkOr: CoreDbAccRef(tx.ctx).call(rollback, tx.aTx).isOkOr:
raiseAssert $api & ": " & $error raiseAssert $api & ": " & $error

View File

@ -52,7 +52,7 @@ type
BaseFinishFn = "finish" BaseFinishFn = "finish"
BaseLevelFn = "level" BaseLevelFn = "level"
BasePushCaptureFn = "pushCapture" BasePushCaptureFn = "pushCapture"
BaseNewTxFn = "newTransaction" BaseNewTxFn = "txFrameBegin"
BasePersistentFn = "persistent" BasePersistentFn = "persistent"
BaseStateBlockNumberFn = "stateBlockNumber" BaseStateBlockNumberFn = "stateBlockNumber"
BaseVerifyFn = "verify" BaseVerifyFn = "verify"
@ -77,7 +77,7 @@ type
TxCommitFn = "commit" TxCommitFn = "commit"
TxDisposeFn = "dispose" TxDisposeFn = "dispose"
TxLevelFn = "level" TxFrameLevelFn = "level"
TxRollbackFn = "rollback" TxRollbackFn = "rollback"
TxSaveDisposeFn = "safeDispose" TxSaveDisposeFn = "safeDispose"

View File

@ -52,14 +52,14 @@ type
KvtApiHasKeyRcFn* = proc(db: KvtDbRef, KvtApiHasKeyRcFn* = proc(db: KvtDbRef,
key: openArray[byte]): Result[bool,KvtError] {.noRaise.} key: openArray[byte]): Result[bool,KvtError] {.noRaise.}
KvtApiIsTopFn* = proc(tx: KvtTxRef): bool {.noRaise.} KvtApiIsTopFn* = proc(tx: KvtTxRef): bool {.noRaise.}
KvtApiLevelFn* = proc(db: KvtDbRef): int {.noRaise.} KvtApiTxFrameLevelFn* = proc(db: KvtDbRef): int {.noRaise.}
KvtApiPutFn* = proc(db: KvtDbRef, KvtApiPutFn* = proc(db: KvtDbRef,
key, data: openArray[byte]): Result[void,KvtError] {.noRaise.} key, data: openArray[byte]): Result[void,KvtError] {.noRaise.}
KvtApiRollbackFn* = proc(tx: KvtTxRef): Result[void,KvtError] {.noRaise.} KvtApiRollbackFn* = proc(tx: KvtTxRef): Result[void,KvtError] {.noRaise.}
KvtApiPersistFn* = proc(db: KvtDbRef): Result[void,KvtError] {.noRaise.} KvtApiPersistFn* = proc(db: KvtDbRef): Result[void,KvtError] {.noRaise.}
KvtApiToKvtDbRefFn* = proc(tx: KvtTxRef): KvtDbRef {.noRaise.} KvtApiToKvtDbRefFn* = proc(tx: KvtTxRef): KvtDbRef {.noRaise.}
KvtApiTxBeginFn* = proc(db: KvtDbRef): Result[KvtTxRef,KvtError] {.noRaise.} KvtApiTxFrameBeginFn* = proc(db: KvtDbRef): Result[KvtTxRef,KvtError] {.noRaise.}
KvtApiTxTopFn* = KvtApiTxFrameTopFn* =
proc(db: KvtDbRef): Result[KvtTxRef,KvtError] {.noRaise.} proc(db: KvtDbRef): Result[KvtTxRef,KvtError] {.noRaise.}
KvtApiRef* = ref KvtApiObj KvtApiRef* = ref KvtApiObj
@ -73,13 +73,13 @@ type
len*: KvtApiLenFn len*: KvtApiLenFn
hasKeyRc*: KvtApiHasKeyRcFn hasKeyRc*: KvtApiHasKeyRcFn
isTop*: KvtApiIsTopFn isTop*: KvtApiIsTopFn
level*: KvtApiLevelFn txFrameLevel*: KvtApiTxFrameLevelFn
put*: KvtApiPutFn put*: KvtApiPutFn
rollback*: KvtApiRollbackFn rollback*: KvtApiRollbackFn
persist*: KvtApiPersistFn persist*: KvtApiPersistFn
toKvtDbRef*: KvtApiToKvtDbRefFn toKvtDbRef*: KvtApiToKvtDbRefFn
txBegin*: KvtApiTxBeginFn txFrameBegin*: KvtApiTxFrameBeginFn
txTop*: KvtApiTxTopFn txFrameTop*: KvtApiTxFrameTopFn
KvtApiProfNames* = enum KvtApiProfNames* = enum
@ -98,8 +98,8 @@ type
KvtApiProfRollbackFn = "rollback" KvtApiProfRollbackFn = "rollback"
KvtApiProfPersistFn = "persist" KvtApiProfPersistFn = "persist"
KvtApiProfToKvtDbRefFn = "toKvtDbRef" KvtApiProfToKvtDbRefFn = "toKvtDbRef"
KvtApiProfTxBeginFn = "txBegin" KvtApiProfTxFrameBeginFn = "txFrameBegin"
KvtApiProfTxTopFn = "txTop" KvtApiProfTxFrameTopFn = "txFrameTop"
KvtApiProfBeGetKvpFn = "be/getKvp" KvtApiProfBeGetKvpFn = "be/getKvp"
KvtApiProfBeLenKvpFn = "be/lenKvp" KvtApiProfBeLenKvpFn = "be/lenKvp"
@ -123,13 +123,13 @@ when AutoValidateApiHooks:
doAssert not api.get.isNil doAssert not api.get.isNil
doAssert not api.hasKeyRc.isNil doAssert not api.hasKeyRc.isNil
doAssert not api.isTop.isNil doAssert not api.isTop.isNil
doAssert not api.level.isNil doAssert not api.txFrameLevel.isNil
doAssert not api.put.isNil doAssert not api.put.isNil
doAssert not api.rollback.isNil doAssert not api.rollback.isNil
doAssert not api.persist.isNil doAssert not api.persist.isNil
doAssert not api.toKvtDbRef.isNil doAssert not api.toKvtDbRef.isNil
doAssert not api.txBegin.isNil doAssert not api.txFrameBegin.isNil
doAssert not api.txTop.isNil doAssert not api.txFrameTop.isNil
proc validate(prf: KvtApiProfRef) = proc validate(prf: KvtApiProfRef) =
prf.KvtApiRef.validate prf.KvtApiRef.validate
@ -161,13 +161,13 @@ func init*(api: var KvtApiObj) =
api.len = len api.len = len
api.hasKeyRc = hasKeyRc api.hasKeyRc = hasKeyRc
api.isTop = isTop api.isTop = isTop
api.level = level api.txFrameLevel = txFrameLevel
api.put = put api.put = put
api.rollback = rollback api.rollback = rollback
api.persist = persist api.persist = persist
api.toKvtDbRef = toKvtDbRef api.toKvtDbRef = toKvtDbRef
api.txBegin = txBegin api.txFrameBegin = txFrameBegin
api.txTop = txTop api.txFrameTop = txFrameTop
when AutoValidateApiHooks: when AutoValidateApiHooks:
api.validate api.validate
@ -184,16 +184,15 @@ func dup*(api: KvtApiRef): KvtApiRef =
len: api.len, len: api.len,
hasKeyRc: api.hasKeyRc, hasKeyRc: api.hasKeyRc,
isTop: api.isTop, isTop: api.isTop,
level: api.level, txFrameLevel: api.txFrameLevel,
put: api.put, put: api.put,
rollback: api.rollback, rollback: api.rollback,
persist: api.persist, persist: api.persist,
toKvtDbRef: api.toKvtDbRef, toKvtDbRef: api.toKvtDbRef,
txBegin: api.txBegin, txFrameBegin: api.txFrameBegin,
txTop: api.txTop) txFrameTop: api.txFrameTop)
when AutoValidateApiHooks: when AutoValidateApiHooks:
result.validate result.validate
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public profile API constuctor # Public profile API constuctor
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -281,15 +280,15 @@ func init*(
KvtApiProfToKvtDbRefFn.profileRunner: KvtApiProfToKvtDbRefFn.profileRunner:
result = api.toKvtDbRef(a) result = api.toKvtDbRef(a)
profApi.txBegin = profApi.txFrameBegin =
proc(a: KvtDbRef): auto = proc(a: KvtDbRef): auto =
KvtApiProfTxBeginFn.profileRunner: KvtApiProfTxFrameBeginFn.profileRunner:
result = api.txBegin(a) result = api.txFrameBegin(a)
profApi.txTop = profApi.txFrameTop =
proc(a: KvtDbRef): auto = proc(a: KvtDbRef): auto =
KvtApiProfTxTopFn.profileRunner: KvtApiProfTxFrameTopFn.profileRunner:
result = api.txTop(a) result = api.txFrameTop(a)
let beDup = be.dup() let beDup = be.dup()
if beDup.isNil: if beDup.isNil:

View File

@ -33,8 +33,8 @@ type
# Transaction wrappers # Transaction wrappers
TxArgStaleTx TxArgStaleTx
TxBackendNotWritable TxBackendNotWritable
TxLevelTooDeep TxFrameLevelTooDeep
TxLevelUseless TxFrameLevelUseless
TxNoPendingTx TxNoPendingTx
TxNotTopTx TxNotTopTx
TxPendingTx TxPendingTx

View File

@ -185,11 +185,11 @@ proc putEndTriggeredFn(db: RdbBackendRef): PutEndFn =
when extraTraceMessages: when extraTraceMessages:
debug logTxt "putEndTriggeredFn: failed", debug logTxt "putEndTriggeredFn: failed",
error=hdl.error, info=hdl.info error=hdl.error, info=hdl.info
# The error return code will signal a problem to the `txStow()` # The error return code will signal a problem to the `txPersist()`
# function which was called by `writeEvCb()` below. # function which was called by `writeEvCb()` below.
return err(hdl.error) return err(hdl.error)
# Commit the session. This will be acknowledged by the `txStow()` # Commit the session. This will be acknowledged by the `txPersist()`
# function which was called by `writeEvCb()` below. # function which was called by `writeEvCb()` below.
ok() ok()
@ -229,22 +229,22 @@ proc writeEvCb(db: RdbBackendRef): RdbWriteEventCb =
# Publish session argument # Publish session argument
db.rdb.session = ws db.rdb.session = ws
# Execute delayed session. Note the the `txStow()` function is located # Execute delayed session. Note the the `txPersist()` function is located
# in `tx_stow.nim`. This module `tx_stow.nim` is also imported by # in `tx_stow.nim`. This module `tx_stow.nim` is also imported by
# `kvt_tx.nim` which contains `persist() `. So the logic goes: # `kvt_tx.nim` which contains `persist() `. So the logic goes:
# :: # ::
# kvt_tx.persist() --> registers a delayed write request rather # kvt_tx.persist() --> registers a delayed write request rather
# than excuting tx_stow.txStow() # than excuting tx_stow.txPersist()
# #
# // the backend owner (i.e. Aristo) will start a write cycle and # // the backend owner (i.e. Aristo) will start a write cycle and
# // invoke the envent handler rocks_db.writeEvCb() # // invoke the envent handler rocks_db.writeEvCb()
# rocks_db.writeEvCb() --> calls tx_stow.txStow() # rocks_db.writeEvCb() --> calls tx_stow.txPersist()
# #
# tx_stow.txStow() --> calls rocks_db.putBegTriggeredFn() # tx_stow.txPersist() --> calls rocks_db.putBegTriggeredFn()
# calls rocks_db.putKvpFn() # calls rocks_db.putKvpFn()
# calls rocks_db.putEndTriggeredFn() # calls rocks_db.putEndTriggeredFn()
# #
let rc = db.rdb.delayedPersist.txStow(persistent=true) let rc = db.rdb.delayedPersist.txPersist()
if rc.isErr: if rc.isErr:
error "writeEventCb(): persist() failed", error=rc.error error "writeEventCb(): persist() failed", error=rc.error
return false return false

View File

@ -19,26 +19,8 @@ import
./kvt_init/memory_only, ./kvt_init/memory_only,
./kvt_desc ./kvt_desc
# ------------------------------------------------------------------------------ export tx_frame
# Public functions, getters
# ------------------------------------------------------------------------------
func txTop*(db: KvtDbRef): Result[KvtTxRef,KvtError] =
## Getter, returns top level transaction if there is any.
db.txFrameTop()
func isTop*(tx: KvtTxRef): bool =
## Getter, returns `true` if the argument `tx` referes to the current top
## level transaction.
tx.txFrameIsTop()
func txLevel*(tx: KvtTxRef): int =
## Getter, positive nesting level of transaction argument `tx`
tx.txFrameLevel()
func level*(db: KvtDbRef): int =
## Getter, non-negative nesting level (i.e. number of pending transactions)
db.txFrameLevel()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions # Public functions
@ -52,55 +34,6 @@ func toKvtDbRef*(tx: KvtTxRef): KvtDbRef =
## Same as `.to(KvtDbRef)` ## Same as `.to(KvtDbRef)`
tx.db tx.db
# ------------------------------------------------------------------------------
# Public functions: Transaction frame
# ------------------------------------------------------------------------------
proc txBegin*(db: KvtDbRef): Result[KvtTxRef,KvtError] =
## Starts a new transaction.
##
## Example:
## ::
## proc doSomething(db: KvtDbRef) =
## let tx = db.txBegin
## defer: tx.rollback()
## ... continue using db ...
## tx.commit()
##
db.txFrameBegin()
proc rollback*(
tx: KvtTxRef; # Top transaction on database
): Result[void,KvtError] =
## Given a *top level* handle, this function discards all database operations
## performed for this transactio. The previous transaction is returned if
## there was any.
##
tx.txFrameRollback()
proc commit*(
tx: KvtTxRef; # Top transaction on database
): Result[void,KvtError] =
## Given a *top level* handle, this function accepts all database operations
## performed through this handle and merges it to the previous layer. The
## previous transaction is returned if there was any.
##
tx.txFrameCommit()
proc collapse*(
tx: KvtTxRef; # Top transaction on database
commit: bool; # Commit if `true`, otherwise roll back
): Result[void,KvtError] =
## Iterated application of `commit()` or `rollback()` performing the
## something similar to
## ::
## while true:
## discard tx.commit() # ditto for rollback()
## if db.topTx.isErr: break
## tx = db.topTx.value
##
tx.txFrameCollapse commit
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions: save database # Public functions: save database
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -121,24 +54,11 @@ proc persist*(
## ##
# Register for saving if piggybacked on remote database # Register for saving if piggybacked on remote database
if db.backend.kind == BackendRdbTriggered: if db.backend.kind == BackendRdbTriggered:
? db.txStowOk(persistent=true) ? db.txPersistOk()
? db.backend.setWrReqFn db ? db.backend.setWrReqFn db
return err(TxPersistDelayed) return err(TxPersistDelayed)
db.txStow(persistent=true) db.txPersist()
proc stow*(
db: KvtDbRef; # Database
): Result[void,KvtError] =
## This function is similar to `persist()` stopping short of performing the
## final step storing on the persistent database. It fails if there is a
## pending transaction.
##
## The function merges all staged data from the top layer cache onto the
## backend stage area and leaves it there. This function can be seen as
## a sort of a bottom level transaction `commit()`.
##
db.txStow(persistent=false)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# End # End

View File

@ -18,14 +18,14 @@ import
results, results,
".."/[kvt_desc, kvt_layers] ".."/[kvt_desc, kvt_layers]
func txFrameIsTop*(tx: KvtTxRef): bool func isTop*(tx: KvtTxRef): bool
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Private helpers # Private helpers
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
func getDbDescFromTopTx(tx: KvtTxRef): Result[KvtDbRef,KvtError] = func getDbDescFromTopTx(tx: KvtTxRef): Result[KvtDbRef,KvtError] =
if not tx.txFrameIsTop(): if not tx.isTop():
return err(TxNotTopTx) return err(TxNotTopTx)
let db = tx.db let db = tx.db
if tx.level != db.stack.len: if tx.level != db.stack.len:
@ -49,15 +49,11 @@ func txFrameTop*(db: KvtDbRef): Result[KvtTxRef,KvtError] =
else: else:
ok(db.txRef) ok(db.txRef)
func txFrameIsTop*(tx: KvtTxRef): bool = func isTop*(tx: KvtTxRef): bool =
## Getter, returns `true` if the argument `tx` referes to the current top ## Getter, returns `true` if the argument `tx` referes to the current top
## level transaction. ## level transaction.
tx.db.txRef == tx and tx.db.top.txUid == tx.txUid tx.db.txRef == tx and tx.db.top.txUid == tx.txUid
func txFrameLevel*(tx: KvtTxRef): int =
## Getter, positive nesting level of transaction argument `tx`
tx.level
func txFrameLevel*(db: KvtDbRef): int = func txFrameLevel*(db: KvtDbRef): int =
## Getter, non-negative nesting level (i.e. number of pending transactions) ## Getter, non-negative nesting level (i.e. number of pending transactions)
if not db.txRef.isNil: if not db.txRef.isNil:
@ -93,7 +89,7 @@ proc txFrameBegin*(db: KvtDbRef): Result[KvtTxRef,KvtError] =
ok db.txRef ok db.txRef
proc txFrameRollback*( proc rollback*(
tx: KvtTxRef; # Top transaction on database tx: KvtTxRef; # Top transaction on database
): Result[void,KvtError] = ): Result[void,KvtError] =
## Given a *top level* handle, this function discards all database operations ## Given a *top level* handle, this function discards all database operations
@ -110,7 +106,7 @@ proc txFrameRollback*(
ok() ok()
proc txFrameCommit*( proc commit*(
tx: KvtTxRef; # Top transaction on database tx: KvtTxRef; # Top transaction on database
): Result[void,KvtError] = ): Result[void,KvtError] =
## Given a *top level* handle, this function accepts all database operations ## Given a *top level* handle, this function accepts all database operations
@ -135,7 +131,7 @@ proc txFrameCommit*(
ok() ok()
proc txFrameCollapse*( proc collapse*(
tx: KvtTxRef; # Top transaction on database tx: KvtTxRef; # Top transaction on database
commit: bool; # Commit if `true`, otherwise roll back commit: bool; # Commit if `true`, otherwise roll back
): Result[void,KvtError] = ): Result[void,KvtError] =

View File

@ -8,7 +8,7 @@
# at your option. This file may not be copied, modified, or distributed # at your option. This file may not be copied, modified, or distributed
# except according to those terms. # except according to those terms.
## Kvt DB -- Transaction stow/save helper ## Kvt DB -- Transaction save helper
## ====================================== ## ======================================
## ##
{.push raises: [].} {.push raises: [].}
@ -23,22 +23,20 @@ import
# Public functions # Public functions
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc txStowOk*( proc txPersistOk*(
db: KvtDbRef; # Database db: KvtDbRef; # Database
persistent: bool; # Stage only unless `true`
): Result[void,KvtError] = ): Result[void,KvtError] =
## Verify that `txStow()` can go ahead ## Verify that `txPersist()` can go ahead
if not db.txRef.isNil: if not db.txRef.isNil:
return err(TxPendingTx) return err(TxPendingTx)
if 0 < db.stack.len: if 0 < db.stack.len:
return err(TxStackGarbled) return err(TxStackGarbled)
if persistent and not db.deltaPersistentOk(): if not db.deltaPersistentOk():
return err(TxBackendNotWritable) return err(TxBackendNotWritable)
ok() ok()
proc txStow*( proc txPersist*(
db: KvtDbRef; # Database db: KvtDbRef; # Database
persistent: bool; # Stage only unless `true`
): Result[void,KvtError] = ): Result[void,KvtError] =
## The function saves the data from the top layer cache into the ## The function saves the data from the top layer cache into the
## backend database. ## backend database.
@ -46,7 +44,7 @@ proc txStow*(
## If there is no backend the function returns immediately with an error. ## If there is no backend the function returns immediately with an error.
## The same happens if there is a pending transaction. ## The same happens if there is a pending transaction.
## ##
? db.txStowOk persistent ? db.txPersistOk()
if 0 < db.top.sTab.len: if 0 < db.top.sTab.len:
# Note that `deltaMerge()` will return the `db.top` argument if the # Note that `deltaMerge()` will return the `db.top` argument if the
@ -58,7 +56,6 @@ proc txStow*(
# New empty top layer # New empty top layer
db.top = LayerRef() db.top = LayerRef()
if persistent:
# Move `balancer` data into persistent tables # Move `balancer` data into persistent tables
? db.deltaPersistent() ? db.deltaPersistent()

View File

@ -81,7 +81,7 @@ proc dbStoreSyncStateLayout*(ctx: BeaconCtxRef; info: static[string]) =
# While executing blocks there are frequent save cycles. Otherwise, an # While executing blocks there are frequent save cycles. Otherwise, an
# extra save request might help to pick up an interrupted sync session. # extra save request might help to pick up an interrupted sync session.
if ctx.db.level() == 0 and ctx.stash.len == 0: if ctx.db.txFrameLevel() == 0 and ctx.stash.len == 0:
let number = ctx.db.getSavedStateBlockNumber() let number = ctx.db.getSavedStateBlockNumber()
ctx.db.persistent(number).isOkOr: ctx.db.persistent(number).isOkOr:
raiseAssert info & " persistent() failed: " & $$error raiseAssert info & " persistent() failed: " & $$error
@ -165,9 +165,9 @@ proc dbHeadersStash*(
## .. ## ..
## ##
let let
txLevel = ctx.db.level() txFrameLevel = ctx.db.txFrameLevel()
last = first + revBlobs.len.uint64 - 1 last = first + revBlobs.len.uint64 - 1
if 0 < txLevel: if 0 < txFrameLevel:
# Need to cache it because FCU has blocked writing through to disk. # Need to cache it because FCU has blocked writing through to disk.
for n,data in revBlobs: for n,data in revBlobs:
ctx.stash[last - n.uint64] = data ctx.stash[last - n.uint64] = data

View File

@ -38,7 +38,7 @@ proc rpcCallEvm*(args: TransactionArgs,
let vmState = ? BaseVMState.new(topHeader, com) let vmState = ? BaseVMState.new(topHeader, com)
let params = ? toCallParams(vmState, args, globalGasCap, header.baseFeePerGas) let params = ? toCallParams(vmState, args, globalGasCap, header.baseFeePerGas)
var dbTx = com.db.ctx.newTransaction() var dbTx = com.db.ctx.txFrameBegin()
defer: dbTx.dispose() # always dispose state changes defer: dbTx.dispose() # always dispose state changes
ok(runComputation(params, CallResult)) ok(runComputation(params, CallResult))
@ -50,7 +50,7 @@ proc rpcCallEvm*(args: TransactionArgs,
const globalGasCap = 0 # TODO: globalGasCap should configurable by user const globalGasCap = 0 # TODO: globalGasCap should configurable by user
let params = ? toCallParams(vmState, args, globalGasCap, header.baseFeePerGas) let params = ? toCallParams(vmState, args, globalGasCap, header.baseFeePerGas)
var dbTx = com.db.ctx.newTransaction() var dbTx = com.db.ctx.txFrameBegin()
defer: dbTx.dispose() # always dispose state changes defer: dbTx.dispose() # always dispose state changes
ok(runComputation(params, CallResult)) ok(runComputation(params, CallResult))
@ -75,7 +75,7 @@ proc rpcEstimateGas*(args: TransactionArgs,
hi : GasInt = GasInt args.gas.get(0.Quantity) hi : GasInt = GasInt args.gas.get(0.Quantity)
cap: GasInt cap: GasInt
var dbTx = com.db.ctx.newTransaction() var dbTx = com.db.ctx.txFrameBegin()
defer: dbTx.dispose() # always dispose state changes defer: dbTx.dispose() # always dispose state changes
# Determine the highest gas limit can be used during the estimation. # Determine the highest gas limit can be used during the estimation.

View File

@ -123,7 +123,7 @@ suite "Aristo compute":
check: check:
db.mergeAccountRecord(k, v) == Result[bool, AristoError].ok(true) db.mergeAccountRecord(k, v) == Result[bool, AristoError].ok(true)
check db.txStow(1, true).isOk() check db.txPersist(1).isOk()
check db.computeKeys(root).isOk() check db.computeKeys(root).isOk()

View File

@ -213,10 +213,7 @@ proc schedStow*(
filterMeter = if db.balancer.isNil: 0 filterMeter = if db.balancer.isNil: 0
else: db.balancer.sTab.len + db.balancer.kMap.len else: db.balancer.sTab.len + db.balancer.kMap.len
persistent = MaxFilterBulk < max(layersMeter, filterMeter) persistent = MaxFilterBulk < max(layersMeter, filterMeter)
if persistent:
db.persist() db.persist()
else:
db.stow()
# ------------------ # ------------------

View File

@ -55,7 +55,7 @@ proc saveToBackend(
xCheckRc rc.error == 0 xCheckRc rc.error == 0
block: block:
let rc = db.txTop() let rc = db.txFrameTop()
xCheckRc rc.error == 0 xCheckRc rc.error == 0
tx = rc.value tx = rc.value
@ -72,7 +72,7 @@ proc saveToBackend(
xCheckRc rc.error == 0 xCheckRc rc.error == 0
block: block:
let rc = db.txTop() let rc = db.txFrameTop()
xCheckErr rc.value.level < 0 # force error xCheckErr rc.value.level < 0 # force error
block: block:
@ -80,7 +80,7 @@ proc saveToBackend(
xCheckRc rc.error == 0 xCheckRc rc.error == 0
# Update layers to original level # Update layers to original level
tx = db.txBegin().value.to(AristoDbRef).txBegin().value tx = db.txFrameBegin().value.to(AristoDbRef).txFrameBegin().value
true true
@ -120,7 +120,7 @@ proc testMergeProofAndKvpList*(
# ps = PartStateRef.init(db) # ps = PartStateRef.init(db)
# # Start transaction (double frame for testing) # # Start transaction (double frame for testing)
# tx = ps.db.txBegin().value.to(AristoDbRef).txBegin().value # tx = ps.db.txFrameBegin().value.to(AristoDbRef).txFrameBegin().value
# xCheck tx.isTop() # xCheck tx.isTop()
# # Update root # # Update root

View File

@ -109,7 +109,7 @@ proc randomisedLeafs(
proc innerCleanUp(db: var AristoDbRef): bool {.discardable.} = proc innerCleanUp(db: var AristoDbRef): bool {.discardable.} =
## Defer action ## Defer action
if not db.isNil: if not db.isNil:
let rx = db.txTop() let rx = db.txFrameTop()
if rx.isOk: if rx.isOk:
let rc = rx.value.collapse(commit=false) let rc = rx.value.collapse(commit=false)
xCheckRc rc.error == 0 xCheckRc rc.error == 0
@ -140,7 +140,7 @@ proc saveToBackend(
xCheckRc rc.error == 0 xCheckRc rc.error == 0
block: block:
let rc = db.txTop() let rc = db.txFrameTop()
xCheckRc rc.error == 0 xCheckRc rc.error == 0
tx = rc.value tx = rc.value
@ -157,7 +157,7 @@ proc saveToBackend(
xCheckRc rc.error == 0 xCheckRc rc.error == 0
block: block:
let rc = db.txTop() let rc = db.txFrameTop()
xCheckErr rc.value.level < 0 # force error xCheckErr rc.value.level < 0 # force error
block: block:
@ -170,7 +170,7 @@ proc saveToBackend(
noisy.say "***", "saveToBackend (8)", " debugID=", debugID noisy.say "***", "saveToBackend (8)", " debugID=", debugID
# Update layers to original level # Update layers to original level
tx = db.txBegin().value.to(AristoDbRef).txBegin().value tx = db.txFrameBegin().value.to(AristoDbRef).txFrameBegin().value
true true
@ -268,8 +268,8 @@ proc testTxMergeAndDeleteOneByOne*(
# AristoDbRef.init(MemBackendRef) # AristoDbRef.init(MemBackendRef)
# # Start transaction (double frame for testing) # # Start transaction (double frame for testing)
# xCheck db.txTop.isErr # xCheck db.txFrameTop.isErr
# var tx = db.txBegin().value.to(AristoDbRef).txBegin().value # var tx = db.txFrameBegin().value.to(AristoDbRef).txFrameBegin().value
# xCheck tx.isTop() # xCheck tx.isTop()
# xCheck tx.level == 2 # xCheck tx.level == 2
@ -375,8 +375,8 @@ proc testTxMergeAndDeleteSubTree*(
# AristoDbRef.init(MemBackendRef) # AristoDbRef.init(MemBackendRef)
# # Start transaction (double frame for testing) # # Start transaction (double frame for testing)
# xCheck db.txTop.isErr # xCheck db.txFrameTop.isErr
# var tx = db.txBegin().value.to(AristoDbRef).txBegin().value # var tx = db.txFrameBegin().value.to(AristoDbRef).txFrameBegin().value
# xCheck tx.isTop() # xCheck tx.isTop()
# xCheck tx.level == 2 # xCheck tx.level == 2

View File

@ -116,7 +116,7 @@ proc forkedChainMain*() =
blk2 = cc.makeBlk(2, blk1) blk2 = cc.makeBlk(2, blk1)
blk3 = cc.makeBlk(3, blk2) blk3 = cc.makeBlk(3, blk2)
dbTx = cc.db.ctx.newTransaction() dbTx = cc.db.ctx.txFrameBegin()
blk4 = cc.makeBlk(4, blk3) blk4 = cc.makeBlk(4, blk3)
blk5 = cc.makeBlk(5, blk4) blk5 = cc.makeBlk(5, blk4)
blk6 = cc.makeBlk(6, blk5) blk6 = cc.makeBlk(6, blk5)

View File

@ -212,7 +212,7 @@ proc runTrial3Survive(env: TestEnv, ledger: LedgerRef; inx: int; noisy = false)
let eAddr = env.txs[inx].getRecipient let eAddr = env.txs[inx].getRecipient
block: block:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
block: block:
let accTx = ledger.beginSavepoint let accTx = ledger.beginSavepoint
@ -228,7 +228,7 @@ proc runTrial3Survive(env: TestEnv, ledger: LedgerRef; inx: int; noisy = false)
dbTx.rollback() dbTx.rollback()
block: block:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
block: block:
let accTx = ledger.beginSavepoint let accTx = ledger.beginSavepoint
@ -247,7 +247,7 @@ proc runTrial4(env: TestEnv, ledger: LedgerRef; inx: int; rollback: bool) =
let eAddr = env.txs[inx].getRecipient let eAddr = env.txs[inx].getRecipient
block: block:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
block: block:
let accTx = ledger.beginSavepoint let accTx = ledger.beginSavepoint
@ -277,7 +277,7 @@ proc runTrial4(env: TestEnv, ledger: LedgerRef; inx: int; rollback: bool) =
dbTx.commit() dbTx.commit()
block: block:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
block: block:
let accTx = ledger.beginSavepoint let accTx = ledger.beginSavepoint
@ -350,14 +350,14 @@ proc runLedgerTransactionTests(noisy = true) =
test &"Run {env.txi.len} two-step trials with rollback": test &"Run {env.txi.len} two-step trials with rollback":
for n in env.txi: for n in env.txi:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
defer: dbTx.dispose() defer: dbTx.dispose()
let ledger = env.com.getLedger() let ledger = env.com.getLedger()
env.runTrial2ok(ledger, n) env.runTrial2ok(ledger, n)
test &"Run {env.txi.len} three-step trials with rollback": test &"Run {env.txi.len} three-step trials with rollback":
for n in env.txi: for n in env.txi:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
defer: dbTx.dispose() defer: dbTx.dispose()
let ledger = env.com.getLedger() let ledger = env.com.getLedger()
env.runTrial3(ledger, n, rollback = true) env.runTrial3(ledger, n, rollback = true)
@ -365,21 +365,21 @@ proc runLedgerTransactionTests(noisy = true) =
test &"Run {env.txi.len} three-step trials with extra db frame rollback" & test &"Run {env.txi.len} three-step trials with extra db frame rollback" &
" throwing Exceptions": " throwing Exceptions":
for n in env.txi: for n in env.txi:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
defer: dbTx.dispose() defer: dbTx.dispose()
let ledger = env.com.getLedger() let ledger = env.com.getLedger()
env.runTrial3Survive(ledger, n, noisy) env.runTrial3Survive(ledger, n, noisy)
test &"Run {env.txi.len} tree-step trials without rollback": test &"Run {env.txi.len} tree-step trials without rollback":
for n in env.txi: for n in env.txi:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
defer: dbTx.dispose() defer: dbTx.dispose()
let ledger = env.com.getLedger() let ledger = env.com.getLedger()
env.runTrial3(ledger, n, rollback = false) env.runTrial3(ledger, n, rollback = false)
test &"Run {env.txi.len} four-step trials with rollback and db frames": test &"Run {env.txi.len} four-step trials with rollback and db frames":
for n in env.txi: for n in env.txi:
let dbTx = env.xdb.ctx.newTransaction() let dbTx = env.xdb.ctx.txFrameBegin()
defer: dbTx.dispose() defer: dbTx.dispose()
let ledger = env.com.getLedger() let ledger = env.com.getLedger()
env.runTrial4(ledger, n, rollback = true) env.runTrial4(ledger, n, rollback = true)