transaction

package
v0.37.0-crescendo-RC7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 12, 2024 License: AGPL-3.0 Imports: 3 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Fail added in v0.33.30

func Fail(e error) func(*Tx) error

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

func Update(db *dbbadger.DB, f func(*Tx) error) error

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.

func View added in v0.33.30

func View(db *dbbadger.DB, f func(*Tx) error) error

View creates a read-only 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.

func WithTx added in v0.17.1

func WithTx(f func(*dbbadger.Txn) error) func(*Tx) error

WithTx is useful when transaction is used without adding callback.

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:

  1. 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.
  2. Execute the functors in the order they were added
  3. 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)
  4. 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

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

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

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

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

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

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

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

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

type DeferredDBUpdate func(*Tx) error

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:

  1. 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.
  2. Execute the functors in the order they were added
  3. 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)
  4. 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

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

type Tx struct {
	DBTxn *dbbadger.Txn
	// contains filtered or unexported fields
}

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL