Skip to content
Christopher Keele edited this page Dec 13, 2017 · 4 revisions

Mnemonix is, at its core, a traditional but very rich GenServer client/server interface.

The Client

The Mnemonix Client API functions convert any conceivable key/value store operation into a Mnemonix.Store.Server call. The server dispatches this instruction to its underlying store implementation and responds with the result; depending on the format of this response the client can either return successfully, return while issuing a warning, or raise an exception.

Forcing every client command to go through a synchronous GenServer call, even when not strictly necessary, ensures that every operation upon a store issued through the Mnemonix API is functionally atomic.

Features

The Mnemonix Client API is actually implemented in a series of discrete modules called 'features'. Each feature groups together conceptually related functions. We perform this grouping for a couple of reasons:

  • It provides a place to document general usage of each feature-set in its module docs
  • It allows for drilling down into function documentation for a specific set of operations rather than having to exclusively peruse the rather wide client API
  • It allows for building custom client APIs that only expose some of the full breadth of Mnemonix by cherrypicking certain feature-sets

The core value proposition of Mnemonix is to allow you to use the Map API on any key/value store. This is where these map-parity functions go.

To ensure we keep this promise, we actively test that (with a few exceptions) we are offering an identical API.

Atomically incrementing and decrementing integer values is a common use-case for key/value stores, and many offer a dedicated API for these operations, so Mnemonix does as well.

Another common desire is to instrument entries within a key/value store with a ttl (time-to-live), after which they remove themselves from the store. This is especially useful for stores being used as expiring caches. Mnemonix supports setting store-wide ttls as well as per-entry ones for any kind of store.

While not always advisable, it is often desirable to enumerate over all entries within a key/value store. Operations that do so, including ones that would otherwise belong in the Map feature, are contained here.

Not every store supports enumeration; unless configured to do so the store server will instruct the client to raise a Mnemonix.Features.Enumerable.Exception at the call site of the enumerable feature function. The store can be tested at runtime for enumeration support via Mnemonix.enumerable?/1.

Client/Server communication

All instructions sent to the server take the form of a tuple representing the feature function being invoked, with all arguments (minus the leading store server parameter itself). So Mnemonix.put_and_expire(store, key, value, ttl) becomes GenServer.call(store, {:put_and_expire, key, value, ttl}).

Calls to the server that represent protocol implementation function invocations use a two-tuple of the protocol name and implementation function in lieu of a feature function name, such as GenServer.call(store, {{Access, :get}, key, default}).

The server interprets this as a call to the underlying store implementation. It performs the requested operation and updates the server's internal state if necessary. It then re-interprets the result of the operation with an instruction to the client to either return, warn and return, or raise. These replies take one of the formats:

  • success: :ok

    The operation was successful and provided no useful return value. Normally the client handles this by returning the store reference itself, but sometimes returns :ok instead.

  • success and return: {:ok, value}

    The operation was successful and the value is returned in the client.

  • warn: {:warn, message}

    The operation was successful but should emit a warning. The operation produced no useful return value.

  • warn: {:warn, message, value}

    The operation was successful but should emit a warning. The client should return the provided value.

  • error: {:raise, exception_module, args}

    The operation failed. The client should raise an exception of the given type using the provided args.

The Server

Server/Implementation communication

Store Behaviours

Store Implementations