feat: Add migration backfill for mptoken_issuance_history - #3128
feat: Add migration backfill for mptoken_issuance_history#3128BryanJ1ang wants to merge 19 commits into
Conversation
a0b2942 to
891846e
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
/ai-reviewer |
Kassaking7
left a comment
There was a problem hiding this comment.
You may also want to add missing unit tests based on the codecov report
2565b28 to
9e0d9fe
Compare
Added some unit tests but for |
|
@PeterChen13579 @yinyiqian1 I can't add you guys as reviewers but please take a look when you guys can! |
| static constexpr auto kDeleter = [](CassCollection* ptr) { cass_collection_free(ptr); }; | ||
|
|
||
| static void | ||
| throwErrorIfNeeded(CassError const rc, std::string_view const label) |
There was a problem hiding this comment.
currently collection and statement is using the refactored function. But there are other places still using the local lambda function. So this refactor is not complete.
I suggest we revert these changes and leave the refactor in a separate PR.
There was a problem hiding this comment.
Pull request overview
Adds a Cassandra migration to backfill historical MPToken issuance transaction history into the new MPT index tables, reusing the existing live ETL extractor and improving migration full-table scan robustness (paging + error propagation).
Changes:
- Introduces
MPTTransactionHistoryMigratorand registers it with the Cassandra migration manager. - Enhances full-table scanning: explicit column selection via
kSelectColumns, Cassandra driver paging support, and propagation of worker/read failures. - Adds/extends unit + integration coverage around scanner behavior, adapter decoding failures, migrator status semantics, and parity with live ETL indexing.
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/util/BatchingTests.cpp | Adds unit coverage for util::BatchBuffer batching behavior and concurrency. |
| tests/unit/migration/MigratorRegisterTests.cpp | Verifies failed migrators don’t write “Migrated” status. |
| tests/unit/migration/MigrationApplicationTests.cpp | Adds unit tests for migrator CLI/application behavior via a mock manager. |
| tests/unit/migration/cassandra/TransactionsAdapterTests.cpp | Tests transaction row deserialization and decode-failure signaling. |
| tests/unit/migration/cassandra/SpecTests.cpp | Updates table spec test to include explicit select-column lists. |
| tests/unit/migration/cassandra/FullTableScannerTests.cpp | Updates tests for new scanner wait/error behavior and adds new validations. |
| tests/unit/CMakeLists.txt | Registers new unit test sources. |
| tests/integration/migration/cassandra/MPTTransactionHistoryMigratorTests.cpp | End-to-end integration coverage for MPT backfill, idempotency, paging, and ETL parity. |
| tests/integration/migration/cassandra/ExampleTransactionsMigrator.cpp | Updates example migrator to new adapter + scanner wait API. |
| tests/integration/migration/cassandra/ExampleObjectsMigrator.cpp | Updates example migrator to new scanner wait API. |
| tests/integration/migration/cassandra/CassandraMigrationManagerTests.cpp | Adds integration test to ensure migration scans read all driver pages. |
| tests/integration/data/cassandra/BaseTests.cpp | Adds base Cassandra test for paging-state iteration across pages. |
| tests/integration/CMakeLists.txt | Registers new integration test source. |
| tests/common/util/MockMigrationManager.hpp | Adds a mock MigrationManagerInterface for application-layer tests. |
| tests/common/migration/TestMigrators.hpp | Adds a throwing migrator used to validate failure semantics. |
| src/util/Batching.hpp | Adds util::BatchBuffer for streaming batching + flush semantics. |
| src/migration/MigrationApplication.hpp | Adds constructor overload allowing injection of a prebuilt migration manager (tests). |
| src/migration/MigrationApplication.cpp | Avoids double Prometheus init and implements injected-manager constructor. |
| src/migration/CMakeLists.txt | Links migration library against clio_etl to reuse extractor for backfill. |
| src/migration/cassandra/MPTTransactionHistoryMigrator.hpp | Declares new backfill migrator for historical MPT issuance tx indexing. |
| src/migration/cassandra/MPTTransactionHistoryMigrator.cpp | Implements full-table scan + batching + decode-failure handling + durable completion. |
| src/migration/cassandra/impl/TransactionsAdapter.hpp | Adds explicit select columns + decode-failure callback + logging support. |
| src/migration/cassandra/impl/TransactionsAdapter.cpp | Implements deserialization with controlled handling of decode failures. |
| src/migration/cassandra/impl/Spec.hpp | Requires kSelectColumns and enforces tuple/column-count alignment. |
| src/migration/cassandra/impl/ObjectsAdapter.hpp | Adds explicit kSelectColumns matching row tuple order. |
| src/migration/cassandra/impl/FullTableScanner.hpp | Adds settings validation and replaces silent waits with error-propagating join. |
| src/migration/cassandra/impl/CassandraMigrationSchema.hpp | Prepares full-scan statements using explicit column lists. |
| src/migration/cassandra/CassandraMigrationManager.hpp | Registers MPTTransactionHistoryMigrator for Cassandra migrations. |
| src/migration/cassandra/CassandraMigrationBackend.hpp | Adds prepared-statement caching, paging-size/state handling, and fail-closed scan errors. |
| src/main/Main.cpp | Initializes Prometheus in the migrate CLI path before creating the migrator app. |
| src/etl/impl/ext/MPT.cpp | Simplifies issuance-index row counting (removes per-tx warning threshold logic). |
| src/data/cassandra/impl/Statement.hpp | Adds paging-size/state helpers and centralizes error throwing. |
| src/data/cassandra/impl/Result.hpp | Adds hasMorePages() API. |
| src/data/cassandra/impl/Result.cpp | Implements hasMorePages(). |
| src/data/cassandra/impl/Collection.hpp | Switches to shared Cassandra error helper (removes local throw helper). |
| src/data/cassandra/Error.hpp | Adds shared throwErrorIfNeeded helper used by statement/binding/paging APIs. |
Comments suppressed due to low confidence (1)
src/util/Batching.hpp:111
- Same capacity issue as in
add():std::exchange(buffer_, {})dropsbuffer_capacity, so the next accumulation may reallocate. ReservingbatchSize_after clearing helps keep allocation behavior stable across flush cycles.
std::scoped_lock const lock{mutex_};
batch = std::exchange(buffer_, {});
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (buffer_.size() < batchSize_) | ||
| return; | ||
| batch = std::exchange(buffer_, {}); | ||
| } |
| ); | ||
| } | ||
| auto throwBindingErrorIfNeeded = [idx](CassError rc, std::string_view label) { | ||
| if (rc != CASS_OK) |
There was a problem hiding this comment.
You're checking if (rc != CASS_OK) twice, because throwErrorIfNeeded also does if (rc != CASS_OK) check
| setPagingSize(std::int32_t const pageSize) const | ||
| { | ||
| auto const rc = cass_statement_set_paging_size(*this, pageSize); | ||
| throwErrorIfNeeded(rc, "Set paging size"); |
There was a problem hiding this comment.
the refactor of throwErrorIfNeeded is mainly for page.
We can keep the logic within Statement.hpp, instead of refactoring in error.hpp, collection.hpp, etc.
| fmt::format("[{}] at idx {}: {}", label, idx, cass_error_desc(rc)) | ||
| ); | ||
| } | ||
| auto throwBindingErrorIfNeeded = [idx](CassError rc, std::string_view label) { |
There was a problem hiding this comment.
The change in bindAt does not change anything. The error message is almost the same after this change, just the ]'s location is moved.
before change: [...] at idx ..
after change: [... at idx ..]
Statement.hpp and Collection.hpp each carried a private static copy of the same CassError-to-logic_error helper; both now use one shared free function in data::cassandra::impl. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nst ref A transaction that fails to deserialize is a deterministic data error, so rerunning the migration could never get past it; log and skip the row instead of permanently wedging the backfill. Callback and DB read errors still fail closed. The scan callback now takes STTx/TxMeta by const ref, removing a deep copy per scanned row. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Buffer extracted records across transactions and flush in batches (mirroring the live ETL path's per-ledger accumulation) so the backend coalesces them into full-size write batches instead of submitting one tiny write pair per transaction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The warning was not operator-actionable and per-tx fanout beyond the threshold should not occur in practice; the Prometheus counter still tracks index rows written. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Key the prepared-statement cache by table name alone (partition key and select columns are fixed per TableDesc), replace the rowsRead counter with a bool, and author the read-failure message once for both the log and the thrown exception. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The TableSpec concept now requires the kSelectColumns list to have exactly one column per Row tuple element, so the two cannot silently drift when columns are added or removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| } | ||
|
|
||
| indexRowsWritten += txIndexRows; | ||
| indexRowsWritten += 1 + record.accounts.size(); |
There was a problem hiding this comment.
I don't think the change in MPT.cpp is needed
| /** | ||
| * @brief The full table scanner settings. | ||
| */ | ||
| struct FullTableScannerSettings { |
There was a problem hiding this comment.
this struct does not need to be moved
|
|
||
| private: | ||
| [[nodiscard]] static std::uint32_t | ||
| validatedCtxThreadsNum(FullTableScannerSettings const& settings) |
| } | ||
|
|
||
| [[nodiscard]] static std::size_t | ||
| computeCursorsNum(FullTableScannerSettings const& settings) |
| FullTableScanner(FullTableScannerSettings settings, TableAdapter&& reader) | ||
| : ctx_(ExecutionContextType(settings.ctxThreadsNum)) | ||
| , cursorsNum_(settings.jobsNum * settings.cursorsPerJob) | ||
| : ctx_(ExecutionContextType(validatedCtxThreadsNum(settings))) |
There was a problem hiding this comment.
we don't need to refactor to pass in validatedCtxThreadsNum
| ); | ||
|
|
||
| auto const cursors = TokenRangesProvider{cursorsNum_}.getRanges(); | ||
| auto const cursors = |
There was a problem hiding this comment.
We don't need the refactor.
29a8354 to
03dd0ca
Compare
Restores Error.hpp, Collection.hpp and Statement.hpp::bindAt to their develop state. The shared throwErrorIfNeeded helper extracted into Error.hpp was an unrelated dedup, and it left four other call sites (Result.hpp, Tuple.hpp x2, Cluster.cpp) on the old inline pattern, so it did not deliver the consistency it aimed for. That cleanup belongs in its own PR that converts every site and settles on one message format. Reverting bindAt also drops two incidental changes this branch had made to it: an eagerly-evaluated fmt::format on every successful bind, and a change to the error message shape from "[label] at idx N" to "[label at idx N]". Drop the private static throwErrorIfNeeded too, and inline its check into the two paging methods that were its only callers. Keeping it would have added a sixth copy of the same check-and-throw to this subsystem, which is the duplication the reverted commit set out to remove. Removing it also leaves bindAt's local lambda with no class-scope name to shadow. Statement.hpp now differs from develop only by setPagingSize and setPagingState, both of which the MPT backfill token-range scan requires. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restores the per-transaction MPT issuance index fanout warning in MPTExt::writeMPTDataFromTransactions to match develop; the removal was unrelated to the migration work on this branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
03dd0ca to
6914780
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 33 out of 33 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
src/migration/MigrationApplication.cpp:48
- The injecting constructor accepts a potentially null migrationManager; run()/printStatus()/migrate() dereference migrationManager_ unconditionally, so constructing with nullptr would crash. Add a defensive check (throw/ASSERT) here to fail fast with a clear error.
MigratorApplication::MigratorApplication(
MigrateSubCmd command,
std::shared_ptr<migration::MigrationManagerInterface> migrationManager
)
: migrationManager_(std::move(migrationManager)), cmd_(std::move(command))
{
}
Note: this PR depends on previous ETL indexing PR here
Summary
Adds
MPTTransactionHistoryMigrator, a Cassandra migration that backfills historical MPT issuance transaction history into the new MPT index tables:mptoken_issuance_transactionsaccount_mptoken_issuance_transactionsThe migrator full-scans the
transactionstable, reuses the live ETL MPT extractor, writes the same deterministic index rows produced by live indexing, and waits for queued async writes before marking the migration as complete.Details
MPTTransactionHistoryMigratorwith the Cassandra migration manager.migration.full_scan_threadsmigration.full_scan_jobsmigration.cursors_per_jobTesting
Added coverage for: