ShareLock
ShareLock is the row-level locking mechanism used internally by PostgreSQL.
Deadlocks and prevention
When several DB transactions are acting on multiple rows of the same table, it's possible to incur in a deadlock and so into an error. This can be prevented by enforcing the same consistent order of lock acquisition on all the transactions performing 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.
Imposing the lock acquisition order on a table with Ecto
When 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:
Performing 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:
Imposing the lock acquisition order between tables with Ecto
When using an 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:
When possible, the simple solution is to move :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:
Note also that for the same reasons multiple operations on the same table in the same transaction are not safe to perform if they each acquire locks in order, because locks are not released until the transaction is committed.
Order used for Explorer's tables
This is a complete list of the ordering currently in use on each table. It also specifies the order between tables in the same transaction: locks for a table on top need to be acquired before those from a table on the bottom.
Note that this should always be enforced because as long as there is one DB transaction performing in a different order there is the possibility of a deadlock.
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.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: :address_hash, asc: :token_contract_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]
Last updated