Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use transactions for asset table upserts #142

Closed

Conversation

danenbm
Copy link
Contributor

@danenbm danenbm commented Nov 22, 2023

Notes

  • Use transactions for asset table upserts.
  • Built on top of and meant to be merged into: Bubblegum Update Metadata Version 2 #135
  • To avoid complexity and avoid edge cases, only added transactions for the asset table.

Testing

  • Used slightly instrumented validator and test code, changes should have no effect on these results.
  • Indexed the same 2 mintV1 instructions 3 times per test case.
  • Examined timestamps for the 5 upserts to the asset table that occur in mintV1 indexing.

Test Results

  • Using this PR reduces the time of the 5 upserts used in mintV1 from the range of 9-23 ms down to 2-4 ms.

Test Data

Test case 1: Existing code from #135

Over 3 tries saw ~9-21 ms for the 5 upserts.
Here are the results for one trial (~11-12 ms for the 5 upserts):

digital-asset-rpc-infrastructure-ingester-1  | DOING MINT V1
digital-asset-rpc-infrastructure-ingester-1  | 
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.909 UTC [72] LOG:  execute sqlx_s_26: INSERT INTO "asset_data" ("id", "chain_data_mutability", "chain_data", "metadata_url", "metadata_mutability", "metadata", "slot_updated", "reindex", "raw_name", "raw_symbol") VALUES ($1, CAST($2 AS chain_mutability), $3, $4, CAST($5 AS mutability), $6, $7, $8, $9, $10) ON CONFLICT ("id") DO UPDATE SET "chain_data_mutability" = "excluded"."chain_data_mutability", "chain_data" = "excluded"."chain_data", "metadata_url" = "excluded"."metadata_url", "metadata_mutability" = "excluded"."metadata_mutability", "slot_updated" = "excluded"."slot_updated", "reindex" = "excluded"."reindex", "raw_name" = "excluded"."raw_name", "raw_symbol" = "excluded"."raw_symbol"
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.909 UTC [72] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = 'immutable', $3 = '{"name": "test", "symbol": "TST", "edition_nonce": 0, "token_standard": "NonFungible", "primary_sale_happened": false}', $4 = 'https://metaplex.com', $5 = 'mutable', $6 = '"processing"', $7 = '224494461', $8 = 't', $9 = '\x74657374', $10 = '\x545354'

digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.911 UTC [75] LOG:  execute sqlx_s_26: INSERT INTO "asset" ("id", "specification_version", "specification_asset_class", "owner_type", "frozen", "royalty_target_type", "royalty_target", "royalty_amount", "asset_data", "slot_updated") VALUES ($1, CAST($2 AS specification_versions), CAST($3 AS specification_asset_class), CAST($4 AS owner_type), $5, CAST($6 AS royalty_target_type), $7, $8, $9, $10) ON CONFLICT ("id") DO UPDATE SET "owner_type" = "excluded"."owner_type", "frozen" = "excluded"."frozen", "specification_version" = "excluded"."specification_version", "specification_asset_class" = "excluded"."specification_asset_class", "royalty_target_type" = "excluded"."royalty_target_type", "royalty_target" = "excluded"."royalty_target", "royalty_amount" = "excluded"."royalty_amount", "asset_data" = "excluded"."asset_data", "slot_updated" = "excluded"."slot_updated"
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.911 UTC [75] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = 'v1', $3 = 'NFT', $4 = 'single', $5 = 'f', $6 = 'creators', $7 = NULL, $8 = '0', $9 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $10 = '224494461'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.914 UTC [73] LOG:  execute sqlx_s_28: INSERT INTO "asset" ("id", "supply", "supply_mint", "compressed", "compressible", "was_decompressed") VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT ("id") DO UPDATE SET "compressed" = "excluded"."compressed", "compressible" = "excluded"."compressible", "supply" = "excluded"."supply", "supply_mint" = "excluded"."supply_mint", "was_decompressed" = "excluded"."was_decompressed" WHERE NOT asset.was_decompressed
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.914 UTC [73] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '1', $3 = NULL, $4 = 't', $5 = 'f', $6 = 'f'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.916 UTC [74] LOG:  execute sqlx_s_28: INSERT INTO "asset" ("id", "tree_id", "leaf", "nonce", "data_hash", "creator_hash", "leaf_seq") VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT ("id") DO UPDATE SET "nonce" = "excluded"."nonce", "tree_id" = "excluded"."tree_id", "leaf" = "excluded"."leaf", "data_hash" = "excluded"."data_hash", "creator_hash" = "excluded"."creator_hash", "leaf_seq" = "excluded"."leaf_seq" WHERE (NOT asset.was_decompressed) AND (excluded.leaf_seq >= asset.leaf_seq OR asset.leaf_seq IS NULL)
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.916 UTC [74] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '\xf8bf1069ff226eb41797417535cc5510ec75ffd006155dbda2371b5fee88bf7d', $3 = '\x921c65b368602da975d6df14fb733a0e4ce6b66d33ff40b9d36b63dfbd4b4c15', $4 = '0', $5 = 'DLrNQJ6gJbfsqBLe3QXMVc8j2kjVtFqFbXd6rFsoFVyG', $6 = '58PDE6bzJweEP4NauMXugPYfjkZMzGGptDyH7rP4ZSEq', $7 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.918 UTC [71] LOG:  execute sqlx_s_28: INSERT INTO "asset" ("id", "owner", "delegate", "owner_delegate_seq") VALUES ($1, $2, $3, $4) ON CONFLICT ("id") DO UPDATE SET "owner" = "excluded"."owner", "delegate" = "excluded"."delegate", "owner_delegate_seq" = "excluded"."owner_delegate_seq" WHERE excluded.owner_delegate_seq >= asset.owner_delegate_seq OR asset.owner_delegate_seq IS NULL
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.918 UTC [71] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '\xdc53343c46e5d7a1bd08f4780285621202f66b596f984e940a5eb423ac560fed', $3 = NULL, $4 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.921 UTC [72] LOG:  execute sqlx_s_27: INSERT INTO "asset" ("id", "seq") VALUES ($1, $2) ON CONFLICT ("id") DO UPDATE SET "seq" = "excluded"."seq" WHERE excluded.seq >= asset.seq OR asset.seq IS NULL
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.921 UTC [72] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '1'

digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.923 UTC [75] LOG:  execute sqlx_s_12: INSERT INTO "asset_v1_account_attachments" ("id", "attachment_type", "slot_updated") VALUES ($1, CAST($2 AS v1_account_attachments), $3) ON CONFLICT ("id") DO NOTHING
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 09:07:25.923 UTC [75] DETAIL:  parameters: $1 = '\x03ca585e58bc0ba63b21c5ebfb54eeb42912152ba229edb3b10fdcbf4a67aec5', $2 = 'master_edition_v2', $3 = '224494461'

Test case 2: Added semicolons after first 4 upserts to attempt SQL batching

Could not find any documentation from PostgreSQL indicating this would result in chaining. From the results it looks like this had no effect.
Over 3 tries saw ~11-23 ms for the 5 upserts.
Here are the results for one trial (~16-23 ms for the 5 upserts):

digital-asset-rpc-infrastructure-ingester-1  | DOING MINT V1
digital-asset-rpc-infrastructure-ingester-1  | 
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.172 UTC [73] LOG:  execute sqlx_s_26: INSERT INTO "asset_data" ("id", "chain_data_mutability", "chain_data", "metadata_url", "metadata_mutability", "metadata", "slot_updated", "reindex", "raw_name", "raw_symbol") VALUES ($1, CAST($2 AS chain_mutability), $3, $4, CAST($5 AS mutability), $6, $7, $8, $9, $10) ON CONFLICT ("id") DO UPDATE SET "chain_data_mutability" = "excluded"."chain_data_mutability", "chain_data" = "excluded"."chain_data", "metadata_url" = "excluded"."metadata_url", "metadata_mutability" = "excluded"."metadata_mutability", "slot_updated" = "excluded"."slot_updated", "reindex" = "excluded"."reindex", "raw_name" = "excluded"."raw_name", "raw_symbol" = "excluded"."raw_symbol"
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.172 UTC [73] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = 'immutable', $3 = '{"name": "test", "symbol": "TST", "edition_nonce": 0, "token_standard": "NonFungible", "primary_sale_happened": false}', $4 = 'https://metaplex.com', $5 = 'mutable', $6 = '"processing"', $7 = '224494461', $8 = 't', $9 = '\x74657374', $10 = '\x545354'

digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.179 UTC [75] LOG:  execute sqlx_s_26: INSERT INTO "asset" ("id", "specification_version", "specification_asset_class", "owner_type", "frozen", "royalty_target_type", "royalty_target", "royalty_amount", "asset_data", "slot_updated") VALUES ($1, CAST($2 AS specification_versions), CAST($3 AS specification_asset_class), CAST($4 AS owner_type), $5, CAST($6 AS royalty_target_type), $7, $8, $9, $10) ON CONFLICT ("id") DO UPDATE SET "owner_type" = "excluded"."owner_type", "frozen" = "excluded"."frozen", "specification_version" = "excluded"."specification_version", "specification_asset_class" = "excluded"."specification_asset_class", "royalty_target_type" = "excluded"."royalty_target_type", "royalty_target" = "excluded"."royalty_target", "royalty_amount" = "excluded"."royalty_amount", "asset_data" = "excluded"."asset_data", "slot_updated" = "excluded"."slot_updated";
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.179 UTC [75] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = 'v1', $3 = 'NFT', $4 = 'single', $5 = 'f', $6 = 'creators', $7 = NULL, $8 = '0', $9 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $10 = '224494461'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.183 UTC [76] LOG:  execute sqlx_s_24: INSERT INTO "asset" ("id", "supply", "supply_mint", "compressed", "compressible", "was_decompressed") VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT ("id") DO UPDATE SET "compressed" = "excluded"."compressed", "compressible" = "excluded"."compressible", "supply" = "excluded"."supply", "supply_mint" = "excluded"."supply_mint", "was_decompressed" = "excluded"."was_decompressed" WHERE NOT asset.was_decompressed;
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.183 UTC [76] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '1', $3 = NULL, $4 = 't', $5 = 'f', $6 = 'f'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.185 UTC [74] LOG:  execute sqlx_s_28: INSERT INTO "asset" ("id", "tree_id", "leaf", "nonce", "data_hash", "creator_hash", "leaf_seq") VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT ("id") DO UPDATE SET "nonce" = "excluded"."nonce", "tree_id" = "excluded"."tree_id", "leaf" = "excluded"."leaf", "data_hash" = "excluded"."data_hash", "creator_hash" = "excluded"."creator_hash", "leaf_seq" = "excluded"."leaf_seq" WHERE (NOT asset.was_decompressed) AND (excluded.leaf_seq >= asset.leaf_seq OR asset.leaf_seq IS NULL);
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.185 UTC [74] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '\xf8bf1069ff226eb41797417535cc5510ec75ffd006155dbda2371b5fee88bf7d', $3 = '\x921c65b368602da975d6df14fb733a0e4ce6b66d33ff40b9d36b63dfbd4b4c15', $4 = '0', $5 = 'DLrNQJ6gJbfsqBLe3QXMVc8j2kjVtFqFbXd6rFsoFVyG', $6 = '58PDE6bzJweEP4NauMXugPYfjkZMzGGptDyH7rP4ZSEq', $7 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.188 UTC [72] LOG:  execute sqlx_s_27: INSERT INTO "asset" ("id", "owner", "delegate", "owner_delegate_seq") VALUES ($1, $2, $3, $4) ON CONFLICT ("id") DO UPDATE SET "owner" = "excluded"."owner", "delegate" = "excluded"."delegate", "owner_delegate_seq" = "excluded"."owner_delegate_seq" WHERE excluded.owner_delegate_seq >= asset.owner_delegate_seq OR asset.owner_delegate_seq IS NULL;
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.188 UTC [72] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '\xdc53343c46e5d7a1bd08f4780285621202f66b596f984e940a5eb423ac560fed', $3 = NULL, $4 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.190 UTC [73] LOG:  execute sqlx_s_27: INSERT INTO "asset" ("id", "seq") VALUES ($1, $2) ON CONFLICT ("id") DO UPDATE SET "seq" = "excluded"."seq" WHERE excluded.seq >= asset.seq OR asset.seq IS NULL;
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.190 UTC [73] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.195 UTC [75] LOG:  execute sqlx_s_27: INSERT INTO "asset" ("id", "update_metadata_seq") VALUES ($1, $2) ON CONFLICT ("id") DO UPDATE SET "update_metadata_seq" = "excluded"."update_metadata_seq" WHERE excluded.update_metadata_seq >= asset.update_metadata_seq OR asset.update_metadata_seq IS NULL
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.195 UTC [75] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '1'

digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.202 UTC [76] LOG:  execute sqlx_s_7: INSERT INTO "asset_v1_account_attachments" ("id", "attachment_type", "slot_updated") VALUES ($1, CAST($2 AS v1_account_attachments), $3) ON CONFLICT ("id") DO NOTHING
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:23:27.202 UTC [76] DETAIL:  parameters: $1 = '\x03ca585e58bc0ba63b21c5ebfb54eeb42912152ba229edb3b10fdcbf4a67aec5', $2 = 'master_edition_v2', $3 = '224494461'

Test case 3: Code from this PR using transactions.

Over 3 tries saw ~2-4 ms for the 5 upserts.
Here are the results for one trial (~2-3 ms for the 5 upserts):

digital-asset-rpc-infrastructure-ingester-1  | DOING MINT V1
digital-asset-rpc-infrastructure-ingester-1  | 
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.024 UTC [76] LOG:  execute sqlx_s_23: INSERT INTO "asset_data" ("id", "chain_data_mutability", "chain_data", "metadata_url", "metadata_mutability", "metadata", "slot_updated", "reindex", "raw_name", "raw_symbol") VALUES ($1, CAST($2 AS chain_mutability), $3, $4, CAST($5 AS mutability), $6, $7, $8, $9, $10) ON CONFLICT ("id") DO UPDATE SET "chain_data_mutability" = "excluded"."chain_data_mutability", "chain_data" = "excluded"."chain_data", "metadata_url" = "excluded"."metadata_url", "metadata_mutability" = "excluded"."metadata_mutability", "slot_updated" = "excluded"."slot_updated", "reindex" = "excluded"."reindex", "raw_name" = "excluded"."raw_name", "raw_symbol" = "excluded"."raw_symbol"
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.024 UTC [76] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = 'immutable', $3 = '{"name": "test", "symbol": "TST", "edition_nonce": 0, "token_standard": "NonFungible", "primary_sale_happened": false}', $4 = 'https://metaplex.com', $5 = 'mutable', $6 = '"processing"', $7 = '224494461', $8 = 't', $9 = '\x74657374', $10 = '\x545354'

digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.031 UTC [74] LOG:  statement: BEGIN
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.031 UTC [74] LOG:  execute sqlx_s_26: INSERT INTO "asset" ("id", "specification_version", "specification_asset_class", "owner_type", "frozen", "royalty_target_type", "royalty_target", "royalty_amount", "asset_data", "slot_updated") VALUES ($1, CAST($2 AS specification_versions), CAST($3 AS specification_asset_class), CAST($4 AS owner_type), $5, CAST($6 AS royalty_target_type), $7, $8, $9, $10) ON CONFLICT ("id") DO UPDATE SET "owner_type" = "excluded"."owner_type", "frozen" = "excluded"."frozen", "specification_version" = "excluded"."specification_version", "specification_asset_class" = "excluded"."specification_asset_class", "royalty_target_type" = "excluded"."royalty_target_type", "royalty_target" = "excluded"."royalty_target", "royalty_amount" = "excluded"."royalty_amount", "asset_data" = "excluded"."asset_data", "slot_updated" = "excluded"."slot_updated"
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.031 UTC [74] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = 'v1', $3 = 'NFT', $4 = 'single', $5 = 'f', $6 = 'creators', $7 = NULL, $8 = '0', $9 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $10 = '224494461'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.031 UTC [74] LOG:  execute sqlx_s_27: INSERT INTO "asset" ("id", "supply", "supply_mint", "compressed", "compressible", "was_decompressed") VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT ("id") DO UPDATE SET "compressed" = "excluded"."compressed", "compressible" = "excluded"."compressible", "supply" = "excluded"."supply", "supply_mint" = "excluded"."supply_mint", "was_decompressed" = "excluded"."was_decompressed" WHERE NOT asset.was_decompressed
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.031 UTC [74] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '1', $3 = NULL, $4 = 't', $5 = 'f', $6 = 'f'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.032 UTC [74] LOG:  execute sqlx_s_28: INSERT INTO "asset" ("id", "tree_id", "leaf", "nonce", "data_hash", "creator_hash", "leaf_seq") VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT ("id") DO UPDATE SET "nonce" = "excluded"."nonce", "tree_id" = "excluded"."tree_id", "leaf" = "excluded"."leaf", "data_hash" = "excluded"."data_hash", "creator_hash" = "excluded"."creator_hash", "leaf_seq" = "excluded"."leaf_seq" WHERE (NOT asset.was_decompressed) AND (excluded.leaf_seq >= asset.leaf_seq OR asset.leaf_seq IS NULL)
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.032 UTC [74] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '\xf8bf1069ff226eb41797417535cc5510ec75ffd006155dbda2371b5fee88bf7d', $3 = '\x921c65b368602da975d6df14fb733a0e4ce6b66d33ff40b9d36b63dfbd4b4c15', $4 = '0', $5 = 'DLrNQJ6gJbfsqBLe3QXMVc8j2kjVtFqFbXd6rFsoFVyG', $6 = '58PDE6bzJweEP4NauMXugPYfjkZMzGGptDyH7rP4ZSEq', $7 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.032 UTC [74] LOG:  execute sqlx_s_29: INSERT INTO "asset" ("id", "owner", "delegate", "owner_delegate_seq") VALUES ($1, $2, $3, $4) ON CONFLICT ("id") DO UPDATE SET "owner" = "excluded"."owner", "delegate" = "excluded"."delegate", "owner_delegate_seq" = "excluded"."owner_delegate_seq" WHERE excluded.owner_delegate_seq >= asset.owner_delegate_seq OR asset.owner_delegate_seq IS NULL
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.032 UTC [74] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '\xdc53343c46e5d7a1bd08f4780285621202f66b596f984e940a5eb423ac560fed', $3 = NULL, $4 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.032 UTC [74] LOG:  execute sqlx_s_30: INSERT INTO "asset" ("id", "seq") VALUES ($1, $2) ON CONFLICT ("id") DO UPDATE SET "seq" = "excluded"."seq" WHERE excluded.seq >= asset.seq OR asset.seq IS NULL
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.032 UTC [74] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.032 UTC [74] LOG:  execute sqlx_s_31: INSERT INTO "asset" ("id", "update_metadata_seq") VALUES ($1, $2) ON CONFLICT ("id") DO UPDATE SET "update_metadata_seq" = "excluded"."update_metadata_seq" WHERE excluded.update_metadata_seq >= asset.update_metadata_seq OR asset.update_metadata_seq IS NULL
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.032 UTC [74] DETAIL:  parameters: $1 = '\x4302561a2799244936a3b020569bf90f58cd9b406af4cd084a82a2cf6415a8f0', $2 = '1'
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.033 UTC [74] LOG:  statement: COMMIT

digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.034 UTC [75] LOG:  execute sqlx_s_14: INSERT INTO "asset_v1_account_attachments" ("id", "attachment_type", "slot_updated") VALUES ($1, CAST($2 AS v1_account_attachments), $3) ON CONFLICT ("id") DO NOTHING
digital-asset-rpc-infrastructure-db-1        | 2023-11-22 08:47:13.034 UTC [75] DETAIL:  parameters: $1 = '\x03ca585e58bc0ba63b21c5ebfb54eeb42912152ba229edb3b10fdcbf4a67aec5', $2 = 'master_edition_v2', $3 = '224494461'

@danenbm danenbm marked this pull request as ready for review November 22, 2023 09:33
.await?;

// Close out transaction and relinqish the lock.
multi_txn.commit().await?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not include the other updates below?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't want to lock all the different tables at first. Starting with asset seemed like a good incremental improvement since it had the most upserts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Incorporated all these changes into #134

Copy link
Collaborator

@linuskendall linuskendall left a comment

Choose a reason for hiding this comment

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

If the transactions are actually going to deliver value, we need to ensure that they incorporate the asset_should_be_updated SELECT statement so we can fix the race conditions pointed out by Nick in the other PR.

upsert_asset_with_seq(&multi_txn, id_bytes.to_vec(), seq as i64).await?;

// Close out transaction and relinqish the lock.
multi_txn.commit().await?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

You need to know how to handle errors here. what if the transaction fails? Need to have recovery scenarios in that acse surely?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the way it works with SeaORM, if the the transaction (multi_txn in this case) goes out of scope, it is rolled back. Therefore, the way the code is structured, if there is an error on one of the executions of the multiple statement transaction, there will be an early return, multi_txn will go out of scope and the transaction will be rolled back.

The reported error will be the one that caused the early return, which is how it functions today. So I think the only difference will be that the asset table changes are tied together, and in the case of failure, all of them will be rolled back together. I don't know if this could be considered better behavior than today or not; it seems about equivalent to me, because either way some of the asset updates for an instruction were missed, and the asset state overall would be missing some updates.

@@ -67,9 +67,12 @@ where
let tree_id = cl.id.to_bytes();
let nonce = cl.index as i64;

// Start a db transaction.
let multi_txn = txn.begin().await?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is too late to start the TXN. The TXN should include asset_should_be_updated and asset_should_be_updated should be using SELECT ... FOR UPDATE instead of the SELECT only. This would allow you to lock the rows you are selecting and fail transactions that cause a raise condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Understood, I see how the txn could solve issue with asset_should_be_updated

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Race condition fixed in #134

.await?;

// Close out transaction and relinqish the lock.
multi_txn.commit().await?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Need to ensure that we know fully what happens if the TX fails and the reason for the TX failing. Is this a recoverable TX error or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does my explanation above for how SeaORM transactions are rolled back when the object goes out of scope answer the question? Is there some type of recovery we should aim to do, which is different then the current code that afaik just ignores errors and continues on?

@danenbm
Copy link
Contributor Author

danenbm commented Dec 5, 2023

These changes have been incorporated into Version 1 of the update_metadata PR. Closing this PR.

@danenbm danenbm closed this Dec 5, 2023
@danenbm danenbm deleted the danenbm/asset-transactions branch January 18, 2024 22:42
@danenbm danenbm mentioned this pull request Feb 7, 2024
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