Documentation ¶
Index ¶
- func Fail(e error) func(*Tx) error
- func Update(db *dbbadger.DB, f func(*Tx) error) error
- func View(db *dbbadger.DB, f func(*Tx) error) error
- func WithTx(f func(*dbbadger.Txn) error) func(*Tx) error
- type DeferredBadgerUpdate
- type DeferredBlockPersist
- func (d *DeferredBlockPersist) AddBadgerOp(op DeferredBadgerUpdate) *DeferredBlockPersist
- func (d *DeferredBlockPersist) AddBadgerOps(ops ...DeferredBadgerUpdate) *DeferredBlockPersist
- func (d *DeferredBlockPersist) AddDbOp(op DeferredDBUpdate) *DeferredBlockPersist
- func (d *DeferredBlockPersist) AddDbOps(ops ...DeferredDBUpdate) *DeferredBlockPersist
- func (d *DeferredBlockPersist) AddIndexingOp(op DeferredBlockPersistOp) *DeferredBlockPersist
- func (d *DeferredBlockPersist) AddIndexingOps(ops ...DeferredBlockPersistOp) *DeferredBlockPersist
- func (d *DeferredBlockPersist) IsEmpty() bool
- func (d *DeferredBlockPersist) OnSucceed(callback func()) *DeferredBlockPersist
- func (d *DeferredBlockPersist) OnSucceeds(callbacks ...func()) *DeferredBlockPersist
- func (d *DeferredBlockPersist) Pending() DeferredBlockPersistOp
- type DeferredBlockPersistOp
- type DeferredDBUpdate
- type DeferredDbOps
- func (d *DeferredDbOps) AddBadgerOp(op DeferredBadgerUpdate) *DeferredDbOps
- func (d *DeferredDbOps) AddBadgerOps(ops ...DeferredBadgerUpdate) *DeferredDbOps
- func (d *DeferredDbOps) AddDbOp(op DeferredDBUpdate) *DeferredDbOps
- func (d *DeferredDbOps) AddDbOps(ops ...DeferredDBUpdate) *DeferredDbOps
- func (d *DeferredDbOps) OnSucceed(callback func()) *DeferredDbOps
- func (d *DeferredDbOps) OnSucceeds(callbacks ...func()) *DeferredDbOps
- func (d *DeferredDbOps) Pending() DeferredDBUpdate
- type Tx
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Fail ¶ added in v0.33.30
Fail returns an anonymous function, whose future execution returns the error e. This is useful for front-loading sanity checks. On the happy path (dominant), this function will generally not be used. However, if one of the front-loaded sanity checks fails, we include `transaction.Fail(e)` in place of the business logic handling the happy path.
func Update ¶
Update creates a badger transaction, passing it to a chain of functions. Only if transaction succeeds, we run `callbacks` that were appended during the transaction execution. The callbacks are useful update caches in order to reduce cache misses.
Types ¶
type DeferredBadgerUpdate ¶ added in v0.33.30
type DeferredBadgerUpdate = func(*badger.Txn) error
DeferredBadgerUpdate is a shorthand notation for an anonymous function that takes a badger transaction as input and runs some database operations as part of that transaction.
type DeferredBlockPersist ¶ added in v0.33.30
type DeferredBlockPersist struct {
// contains filtered or unexported fields
}
DeferredBlockPersist is a utility for accumulating deferred database interactions that are supposed to be executed in one atomic transaction. It supports:
- Deferred database operations that work directly on Badger transactions.
- Deferred database operations that work on `transaction.Tx`. Tx is a storage-layer abstraction, with support for callbacks that are executed after the underlying database transaction completed _successfully_.
- Deferred database operations that depend on the ID of the block under construction and `transaction.Tx`. Especially useful for populating `ByBlockID` indices.
ORDER OF EXECUTION We extend the process in which `transaction.Tx` executes database operations, schedules callbacks, and executed the callbacks. Specifically, DeferredDbOps proceeds as follows:
- Record functors added via `AddBadgerOp`, `AddDbOp`, `OnSucceed` ... • some functors may schedule callbacks (depending on their type), which are executed after the underlying database transaction completed _successfully_. • `OnSucceed` is treated exactly the same way: it schedules a callback during its execution, but it has no database actions.
- Execute the functors in the order they were added
- During each functor's execution: • some functors may schedule callbacks (depending on their type) • record those callbacks in the order they are scheduled (no execution yet)
- If and only if the underlying database transaction succeeds, run the callbacks
DESIGN PATTERN
- DeferredDbOps is stateful, i.e. it needs to be passed as pointer variable.
- Do not instantiate Tx directly. Instead, use one of the following transaction.Update(db, DeferredDbOps.Pending().WithBlock(blockID)) transaction.View(db, DeferredDbOps.Pending().WithBlock(blockID)) operation.RetryOnConflictTx(db, transaction.Update, DeferredDbOps.Pending().WithBlock(blockID))
NOT CONCURRENCY SAFE
func NewDeferredBlockPersist ¶ added in v0.33.30
func NewDeferredBlockPersist() *DeferredBlockPersist
NewDeferredBlockPersist instantiates a DeferredBlockPersist. Initially, it behaves like a no-op until functors are added.
func (*DeferredBlockPersist) AddBadgerOp ¶ added in v0.33.30
func (d *DeferredBlockPersist) AddBadgerOp(op DeferredBadgerUpdate) *DeferredBlockPersist
AddBadgerOp schedules the given DeferredBadgerUpdate to be executed as part of the future transaction. For adding multiple DeferredBadgerUpdates, use `AddBadgerOps(ops ...DeferredBadgerUpdate)` if easily possible, as it reduces the call stack compared to adding the functors individually via `AddBadgerOp(op DeferredBadgerUpdate)`. This method returns a self-reference for chaining.
func (*DeferredBlockPersist) AddBadgerOps ¶ added in v0.33.30
func (d *DeferredBlockPersist) AddBadgerOps(ops ...DeferredBadgerUpdate) *DeferredBlockPersist
AddBadgerOps schedules the given DeferredBadgerUpdates to be executed as part of the future transaction. This method returns a self-reference for chaining.
func (*DeferredBlockPersist) AddDbOp ¶ added in v0.33.30
func (d *DeferredBlockPersist) AddDbOp(op DeferredDBUpdate) *DeferredBlockPersist
AddDbOp schedules the given DeferredDBUpdate to be executed as part of the future transaction. For adding multiple DeferredBadgerUpdates, use `AddDbOps(ops ...DeferredDBUpdate)` if easily possible, as it reduces the call stack compared to adding the functors individually via `AddDbOp(op DeferredDBUpdate)`. This method returns a self-reference for chaining.
func (*DeferredBlockPersist) AddDbOps ¶ added in v0.33.30
func (d *DeferredBlockPersist) AddDbOps(ops ...DeferredDBUpdate) *DeferredBlockPersist
AddDbOps schedules the given DeferredDBUpdates to be executed as part of the future transaction. This method returns a self-reference for chaining.
func (*DeferredBlockPersist) AddIndexingOp ¶ added in v0.33.30
func (d *DeferredBlockPersist) AddIndexingOp(op DeferredBlockPersistOp) *DeferredBlockPersist
AddIndexingOp schedules the given DeferredBlockPersistOp to be executed as part of the future transaction. Usually, these are operations to populate some `ByBlockID` index. For adding multiple DeferredBlockPersistOps, use `AddIndexingOps(ops ...DeferredBlockPersistOp)` if easily possible, as it reduces the call stack compared to adding the functors individually via `AddIndexOp(op DeferredBlockPersistOp)`. This method returns a self-reference for chaining.
func (*DeferredBlockPersist) AddIndexingOps ¶ added in v0.33.30
func (d *DeferredBlockPersist) AddIndexingOps(ops ...DeferredBlockPersistOp) *DeferredBlockPersist
AddIndexingOps schedules the given DeferredBlockPersistOp to be executed as part of the future transaction. Usually, these are operations to populate some `ByBlockID` index. This method returns a self-reference for chaining.
func (*DeferredBlockPersist) IsEmpty ¶ added in v0.33.30
func (d *DeferredBlockPersist) IsEmpty() bool
IsEmpty returns true if and only if there are zero pending database operations.
func (*DeferredBlockPersist) OnSucceed ¶ added in v0.33.30
func (d *DeferredBlockPersist) OnSucceed(callback func()) *DeferredBlockPersist
OnSucceed adds a callback to be executed after the deferred database operations have succeeded. For adding multiple callbacks, use `OnSucceeds(callbacks ...func())` if easily possible, as it reduces the call stack compared to adding the functors individually via `OnSucceed(callback func())`. This method returns a self-reference for chaining.
func (*DeferredBlockPersist) OnSucceeds ¶ added in v0.33.30
func (d *DeferredBlockPersist) OnSucceeds(callbacks ...func()) *DeferredBlockPersist
OnSucceeds adds callbacks to be executed after the deferred database operations have succeeded. This method returns a self-reference for chaining.
func (*DeferredBlockPersist) Pending ¶ added in v0.33.30
func (d *DeferredBlockPersist) Pending() DeferredBlockPersistOp
Pending returns a DeferredBlockPersistOp that comprises all database operations and callbacks that were added so far. Caution, DeferredBlockPersist keeps its internal state of deferred operations. Pending() can be called multiple times, but should only be executed in a database transaction once to avoid conflicts.
type DeferredBlockPersistOp ¶ added in v0.33.30
type DeferredBlockPersistOp func(blockID flow.Identifier, tx *Tx) error
DeferredBlockPersistOp is a shorthand notation for an anonymous function that takes the ID of a fully constructed block and a `transaction.Tx` as inputs and runs some database operations as part of that transaction. It is a "Promise Pattern", essentially saying: once we have the completed the block's construction, we persist data structures that are referenced by the block or populate database indices. This pattern is necessary, because internally to the protocol_state package we don't have access to the candidate block ID yet because we are still determining the protocol state ID for that block.
func (DeferredBlockPersistOp) WithBlock ¶ added in v0.33.30
func (d DeferredBlockPersistOp) WithBlock(blockID flow.Identifier) DeferredDBUpdate
WithBlock adds the still missing block ID information to a `DeferredBlockPersistOp`, thereby converting it into a `transaction.DeferredDBUpdate`.
type DeferredDBUpdate ¶ added in v0.33.30
DeferredDBUpdate is a shorthand notation for an anonymous function that takes a `transaction.Tx` as input and runs some database operations as part of that transaction.
type DeferredDbOps ¶ added in v0.33.30
type DeferredDbOps struct {
// contains filtered or unexported fields
}
DeferredDbOps is a utility for accumulating deferred database interactions that are supposed to be executed in one atomic transaction. It supports:
- Deferred database operations that work directly on Badger transactions.
- Deferred database operations that work on `transaction.Tx`. Tx is a storage-layer abstraction, with support for callbacks that are executed after the underlying database transaction completed _successfully_.
ORDER OF EXECUTION We extend the process in which `transaction.Tx` executes database operations, schedules callbacks, and executed the callbacks. Specifically, DeferredDbOps proceeds as follows:
- Record functors added via `AddBadgerOp`, `AddDbOp`, `OnSucceed` ... • some functor's may schedule callbacks (depending on their type), which are executed after the underlying database transaction completed _successfully_. • `OnSucceed` is treated exactly the same way: it schedules a callback during its execution, but it has no database actions.
- Execute the functors in the order they were added
- During each functor's execution: • some functor's may schedule callbacks (depending on their type) • record those callbacks in the order they are scheduled (no execution yet)
- If and only if the underlying database transaction succeeds, run the callbacks
DESIGN PATTERN
- DeferredDbOps is stateful, i.e. it needs to be passed as pointer variable.
- Do not instantiate Tx directly. Instead, use one of the following transaction.Update(db, DeferredDbOps.Pending()) transaction.View(db, DeferredDbOps.Pending()) operation.RetryOnConflictTx(db, transaction.Update, DeferredDbOps.Pending())
NOT CONCURRENCY SAFE
func NewDeferredDbOps ¶ added in v0.33.30
func NewDeferredDbOps() *DeferredDbOps
NewDeferredDbOps instantiates a DeferredDbOps. Initially, it behaves like a no-op until functors are added.
func (*DeferredDbOps) AddBadgerOp ¶ added in v0.33.30
func (d *DeferredDbOps) AddBadgerOp(op DeferredBadgerUpdate) *DeferredDbOps
AddBadgerOp schedules the given DeferredBadgerUpdate to be executed as part of the future transaction. For adding multiple DeferredBadgerUpdates, use `AddBadgerOps(ops ...DeferredBadgerUpdate)` if easily possible, as it reduces the call stack compared to adding the functors individually via `AddBadgerOp(op DeferredBadgerUpdate)`. This method returns a self-reference for chaining.
func (*DeferredDbOps) AddBadgerOps ¶ added in v0.33.30
func (d *DeferredDbOps) AddBadgerOps(ops ...DeferredBadgerUpdate) *DeferredDbOps
AddBadgerOps schedules the given DeferredBadgerUpdates to be executed as part of the future transaction. This method returns a self-reference for chaining.
func (*DeferredDbOps) AddDbOp ¶ added in v0.33.30
func (d *DeferredDbOps) AddDbOp(op DeferredDBUpdate) *DeferredDbOps
AddDbOp schedules the given DeferredDBUpdate to be executed as part of the future transaction. For adding multiple DeferredBadgerUpdates, use `AddDbOps(ops ...DeferredDBUpdate)` if easily possible, as it reduces the call stack compared to adding the functors individually via `AddDbOp(op DeferredDBUpdate)`. This method returns a self-reference for chaining.
func (*DeferredDbOps) AddDbOps ¶ added in v0.33.30
func (d *DeferredDbOps) AddDbOps(ops ...DeferredDBUpdate) *DeferredDbOps
AddDbOps schedules the given DeferredDBUpdates to be executed as part of the future transaction. This method returns a self-reference for chaining.
func (*DeferredDbOps) OnSucceed ¶ added in v0.33.30
func (d *DeferredDbOps) OnSucceed(callback func()) *DeferredDbOps
OnSucceed adds a callback to be executed after the deferred database operations have succeeded. For adding multiple callbacks, use `OnSucceeds(callbacks ...func())` if easily possible, as it reduces the call stack compared to adding the functors individually via `OnSucceed(callback func())`. This method returns a self-reference for chaining.
func (*DeferredDbOps) OnSucceeds ¶ added in v0.33.30
func (d *DeferredDbOps) OnSucceeds(callbacks ...func()) *DeferredDbOps
OnSucceeds adds callbacks to be executed after the deferred database operations have succeeded. This method returns a self-reference for chaining.
func (*DeferredDbOps) Pending ¶ added in v0.33.30
func (d *DeferredDbOps) Pending() DeferredDBUpdate
Pending returns a DeferredDBUpdate that includes all database operations and callbacks that were added so far. Caution, DeferredDbOps keeps its internal state of deferred operations. Pending() can be called multiple times, but should only be executed in a database transaction once to avoid conflicts.
type Tx ¶
Tx wraps a badger transaction and includes and additional slice for callbacks. The callbacks are executed after the badger transaction completed _successfully_. DESIGN PATTERN
- DBTxn should never be nil
- at initialization, `callbacks` is empty
- While business logic code operates on `DBTxn`, it can append additional callbacks via the `OnSucceed` method. This generally happens during the transaction execution.
CAUTION:
- Tx is stateful (calls to `OnSucceed` change its internal state). Therefore, Tx needs to be passed as pointer variable.
- Do not instantiate Tx outside of this package. Instead, use `Update` or `View` functions.
- Whether a transaction is considered to have succeeded depends only on the return value of the outermost function. For example, consider a chain of 3 functions: f3( f2( f1(x))) Lets assume f1 fails with an `storage.ErrAlreadyExists` sentinel, which f2 expects and therefore discards. f3 could then succeed, i.e. return nil. Consequently, the entire list of callbacks is executed, including f1's callback if it added one. Callback implementations therefore need to account for this edge case.
- not concurrency safe
func (*Tx) OnSucceed ¶
func (b *Tx) OnSucceed(callback func())
OnSucceed adds a callback to execute after the batch has been successfully flushed. Useful for implementing the cache where we will only cache after the batch of database operations has been successfully applied. CAUTION: Whether a transaction is considered to have succeeded depends only on the return value of the outermost function. For example, consider a chain of 3 functions: f3( f2( f1(x))) Lets assume f1 fails with an `storage.ErrAlreadyExists` sentinel, which f2 expects and therefore discards. f3 could then succeed, i.e. return nil. Consequently, the entire list of callbacks is executed, including f1's callback if it added one. Callback implementations therefore need to account for this edge case.