The storage contract Episteme.Database delegates every clause-storage
operation to, so the database's actual persistence strategy is a
pluggable choice rather than baked into Episteme.Database itself.
Ships two implementations -- Episteme.Database.Backends.Ets (the
default: an in-memory ETS table, indexed by {name, arity}) and
Episteme.Database.Backends.Dets (the same shape, backed by a DETS
file on disk, for a database that should survive past the owning
process) -- and any third module implementing this behaviour works
too: pass it as Episteme.Database.new/1's :backend option.
A backend only has to get one thing right: replace_clauses/4 is the
single write primitive every mutation in Episteme.Database
(add_clause/2, add_clause_first/2, and Episteme.Engine's
retract/1/retractall/1) is built from, and clauses_for/3 must
return them back in exactly the order they were last written --
clause-selection order is backtracking order, so a backend that
reorders rows changes program behavior, not just performance.
Summary
Types
Whatever a backend needs to find its own data again -- an ETS tid, a DETS table name, a pid, ...
Callbacks
Every clause currently stored for {name, arity}, in declared/assert order.
Releases whatever resources the backend holds (an ETS table, an open DETS file, ...).
Whether any clause has ever been stored for {name, arity} (including a since-emptied retractall/1).
Initializes fresh backend state from opts (backend-specific -- e.g. :file for Episteme.Database.Backends.Dets).
Replaces the entire clause list for {name, arity}.
Forces any buffered writes to durable storage. A no-op for a purely in-memory backend.
Types
Callbacks
@callback clauses_for(state(), atom(), non_neg_integer()) :: [clause()]
Every clause currently stored for {name, arity}, in declared/assert order.
@callback close(state()) :: :ok
Releases whatever resources the backend holds (an ETS table, an open DETS file, ...).
@callback defined?(state(), atom(), non_neg_integer()) :: boolean()
Whether any clause has ever been stored for {name, arity} (including a since-emptied retractall/1).
Initializes fresh backend state from opts (backend-specific -- e.g. :file for Episteme.Database.Backends.Dets).
@callback replace_clauses(state(), atom(), non_neg_integer(), [clause()]) :: :ok
Replaces the entire clause list for {name, arity}.
@callback sync(state()) :: :ok
Forces any buffered writes to durable storage. A no-op for a purely in-memory backend.