BeamAgent.Store (beam_agent_ex v0.1.0)

Copy Markdown View Source

Store adapter boundary for canonical BeamAgent domains.

This module wraps the Erlang :beam_agent_store boundary, providing idiomatic Elixir access to domain-level persistence configuration. Domains default to the ETS adapter (:beam_agent_store_ets); callers only need this module when switching a domain to a durable adapter such as :beam_agent_store_dets.

Quick start

# Switch a domain to DETS-backed durable storage
:ok = BeamAgent.Store.configure_domain(:my_domain, %{
  adapter: :beam_agent_store_dets,
  options: %{data_dir: "/var/data", ram_file: false}
})

# With atomic counters for concurrent-safe increments
:ok = BeamAgent.Store.configure_domain(:my_domain, %{
  adapter: :beam_agent_store_dets,
  options: %{data_dir: "/var/data", atomic_counters: true}
})

# Query current config
%{adapter: :beam_agent_store_dets} = BeamAgent.Store.domain_config(:my_domain)

# Reset back to default ETS adapter
:ok = BeamAgent.Store.reset_domain(:my_domain)

Available adapters

AdapterDescription
:beam_agent_store_etsDefault. In-memory ETS with hardened-mode write proxying.
:beam_agent_store_detsDurable disk-backed DETS. Supports atomic_counters option.

DETS store options

OptionTypeDefaultDescription
data_dirbinary or string"beam_agent_data"Directory for .dets files
auto_savenon_neg_integer or :infinity30000Auto-save interval in ms
ram_filebooleanfalseKeep file contents in RAM (useful for tests)
atomic_countersbooleanfalseUse atomics CAS loops for lock-free counter increments

Summary

Types

A store adapter module implementing the beam_agent_store behaviour.

A canonical domain atom (e.g., :runs, :artifacts, :journal).

Store configuration map.

Store key type.

Adapter-specific options passed through to the backing store.

ETS/DETS table name.

Counter update operation.

Functions

Return the adapter module backing a domain.

Clear all domain store configuration and revert every domain to defaults.

Close a DETS table file.

Configure a persistence adapter for a canonical domain.

Resolve the data directory from DETS store options.

Return the normalized store config for a domain, including defaults.

Ensure the store configuration table exists. Idempotent.

Flush in-memory atomic counter values back to their DETS records.

Remove any custom store config for a domain and restore defaults.

Flush pending writes for a DETS table to disk.

Types

adapter_module()

@type adapter_module() :: module()

A store adapter module implementing the beam_agent_store behaviour.

domain()

@type domain() :: atom()

A canonical domain atom (e.g., :runs, :artifacts, :journal).

store_config()

@type store_config() :: %{
  :adapter => adapter_module(),
  optional(:options) => store_options()
}

Store configuration map.

Must contain :adapter (a module implementing the store behaviour). May contain :options (adapter-specific settings).

store_key()

@type store_key() :: atom() | binary() | tuple() | pid() | integer()

Store key type.

Covers the common BEAM key types used across BeamAgent domains.

store_options()

@type store_options() :: map()

Adapter-specific options passed through to the backing store.

table_name()

@type table_name() :: atom()

ETS/DETS table name.

update_op()

@type update_op() ::
  integer()
  | {pos_integer(), integer()}
  | {pos_integer(), integer(), integer(), integer()}

Counter update operation.

  • Integer: increment element at position 2 by the given amount.
  • {pos, incr}: increment element at pos by incr.
  • {pos, incr, threshold, set_value}: bounded increment.

Functions

adapter_module(domain)

@spec adapter_module(domain()) :: adapter_module()

Return the adapter module backing a domain.

Example

:beam_agent_store_ets = BeamAgent.Store.adapter_module(:runs)

clear()

@spec clear() :: :ok

Clear all domain store configuration and revert every domain to defaults.

close_table(table)

@spec close_table(table_name()) :: :ok

Close a DETS table file.

Flushes any in-memory atomic counter values to disk before closing. Safe to call on tables that are not open. No-op for ETS-backed domains.

Example

:ok = BeamAgent.Store.close_table(:my_dets_table)

configure_domain(domain, config)

@spec configure_domain(domain(), store_config()) ::
  :ok | {:error, :invalid_options | {:invalid_adapter, atom()}}

Configure a persistence adapter for a canonical domain.

Domains default to :beam_agent_store_ets. Use this to switch a domain to :beam_agent_store_dets or any custom adapter implementing the beam_agent_store behaviour.

Returns :ok on success, or {:error, reason} for invalid config.

Example

:ok = BeamAgent.Store.configure_domain(:my_domain, %{
  adapter: :beam_agent_store_dets,
  options: %{data_dir: "/var/data"}
})

data_dir(store_opts)

@spec data_dir(store_options()) :: String.t()

Resolve the data directory from DETS store options.

Returns the directory path where .dets files are stored as a binary string. Defaults to "beam_agent_data" when no data_dir is configured.

The underlying Erlang function returns a charlist (file:filename()); this wrapper converts it to a binary for idiomatic Elixir usage.

Examples

"beam_agent_data" = BeamAgent.Store.data_dir(%{})
"/var/data" = BeamAgent.Store.data_dir(%{data_dir: "/var/data"})

domain_config(domain)

@spec domain_config(domain()) :: store_config()

Return the normalized store config for a domain, including defaults.

Example

%{adapter: :beam_agent_store_ets, options: %{}} =
  BeamAgent.Store.domain_config(:default_domain)

ensure_tables()

@spec ensure_tables() :: :ok

Ensure the store configuration table exists. Idempotent.

flush_counters(table)

@spec flush_counters(table_name()) :: :ok

Flush in-memory atomic counter values back to their DETS records.

No-op when atomic_counters is not enabled or no counters have been incremented for table. After flushing, tracking entries are removed so the next update_counter re-seeds from DETS.

Called automatically by close_table/1 and sync_table/1.

Example

:ok = BeamAgent.Store.flush_counters(:my_dets_table)

reset_domain(domain)

@spec reset_domain(domain()) :: :ok

Remove any custom store config for a domain and restore defaults.

Example

:ok = BeamAgent.Store.reset_domain(:my_domain)

sync_table(table)

@spec sync_table(table_name()) :: :ok

Flush pending writes for a DETS table to disk.

Also flushes any in-memory atomic counter values before syncing.

Example

:ok = BeamAgent.Store.sync_table(:my_dets_table)