MishkaInstaller.Helper.MnesiaAssistant.Transaction (Mishka Installer v0.1.16)

Copy Markdown View Source

Runs Mnesia activities and maps aborted results to the installer's error shape.

Summary

Functions

Runs fun, a function of dirty reads (MishkaInstaller.Helper.MnesiaAssistant.Query's dirty_* functions), and answers like transaction/1: {:atomic, result}, or {:aborted, reason} when Mnesia aborts a read because it is not running or the table does not exist.

Runs fun inside a durable transaction: :mnesia.sync_transaction/1 to commit on every node holding a copy of the table, then :mnesia.sync_log/0 to flush the transaction log to disk before returning.

Runs fun as a fast, dirty ets activity. Delegates to :mnesia.ets/1.

Runs fun inside a Mnesia transaction. Delegates to :mnesia.transaction/1.

Builds a standard {:error, [map]} from an aborted transaction reason.

Functions

dirty(fun)

@spec dirty((-> any())) :: {:atomic, any()} | {:aborted, term()}

Runs fun, a function of dirty reads (MishkaInstaller.Helper.MnesiaAssistant.Query's dirty_* functions), and answers like transaction/1: {:atomic, result}, or {:aborted, reason} when Mnesia aborts a read because it is not running or the table does not exist.

A dirty read looks the record up in the node's own ETS copy of the table. It takes no lock and sends nothing to Mnesia's transaction or lock manager, so concurrent readers never queue behind one process, and a read never waits for a write that holds the record. It sees every record as last committed; the writes stay in durable_transaction/1, which re-reads under a write lock.

The catch is the boundary where Mnesia's abort exit becomes {:aborted, reason}: a read that succeeds runs no exception code.

durable_transaction(fun)

@spec durable_transaction((-> any())) :: {:atomic, any()} | {:aborted, term()}

Runs fun inside a durable transaction: :mnesia.sync_transaction/1 to commit on every node holding a copy of the table, then :mnesia.sync_log/0 to flush the transaction log to disk before returning.

Use it for writes that must survive an unclean node exit. transaction/1 alone buffers the commit and only reaches the disk on the periodic dump (dump_log_time_threshold, three minutes by default), so a node that dies in between comes back with the old record — and a plugin's :stopped/:started status is an operator's setting, not a cache.

Returns {:atomic, result} or {:aborted, reason}.

ets(fun)

@spec ets((-> any())) :: any()

Runs fun as a fast, dirty ets activity. Delegates to :mnesia.ets/1.

Only safe for ram_copies tables or read-only access on disc_copies.

transaction(fun)

@spec transaction((-> any())) :: {:atomic, any()} | {:aborted, term()}

Runs fun inside a Mnesia transaction. Delegates to :mnesia.transaction/1.

Returns {:atomic, result} or {:aborted, reason}.

transaction_error(reason, module, type, field, action)

@spec transaction_error(term(), module(), String.t(), atom(), atom()) ::
  {:error, [map()]}

Builds a standard {:error, [map]} from an aborted transaction reason.

The returned map carries :message, :field, :action and the raw :source error, so callers can surface a consistent error across the codebase.

Example

transaction_error(reason, MyTable, "reading", :global, :database)