Tama.Dex.Index (tama_dex v0.1.0)

Copy Markdown View Source

The SQLite index of operation documents.

A host starts the index under its own supervisor, with an explicit database location, and passes it (a pid or registered name) into every Tama.Dex call. tama-dex has no application callback, so nothing is opened until a host starts an index.

children = [
  {Tama.Dex.Index, path: "/var/lib/my_host/tama-dex.sqlite3", name: MyHost.Index}
]

One index holds every cassette the host installs. Each cassette is a namespace inside it.

Options

  • :path (required): a database file path, or :memory. A new file is created with mode 0600 and opened in WAL mode. Its directory must exist. :memory keeps the index in memory for the life of the process, which suits tests and short-lived hosts.
  • :name (optional): a name to register the index under.
  • :limits (optional): lower limits for documents loaded into this index, as a keyword list of :max_document_bytes, :max_operations and :max_schema_bytes. They can't exceed the profile's limits.

Processes

The index process holds state and coordinates two linked workers, each owning one connection. The reader serves queries and the writer runs loads and imports one at a time. In a file-backed index, WAL mode lets reads see the last committed state while a write runs. An in-memory index shares one memdb database between the two connections, so a read issued during a write may wait for the commit, but never sees a mixture.

The database is derived data. One whose storage schema version this code doesn't know is recreated empty, emitting [:tama_dex, :index, :recreated], and the host loads its documents again.

Readiness

status/1 reports whether the index can serve. Search must never block or fail a host's startup, so while nothing is committed and a load or import runs, Tama.Dex.search/3 and Tama.Dex.describe/4 return {:error, :not_ready} and Tama.Dex.execute/5 a :not_ready error, without waiting. See status/1.

Summary

Functions

Starts an index. See the module documentation for the options.

The index's readiness as a whole

Types

progress()

@type progress() :: %{
  cassette: String.t(),
  done: non_neg_integer(),
  total: non_neg_integer()
}

status()

@type status() :: :ready | {:importing, progress()} | {:failed, atom()} | :empty

t()

@type t() :: GenServer.server()

Functions

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts an index. See the module documentation for the options.

Raises ArgumentError, creating nothing, when :path is missing or an option is invalid.

status(index)

@spec status(t()) :: status()

The index's readiness as a whole:

  • :ready whenever at least one cassette is committed, even while other loads or imports run or after one has failed;
  • otherwise {:importing, %{cassette, done, total}} while a load or import runs or waits, counting sources;
  • otherwise {:failed, reason} when the last attempt failed, with the kind of its error, such as :deadline;
  • otherwise :empty.

:ready means at least one cassette is committed, not all of them. Each cassette's own status is in Tama.Dex.cassettes/1. Every change emits [:tama_dex, :index, :status] with the new status and the index pid in its metadata.

Reads the index's state only, so it never waits on SQLite.