Skip to content

[Storage Refactor] Refactor saving execution results#6906

Merged
zhangchiqing merged 56 commits intomasterfrom
leo/db-ops-save-execution-results
Mar 5, 2025
Merged

[Storage Refactor] Refactor saving execution results#6906
zhangchiqing merged 56 commits intomasterfrom
leo/db-ops-save-execution-results

Conversation

@zhangchiqing
Copy link
Member

@zhangchiqing zhangchiqing commented Jan 16, 2025

This PR updates the execution node and access node’s saving result process to use the new storage abstraction.

The following database modules are refactored into new storage abstraction:

  • events
  • service events
  • light transaction results
  • transactionResultErrorMessages
  • commits
  • execution results
  • execution receipts
  • my execution receipts
  • transaction results

@zhangchiqing zhangchiqing force-pushed the leo/db-ops-save-execution-results branch 2 times, most recently from f793dcf to 51b6fa0 Compare January 22, 2025 21:48
@codecov-commenter
Copy link

codecov-commenter commented Jan 22, 2025

Codecov Report

Attention: Patch coverage is 38.90063% with 578 lines in your changes missing coverage. Please review.

Project coverage is 41.25%. Comparing base (cb8722b) to head (5fb21c8).

Files with missing lines Patch % Lines
storage/operation/transaction_results.go 0.00% 94 Missing ⚠️
engine/execution/state/state.go 49.25% 27 Missing and 7 partials ⚠️
storage/store/results.go 65.26% 27 Missing and 6 partials ⚠️
cmd/execution_builder.go 0.00% 31 Missing ⚠️
storage/store/receipts.go 57.35% 22 Missing and 7 partials ⚠️
storage/store/events.go 26.31% 28 Missing ⚠️
engine/testutil/nodes.go 0.00% 24 Missing ⚠️
storage/store/transaction_results.go 54.54% 17 Missing and 3 partials ⚠️
...ck-executed-height/cmd/rollback_executed_height.go 0.00% 19 Missing ⚠️
storage/store/light_transaction_results.go 57.14% 15 Missing and 3 partials ⚠️
... and 38 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6906      +/-   ##
==========================================
- Coverage   41.26%   41.25%   -0.02%     
==========================================
  Files        2155     2158       +3     
  Lines      189309   189421     +112     
==========================================
+ Hits        78125    78150      +25     
- Misses     104673   104754      +81     
- Partials     6511     6517       +6     
Flag Coverage Δ
unittests 41.25% <38.90%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@zhangchiqing zhangchiqing force-pushed the leo/db-ops-save-execution-results branch 6 times, most recently from 7aaf9ae to 868a31e Compare February 12, 2025 23:13
Comment on lines +350 to +352
events storage.Events
lightTransactionResults storage.LightTransactionResults
transactionResultErrorMessages storage.TransactionResultErrorMessages
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Access node syncs events, transaction results from EN with indexer engine, I'm refactoring them altogether along with the execution node's saving results process.

}).
Module("transaction results storage", func(node *cmd.NodeConfig) error {
builder.Storage.LightTransactionResults = bstorage.NewLightTransactionResults(node.Metrics.Cache, node.DB, bstorage.DefaultCacheSize)
builder.lightTransactionResults = store.NewLightTransactionResults(node.Metrics.Cache, node.ProtocolDB, bstorage.DefaultCacheSize)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProtocolDB is a storage abstraction, so that we can change in a single place to decide using badger or pebble.

exeNode.txResults,
node.DB,
node.ProtocolDB,
getLatestFinalized,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for the execution state to implement getting highest finalized and executed block.


var blockID flow.Identifier
var lastExecuted uint64
err = db.View(procedure.GetLastExecutedBlock(&lastExecuted, &blockID))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetLastExecutedBlock procedure is replaced by RetrieveExecutedBlock which returns only the block ID, and getting the block with protocol State.

}

// RemoveStateCommitment removes the state commitment by block ID
func RemoveStateCommitment(w storage.Writer, blockID flow.Identifier) error {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is mostly identical with storage/badger/operation/commits.go, except BatchRemoveStateCommitment and BatchIndexStateCommitment are removed, since RemoveStateCommitment is always a batch updates.

@@ -0,0 +1,31 @@
package operation_test
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file is identical to the same file in storage/badger/operation/

@@ -0,0 +1,166 @@
package operation
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file is identical to the same file in storage/badger/operation/

Except the following functions are removed:

  • BatchInsertTransactionResult
  • BatchIndexTransactionResult

@@ -0,0 +1,82 @@
package store
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file is identical to the same file in storage/badger/operation/

blockID := receipt.ExecutionResult.BlockID
receiptID := receipt.ID()
var myOwnReceiptExecutedBefore flow.Identifier
err := operation.LookupOwnExecutionReceipt(rw.GlobalReader(), blockID, &myOwnReceiptExecutedBefore)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where we need to pay attention to, the original implementation can check if an own receipt already exist during insert.

			if errors.Is(err, storage.ErrAlreadyExists) {
				var savedReceiptID flow.Identifier
				err := operation.LookupOwnExecutionReceipt(blockID, &savedReceiptID)(tx)
				if err != nil {
					return err
				}

The original implementation can do so because it's using badger transaction. However, the new storage abstraction uses badger updates, so we have to check it ourselves.

The new way it works is to acquire the indexingOwnReceipts and ensure no other process is storing own receipts, so that the check for if any own receipts for this block won't be stale.

})
})

t.Run("store1 different receipt concurrent for same block should fail", func(t *testing.T) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is the same as the original, except this added concurrent tests.

@zhangchiqing zhangchiqing mentioned this pull request Feb 19, 2025
17 tasks
@zhangchiqing zhangchiqing changed the title [WIP] [Storage Refactor] Refactor saving execution results [Storage Refactor] Refactor saving execution results Feb 21, 2025
block := unittest.BlockFixture()
receipt1 := unittest.ReceiptForBlockFixture(&block)

err := db.WithReaderBatchWriter(func(rw storage.ReaderBatchWriter) error {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is the same as the deleted storage/badger/my_receipts_test.go, except the StoreMyReceipt call is replaced with BatchStoreMyReceipt, since we never call StoreMyReceipt alone.

@zhangchiqing zhangchiqing marked this pull request as ready for review February 21, 2025 19:15
@zhangchiqing zhangchiqing requested a review from a team as a code owner February 21, 2025 19:15
Copy link
Contributor

@peterargue peterargue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

long, but straight forward. looks good to me

Copy link
Member

@fxamacker fxamacker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I mostly focused on general Go programming.

Comment on lines +183 to +184
reader := badgerimpl.ToDB(db).Reader()
err = operation.RetrieveExecutedBlock(reader, &blockID)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findLastExecutedAndSealedHeight() (not added in this PR) appears to be very similar to latest.LatestSealedAndExecutedHeight(). Maybe reuse that function.

func LatestSealedAndExecutedHeight(state protocol.State, db storage.DB) (uint64, error) {

@zhangchiqing zhangchiqing added this pull request to the merge queue Mar 5, 2025
Merged via the queue into master with commit 109b7e2 Mar 5, 2025
56 checks passed
@zhangchiqing zhangchiqing deleted the leo/db-ops-save-execution-results branch March 5, 2025 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants