Prev Next

Database / Mnesia intermediate to advanced Interview questions

How do you handle a transaction that needs to retry after being aborted due to a deadlock?

When Mnesia detects a deadlock between two transactions, it aborts one of them automatically, but it doesn't retry it for you — the calling code gets back {aborted, Reason} and is responsible for deciding whether and how to retry.

retry_transaction(Fun, Retries) when Retries > 0 ->
    case mnesia:transaction(Fun) of
        {atomic, Result} -> {ok, Result};
        {aborted, {deadlock, _}} ->
            timer:sleep(rand:uniform(50)),   %% small random backoff
            retry_transaction(Fun, Retries - 1);
        {aborted, Reason} -> {error, Reason}
    end;
retry_transaction(_Fun, 0) -> {error, max_retries_exceeded}.

A short, randomized backoff before retrying helps avoid two competing transactions immediately re-colliding in the same way; a bounded retry count avoids looping forever if the underlying contention doesn't clear. This retry logic is application-level code you write yourself — Mnesia's job ends at correctly detecting and aborting one side of the deadlock, not resubmitting the work.

Does Mnesia automatically retry a transaction it aborts due to deadlock?
Why add a small randomized backoff before retrying an aborted transaction?

More Related questions...

What is the difference between mnesia:transaction/1 and mnesia:sync_transaction/1? What is the difference between async_dirty and sync_dirty activity contexts? How does mnesia:activity/4 let you customize the access context of an operation? What is table fragmentation in Mnesia and why would you use it? How do you configure a fragmented Mnesia table? Why does fragmentation help Mnesia scale beyond what one table replica set can handle? What is the difference between mnesia:match_object/1 and mnesia:select/2? What is mnesia:all_keys/1 used for? How do you integrate Mnesia with QLC for complex queries? Why would you use qlc:q with mnesia:table/1 instead of mnesia:select/2? What is a sticky lock in Mnesia and why does it improve performance? When can sticky locks cause a problem in a distributed Mnesia cluster? How do you dynamically add a new node to a running Mnesia cluster? What is mnesia:change_config(extra_db_nodes, Nodes) used for? How do you remove a table replica from a node without dropping the whole table? What is mnesia:del_table_copy/2 used for? How do you move a table copy from one node to another while the system stays live? What is mnesia:move_table_copy/3 used for? What is the {majority, true} table option and what tradeoff does it introduce? Why would you enable the majority option on a table prone to network partitions? What is a local_content table in Mnesia? When would you use a local_content table instead of a normal replicated table? What is mnesia:set_master_nodes/2 used for? How does setting master nodes influence conflict resolution after a network partition? What is mnesia_tm and what role does it play internally? How does Mnesia's transaction manager serialize concurrent transactions touching the same records? Why can a "hot" record or table become a bottleneck under heavy Mnesia write load? How can you redesign a schema to reduce lock contention on a frequently-updated record? What is mnesia:subscribe/1 used for? How do you react to table events using Mnesia's subscription mechanism? What is a nested Mnesia transaction and how does it behave differently from a top-level one? Why should nested transactions generally be avoided or used carefully in Mnesia? What is the dc_dump_limit configuration parameter used for? Why does tuning the transaction log dump frequency matter for write-heavy Mnesia workloads? How do you merge two previously-separate Mnesia clusters into one? What complications arise when merging schemas from two independently-created Mnesia databases? How does Mnesia decide which node's data wins during schema merge conflicts? What is the difference between a global lock and a per-record lock in Mnesia transactions? When would you use mnesia:read_lock_table/1 instead of relying on per-record locks? How do you profile and optimize Mnesia transaction throughput in a write-heavy system? Why is batching multiple related writes into a single transaction usually better than many small transactions? How does Mnesia's schema interact with OTP release upgrades (appup/relup)? What is the difference between mnesia:dirty_all_keys/1 and mnesia:all_keys/1? Explain the internal working of how Mnesia chooses which replica to read from in a load-balanced cluster? What is the where_to_read table_info item used for? What is mnesia:dump_log/0 used for? How do you handle a transaction that needs to retry after being aborted due to a deadlock? What is the difference between mnesia:transaction/1's built-in behavior and manual retry logic you might add?
Show more question and Answers...


Comments & Discussions