brazier/store

Types

A list store — any number of values per key. Appending the same value twice stores it twice. Auto-broadcasts on append/delete.

A local list store is an ETS duplicate_bag and get_all returns values in insertion order. A replicated one returns them in timestamp order (see open_list).

pub type ListStore(value) {
  ListStore(
    table: @internal EtsTable,
    topic: String,
    writer: Writer,
  )
}

Constructors

  • ListStore(
      table: @internal EtsTable,
      topic: String,
      writer: Writer,
    )

Where a store’s data lives.

pub type Mode {
  Local
  Replicated(replicated.Config)
}

Constructors

  • Local

    One table per node; writes and notifications stay on the node.

  • Replicated(replicated.Config)

    A replica on every node that opens the store, kept convergent.

Why open / open_list failed.

pub type OpenError {
  InvalidStore(StoreError)
  InvalidConfig(reason: String)
  StartFailed(reason: String)
}

Constructors

  • InvalidStore(StoreError)

    The name is invalid, or a table of that name exists with another type.

  • InvalidConfig(reason: String)

    The replicated configuration is out of range, or the store is already open in another mode or with a different configuration.

  • StartFailed(reason: String)

    The replica process failed to start.

A key-value store backed by ETS. Auto-broadcasts on put/delete.

pub type Store(value) {
  Store(
    manager: @internal EtsManager,
    topic: String,
    writer: Writer,
  )
}

Constructors

  • Store(
      manager: @internal EtsManager,
      topic: String,
      writer: Writer,
    )

Why a store could not be created or reused. name is the store’s table name: the store name with its prefix (brazier_store_ for a Store, brazier_ls_ for a ListStore), which must be 1-255 bytes of [A-Za-z0-9_-] (it becomes an ETS table atom).

pub type StoreError {
  InvalidName(name: String, reason: String)
  TableTypeMismatch(
    name: String,
    expected: String,
    found: String,
  )
  TableOwnerUnavailable(name: String, reason: String)
}

Constructors

  • InvalidName(name: String, reason: String)

    The name is empty, too long, or has a character outside [A-Za-z0-9_-].

  • TableTypeMismatch(name: String, expected: String, found: String)

    A table with this name already exists with a different type.

  • TableOwnerUnavailable(name: String, reason: String)

    The table owner could not create the table, for example because it crashed owning tables and the application has not restarted.

Why synced / list_synced has no answer.

pub type SyncedError {
  NotReplicated(topic: String)
  ReplicaFailed(replicated.WriteError)
}

Constructors

  • NotReplicated(topic: String)

    The store is Local: it has no replicas to be in sync with. topic names the store.

  • ReplicaFailed(replicated.WriteError)

    The node’s replica did not answer (see replicated.WriteError).

Why a write failed (see brazier/store/replicated.WriteError).

pub type WriteError =
  replicated.WriteError

How a store’s writes are applied.

pub opaque type Writer

Values

pub fn append(
  store: ListStore(value),
  key: String,
  value: value,
) -> Nil

Append a value. Auto-broadcasts to store-level watchers. Crashes the caller (after logging) if the write fails; see try_append.

pub fn append_many(
  store: ListStore(value),
  key: String,
  values: List(value),
) -> Nil

Append multiple values at once. Only broadcasts ONCE after all inserts. Use this instead of calling append() in a loop. Crashes the caller (after logging) if the write fails; see try_append_many.

pub fn append_notify(
  store: ListStore(value),
  key: String,
  value: value,
  topic_prefix: String,
) -> Nil

Append a value and broadcast to both the store topic AND a per-key topic. The per-key topic is prefix <> key (e.g., “room:” <> “general” = “room:general”). Use with brazier.subscriptions() for dynamic per-key subscriptions. Crashes the caller (after logging) if the write fails; see try_append_notify.

pub fn count(store: Store(value)) -> Int

Count total entries. Reads like get.

pub fn delete(store: Store(value), key: String) -> Nil

Delete a value by key. Auto-broadcasts to watchers. Crashes the caller (after logging) if the write fails; see try_delete.

pub fn delete_all(store: ListStore(value), key: String) -> Nil

Delete all values for a key. Auto-broadcasts to store-level watchers. Crashes the caller (after logging) if the write fails; see try_delete_all.

pub fn delete_all_notify(
  store: ListStore(value),
  key: String,
  topic_prefix: String,
) -> Nil

Delete all values for a key and broadcast to a per-key topic. Crashes the caller (after logging) if the write fails; see try_delete_all_notify.

pub fn describe_error(err: StoreError) -> String

A human-readable description of a store error, for logs and messages.

pub fn get(
  store: Store(value),
  key: String,
) -> Result(value, Nil)

Get a value by key.

A replicated store reads its node’s replica. If that replica is down (restarting), the read is logged and crashes the caller.

pub fn get_all(
  store: ListStore(value),
  key: String,
) -> List(value)

Get all values for a key. Reads like get.

pub fn list_synced(
  store: ListStore(value),
) -> Result(Bool, SyncedError)

synced for a list store.

pub fn list_topic(store: ListStore(value)) -> String

Get the PubSub topic for this list store (return it from brazier.subscriptions).

pub fn new(name: String) -> Store(value)

Create (or reuse) a local key-value store. Calling it again with the same name returns the same store.

Store names are developer-supplied constants, so a failure (an invalid name) is a programming error: it is logged and crashes the caller loudly. Use try_new to handle it as a value.

pub fn new_list(name: String) -> ListStore(value)

Create (or reuse) a local list store. Calling it again with the same name returns the same store.

A failure (an invalid name) is a programming error: it is logged and crashes the caller loudly. Use try_new_list to handle it as a value.

pub fn open(
  name: String,
  mode: Mode,
) -> Result(Store(value), OpenError)

Open (or reuse) a key-value store in the given mode.

pub fn open_list(
  name: String,
  mode: Mode,
) -> Result(ListStore(value), OpenError)

Open (or reuse) a list store in the given mode.

A replicated list store orders the values of a key by the hybrid logical clock timestamp of their append: insertion order for appends made on one node, and the same order on every node for concurrent appends on different nodes.

pub fn put(store: Store(value), key: String, value: value) -> Nil

Set a value by key. Auto-broadcasts to watchers. Crashes the caller (after logging) if the write fails; see try_put.

pub fn synced(store: Store(value)) -> Result(Bool, SyncedError)

Whether this node’s replica of a replicated store is in sync with every peer replica: each one last sent a digest equal to this replica’s (see replicated.synced, which this asks). Ok(True) with no peer. Every value written anywhere before those digests were sent is then readable on this node. Each change into sync also emits [brazier, store, synced] (docs/TELEMETRY.md).

A Local store is Error(NotReplicated(..)): it has no replicas, so “in sync” has no meaning for it.

pub fn topic(store: Store(value)) -> String

Get the PubSub topic for this store (return it from brazier.subscriptions).

pub fn try_append(
  store: ListStore(value),
  key: String,
  value: value,
) -> Result(Nil, replicated.WriteError)

Append a value, returning why the write failed.

pub fn try_append_many(
  store: ListStore(value),
  key: String,
  values: List(value),
) -> Result(Nil, replicated.WriteError)

Append multiple values at once, returning why the write failed. In a replicated store the values are one write: all of them or none.

pub fn try_append_notify(
  store: ListStore(value),
  key: String,
  value: value,
  topic_prefix: String,
) -> Result(Nil, replicated.WriteError)

append_notify, returning why the write failed. The per-key topic is checked before the write, so an invalid one writes nothing.

pub fn try_delete(
  store: Store(value),
  key: String,
) -> Result(Nil, replicated.WriteError)

Delete a value by key, returning why the write failed. In a replicated store a value written concurrently on another node survives the delete.

pub fn try_delete_all(
  store: ListStore(value),
  key: String,
) -> Result(Nil, replicated.WriteError)

Delete all values for a key, returning why the write failed. In a replicated store values appended concurrently on another node survive.

pub fn try_delete_all_notify(
  store: ListStore(value),
  key: String,
  topic_prefix: String,
) -> Result(Nil, replicated.WriteError)

delete_all_notify, returning why the write failed.

pub fn try_new(name: String) -> Result(Store(value), StoreError)

Create (or reuse) a local key-value store, returning a typed error for an invalid name.

pub fn try_new_list(
  name: String,
) -> Result(ListStore(value), StoreError)

Create (or reuse) a local list store, returning a typed error for an invalid name.

pub fn try_put(
  store: Store(value),
  key: String,
  value: value,
) -> Result(Nil, replicated.WriteError)

Set a value by key, returning why the write failed.

✨ Search Document