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.

Revisions

  1. christhekeele revised this gist Dec 13, 2017. 1 changed file with 15 additions and 0 deletions.
    15 changes: 15 additions & 0 deletions mnemonix-passthrough-proxy.ex
    Original file line number Diff line number Diff line change
    @@ -17,19 +17,34 @@ defmodule Mnemonix.Stores.Meta.PassThrough do
    "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
    iex> {nil, ^passthrough} = Mnemonix.get_and_update(passthrough, "foo", &({&1, {&1, &1}}))
    iex> Mnemonix.get(passthrough, "foo")
    {nil, nil}
    iex> Mnemonix.Stores.Meta.PassThrough.__info__(:functions) |> IO.inspect(limit: :infinity)
    #=> [bump: 3, bump!: 3, child_spec: 0, child_spec: 1, collectable_into: 2,
    #=> decrement: 2, decrement: 3, delete: 2, deserialize_key: 2,
    #=> deserialize_value: 2, do_bump: 4, do_bump_calculation: 3, drop: 2,
    #=> enumerable?: 1, enumerable_count: 1, enumerable_member?: 2,
    #=> enumerable_reduce: 3, fetch: 2, fetch!: 2, get: 2, get: 3, get_and_update: 3,
    #=> get_and_update!: 3, get_lazy: 3, has_key?: 2, increment: 2, increment: 3,
    #=> keys: 1, msg_for: 2, pop: 2, pop: 3, pop_lazy: 3, put: 3, put_new: 3,
    #=> put_new_lazy: 3, replace: 3, replace!: 3, serialize_key: 2, serialize_value: 2,
    #=> setup: 1, setup_initial: 1, split: 2, start_link: 0, start_link: 1, take: 2,
    #=> teardown: 2, to_enumerable: 1, to_list: 1, update: 4, update!: 3, values: 1]
    This store raises errors on the functions in `Mnemonix.Features.Enumerable`.
    """
  2. christhekeele revised this gist Dec 13, 2017. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions mnemonix-passthrough-proxy.ex
    Original file line number Diff line number Diff line change
    @@ -27,6 +27,9 @@ defmodule Mnemonix.Stores.Meta.PassThrough do
    nil
    iex> Mnemonix.get(backend, "foo")
    nil
    iex> {nil, ^passthrough} = Mnemonix.get_and_update(passthrough, "foo", &({&1, {&1, &1}}))
    iex> Mnemonix.get(passthrough, "foo")
    {nil, nil}
    This store raises errors on the functions in `Mnemonix.Features.Enumerable`.
    """
  3. christhekeele revised this gist Dec 13, 2017. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions mnemonix-passthrough-proxy.ex
    Original file line number Diff line number Diff line change
    @@ -17,6 +17,16 @@ defmodule Mnemonix.Stores.Meta.PassThrough do
    "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`.
    """
  4. christhekeele created this gist Dec 13, 2017.
    89 changes: 89 additions & 0 deletions mnemonix-passthrough-proxy.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,89 @@
    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"
    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