Skip to content

Instantly share code, notes, and snippets.

@christhekeele
Last active December 13, 2017 19:54
Show Gist options
  • Select an option

  • Save christhekeele/1c0dc69d23931c69e1d50fc2fe9ca842 to your computer and use it in GitHub Desktop.

Select an option

Save christhekeele/1c0dc69d23931c69e1d50fc2fe9ca842 to your computer and use it in GitHub Desktop.
An example meta store for Mnemonix
defmodule Mnemonix.Stores.Meta.PassThrough do
@moduledoc """
A `Mnemonix.Store` that caches reads from a backend store into a frontend one.
Writes and removals are applied to both stores.
Works best with quicker or closer stores in the frontend, like in-memory ones;
with a store-wide ttl to keep their footprint light.
iex> {:ok, backend} = Mnemonix.Stores.Redix.start_link()
iex> {:ok, frontend} = Mnemonix.Stores.ETS.start_link()
iex> {:ok, passthrough} = Mnemonix.Stores.Meta.PassThrough.start_link(frontend: frontend, backend: backend)
iex> Mnemonix.put(backend, "foo", "bar")
iex> Mnemonix.get(frontend, "foo")
nil
iex> Mnemonix.get(passthrough, "foo")
"bar"
iex> Mnemonix.get(frontend, "foo")
"bar"
iex> Mnemonix.put(passthrough, "foo", "baz")
iex> Mnemonix.get(frontend, "foo")
"baz"
iex> Mnemonix.get(backend, "foo")
"baz"
iex> Mnemonix.delete(passthrough, "foo")
iex> Mnemonix.get(frontend, "foo")
nil
iex> Mnemonix.get(backend, "foo")
nil
This store raises errors on the functions in `Mnemonix.Features.Enumerable`.
"""
alias Mnemonix.Store
use Store.Behaviour
use Store.Translator.Raw
####
# Mnemonix.Store.Behaviours.Core
##
@doc """
Tracks frontend and backend stores furnished in `opts`.
## Options
- `frontend:` A store reference to cache reads from the backend store in.
- `backend:` A store reference to use as the canonical uncached source of truth.
"""
@impl Store.Behaviours.Core
@spec setup(Store.options()) :: {:ok, state :: term} | {:stop, reason :: any}
def setup(opts) do
{:ok, %{frontend: Keyword.fetch!(opts, :frontend), backend: Keyword.fetch!(opts, :backend)}}
end
####
# Mnemonix.Store.Behaviours.Map
##
@impl Store.Behaviours.Map
@spec delete(Store.t(), Mnemonix.key()) :: Store.Server.instruction()
def delete(%Store{state: state} = store, key) do
%{frontend: frontend, backend: backend} = state
with ^frontend <- Mnemonix.delete(frontend, key),
^backend <- Mnemonix.delete(backend, key) do
{:ok, store}
end
end
@impl Store.Behaviours.Map
@spec fetch(Store.t(), Mnemonix.key()) ::
Store.Server.instruction({:ok, Mnemonix.value()} | :error)
def fetch(%Store{state: state} = store, key) do
%{frontend: frontend, backend: backend} = state
if value = Mnemonix.get(frontend, key) do
{:ok, store, {:ok, value}}
else
if value = Mnemonix.get(backend, key) do
with ^frontend <- Mnemonix.put(frontend, key, value) do
{:ok, store, {:ok, value}}
end
else
{:ok, store, :error}
end
end
end
@impl Store.Behaviours.Map
@spec put(Store.t(), Mnemonix.key(), Mnemonix.value()) :: Store.Server.instruction()
def put(%Store{state: state} = store, key, value) do
%{frontend: frontend, backend: backend} = state
with ^frontend <- Mnemonix.put(frontend, key, value),
^backend <- Mnemonix.put(backend, key, value) do
{:ok, store}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment