Mnemonix v0.4.0 Mnemonix.Store.Behaviour

Main point of entry for implementing new Mnemonix.Stores.

To create new store, you simply use this module as a meta-behaviour that brings in many others.

It will implement start_link/1, start_link/2, and start_link/3 functions and bring in the actual Mnemonix behaviours:

  • Mnemonix.Core.Behaviour: required callbacks with no default implementation a store must provide
  • Mnemonix.Lifecycle.Behaviour: support for c:GenServer:init/1 and c:GenServer:terminate/2
  • Mnemonix.Map.Behaviour: support for map operations
  • Mnemonix.Expiry.Behaviour: support for expires/persist operations
  • Mnemonix.Bump.Behaviour: support for increment/decrement operations

These behaviours may have required callbacks you need to implement for the store to work, and optional callbacks with default implementations that leverage the required ones to make the store fully featured.

Core Callbacks

Currently the callbacks you must implement for a full-featured store are:

  • c:Mnemonix.Core.Behaviour.setup/1
  • c:Mnemonix.Core.Behaviour.delete/2
  • c:Mnemonix.Core.Behaviour.fetch/2
  • c:Mnemonix.Core.Behaviour.put/3

All other Mnemonix functions can be implemented in terms of them.

Optional Callbacks

Every single Mnemonix function/arity combo has a corresponding callback. Those that are not required have default implementations, normally in terms of the core ones. However, these implementations are all marked as overridable, so if the store you are building offers native support for an operation, you can call it directly to provide a more efficient implementation.

If any these callbacks don’t make sense to implement in the context of the store you’re developing, feel free to override them to raise an exception when they are used. Most callbacks are expected to return some variant of {:ok, updated_store, return_value}, but if they return {:error, ExceptionModule, args}, it will raise the exception at the Mnemonix call site, keeping the store process alive.

Building a Store

Mnemonix.Map.Store exists mostly to provide a reference implementation for store developers, demonstrating the minimum necessary to get a store working.

Mnemonix.ETS.Store is a good example of a store that requires more complicated initialization logic.

Mnemonix.Redix.Store is a good example of a store that overrides optional callbacks with native support for Mnemonix.Expiry.Behaviour and Mnemonix.Bump.Behaviour.

Adding Capabilities to Mnemonix

Mnemonix is powered by a non-trivial set of interfaces. If you want to contribute functionality to the core Mnemonix module, you must understand how they all work. Reading the source code is the best way to do this, but here’s a high level overview.

Mnemonix.Store

Every Mnemonix.Store is just a GenServer with a very particular interface and state.

Mnemonix.Store.start_link

When the store is started, it goes through an initialization pipeline provided by init/1. First it invokes c:Mnemonix.Lifecycle.Behaviour.setup/1 to prepare private internal state from user-provided options, then it allows utilities to do feature-specific setup in extra callbacks like c:Mnemonix.Expiry.Behaviour.setup_expiry/1.

The Mnemonix.Store struct

The state of the Mnemonix.Store server, and result of init/1, is a struct containing:

  • impl: the underlying store module to make calls to
  • opts: the options this store was configured with in init/1
  • state: the store-specific result of c:Mnemonix.Lifecycle.Behaviour.setup/1
  • expiry: the store-specific result of c:Mnemonix.Expiry.Behaviour.setup_expiry/1

Mnemonix => Mnemonix.Store

Mnemonix functions invoke GenServer.call/3.