ShareLock is the row-level locking mechanism used internally by PostgreSQL.
INSERT
, UPDATE
or DELETE
on a given table.
On top of this, if multiple DB transactions act on multiple tables a deadlock will occur, even if they follow the order on each table described above, if they acquire locks on said tables in a different order. This can also be prevented by using a consistent order of lock acquisition between different tables.
INSERT
ing a list of rows Postgres will respect the order in which they appear in the query, so the reordering can happen beforehand.
For example, this will work:
UPDATE
s is trickier because there is no ORDER BY
clause. The solution to this is to JOIN
on a subquery that SELECT
s with the option FOR UPDATE
.
Using Ecto this can be done, for example, like this:
DELETE
has the same quirks as UPDATE
and it is too solved in the same way.
For example:
Ecto.Multi
to perform INSERT
, UPDATE
or DELETE
on multiple tables the order to keep is between different operation. For example, supposing EntryA
was established to be modified before EntryB
, this is not correct:
:update_a
to be before :update_b
. When not possible, for instance if :update_a
depends on the result of :update_b
, this can be solved by acquiring the locks in a separate operation.
For example:
schema module | table name | ordered by |
---|---|---|
Explorer.Chain.Address | addresses | [asc: :hash] |
Explorer.Chain.Address.Name | address_names | [asc: :address_hash, asc: :name] |
Explorer.Chain.Address.CoinBalance | address_coin_balances | [asc: :address_hash, asc: :block_number] |
Explorer.Chain.Block | blocks | [asc: :hash] |
Explorer.Chain.Block.SecondDegreeRelation | block_second_degree_relations | [asc: :nephew_hash, asc: :uncle_hash] |
Explorer.Chain.Block.Reward | block_rewards | [asc: :address_hash, asc: :address_type, asc: :block_hash] |
Explorer.Chain.Block.EmissionReward | emission_rewards | [asc: :block_range] |
Explorer.Chain.Transaction | transactions | [asc: :hash] |
Explorer.Chain.Transaction.Fork | transaction_forks | [asc: :uncle_hash, asc: :index] |
Explorer.Chain.Log | logs | [asc: :transaction_hash, asc: :index] |
Explorer.Chain.InternalTransaction | internal_transactions | [asc: :transaction_hash, asc: :index] |
Explorer.Chain.Token | tokens | [asc: :contract_address_hash] |
Explorer.Chain.TokenTransfer | token_transfers | [asc: :transaction_hash, asc: :log_index] |
Explorer.Chain.TransactionAction | transaction_actions | [asc: :hash, asc: :log_index] |
Explorer.Chain.PolygonEdge.Deposit | polygon_edge_deposits | [asc: :msg_id] |
Explorer.Chain.PolygonEdge.DepositExecute | polygon_edge_deposit_executes | [asc: :msg_id] |
Explorer.Chain.PolygonEdge.Withdrawal | polygon_edge_withdrawals | [asc: :msg_id] |
Explorer.Chain.PolygonEdge.WithdrawalExit | polygon_edge_withdrawal_exits | [asc: :msg_id] |
Explorer.Chain.Optimism.OutputRoot | op_output_roots | [asc: :l2_output_index] |
Explorer.Chain.Optimism.TxnBatch | op_transaction_batches | [asc: :l2_block_number] |
Explorer.Chain.Optimism.Deposit | op_deposits | [asc: :l2_transaction_hash] |
Explorer.Chain.Optimism.DisputeGame | op_dispute_games | [asc: :index] |
Explorer.Chain.Optimism.FrameSequence | op_frame_sequences | [asc: :id] |
Explorer.Chain.Optimism.FrameSequenceBlob | op_frame_sequence_blobs | [asc: :id] |
Explorer.Chain.Optimism.WithdrawalEvent | op_withdrawal_events | [asc: :withdrawal_hash, asc: :l1_event_type] |
Explorer.Chain.Optimism.Withdrawal | op_withdrawals | [asc: :msg_nonce] |
Explorer.Chain.Optimism.EIP1559ConfigUpdate | op_eip1559_config_updates | [asc: :l2_block_number] |
Explorer.Chain.Optimism.InteropMessage | op_interop_messages | [asc: :nonce, asc: :init_chain_id] |
Explorer.Chain.Address.TokenBalance | address_token_balances | [asc: :address_hash, asc: :token_contract_address_hash, asc: :block_number] |
Explorer.Chain.Address.CurrentTokenBalance | address_current_token_balances | [asc: :token_contract_address_hash, asc: :token_id, asc: :address_hash] |
Explorer.Chain.Scroll.Batch | scroll_batches | [asc: number] |
Explorer.Chain.Scroll.BatchBundle | scroll_batch_bundles | [asc: final_batch_number] |
Explorer.Chain.Scroll.Bridge | scroll_bridge | [asc: :type, asc: message_hash] |
Explorer.Chain.Scroll.L1FeeParam | scroll_l1_fee_params | [asc: :block_number, asc: tx_index, asc: name] |
Explorer.Chain.Shibarium.Bridge | shibarium_bridge | [asc: :operation_hash, asc: l1_transaction_hash, asc: l2_transaction_hash] |
Explorer.Chain.StakingPool | staking_pools | [asc: :staking_address_hash] |
Explorer.Chain.StakingPoolsDelegator | staking_pools_delegators | [asc: :delegator_address_hash, asc: :pool_address_hash] |
Explorer.Chain.ContractMethod | contract_methods | [asc: :identified, asc: :abi] |
Explorer.Market.MarketHistory | market_history | [asc: :date] |
Explorer.Chain.Withdrawal | withdrawals | [asc: :index] |
Explorer.Chain.Zkevm.TransactionBatch | zkevm_transaction_batches | [asc: :number] |
Explorer.Chain.Zkevm.BatchTransaction | zkevm_batch_l2_transactions | [asc: :hash] |
Explorer.Chain.Zkevm.LifecycleTransaction | zkevm_lifecycle_l1_transactions | [asc: :id] |
Explorer.Chain.Zkevm.Bridge | zkevm_bridge | [asc: :type, asc: :index] |
Explorer.Chain.Zkevm.BridgeL1Token | zkevm_bridge_l1_tokens | [asc: :address] |
Explorer.Chain.ZkSync.TransactionBatch | zksync_transaction_batches | [asc: :number] |
Explorer.Chain.ZkSync.BatchBlock | zksync_batch_blocks | [asc: :hash] |
Explorer.Chain.ZkSync.BatchTransaction | zksync_batch_transactions | [asc: :hash] |
Explorer.Chain.ZkSync.LifecycleTransaction | zksync_lifecycle_transactions | [asc: :id] |
Explorer.Chain.Celo.EpochReward | celo_epoch_rewards | [asc: :block_hash] |
Explorer.Chain.Celo.PendingEpochBlockOperation | celo_pending_epoch_block_operations | [asc: :block_hash] |
Explorer.Chain.Celo.ValidatorGroupVote | celo_epoch_validator_group_votes | [asc: :transaction_hash, asc: :account_address_hash, asc: :group_address_hash] |
Explorer.Chain.Celo.ElectionReward | celo_election_rewards | [asc: :block_hash, asc: type, asc: :account_address_hash, asc: :associated_account_address_hash] |
Explorer.Chain.Zilliqa.QuorumCertificate | zilliqa_quorum_certificates | [asc: :block_hash] |
Explorer.Chain.Zilliqa.AggregateQuorumCertificate | zilliqa_aggregate_quorum_certificates | [asc: :block_hash] |
Explorer.Chain.Zilliqa.NestedQuorumCertificate | zilliqa_nested_quorum_certificates | [asc: :block_hash, asc: proposed_by_validator_index] |
Explorer.Chain.Filecoin.PendingAddressOperation | filecoin_pending_address_operations | [asc: :address_hash] |