SimpleMemCache

Trade memory for performance.

In-memory key-value cache with expiration-time after creation/modification/access (a.k.a. entry time-to-live and entry idle-timeout), automatic value loading and time travel support.

Installation

  1. Add simple_mem_cache to your list of dependencies in mix.exs:
```elixir
def deps do
[{:simple_mem_cache, "~> 0.1"}]
end
```
  1. mix deps.get
```sh
$ mix deps.get
```
  1. create ets table:

Only ets types: set and ordered_set are supported.

To create the ets table I recommend Eternal.

Code will be something like this:

```elixir
defmodule MyProject do
use Application

def start(_type, _args) do import Supervisor.Spec, warn: false

Eternal.new(SimpleMemCache, [ :named_table, :set, { :read_concurrency, true }, { :write_concurrency, true }])
```

Usage

Keep in cache for a limited time, automatically load new value after that

Note about automatically new value loading:

Keep in cache for a limited time but extend life-time everytime it is accessed

Keep as long this process is running

or you can force an automatically load at first access by invalidating the cached item.

Invalidate cached item

IEx demo

$ iex -S mix
Interactive Elixir (1.3.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> f_now = fn -> DateTime.to_string(DateTime.utc_now()) end
#Function<20.52032458/0 in :erl_eval.expr/5>
iex(2)> tid = :ets.new(__MODULE__, [:set, :public, {:read_concurrency, true}, {:write_concurrency, true}])
127009
iex(3)> SimpleMemCache.put(tid, "key1", "value1")
"value1"
iex(4)> SimpleMemCache.get(tid, "key1")
{:ok, "value1"}
iex(5)> SimpleMemCache.get!(tid, "key1")
"value1"
iex(6)> SimpleMemCache.remove(tid, "key1")
"value1"
iex(7)> SimpleMemCache.get(tid, "key1")
{:not_cached, nil}
iex(8)> SimpleMemCache.get!(tid, "key1")
nil
iex(9)> IO.puts f_now.(); SimpleMemCache.put(tid, "key1", 1, "value1"); # one minute
2016-08-03 22:42:04.410133Z
"value1"
iex(10)> IO.puts f_now.(); SimpleMemCache.get(tid, "key1")
2016-08-03 22:42:36.641060Z
{:ok, "value1"}
iex(11)> IO.puts f_now.(); SimpleMemCache.get(tid, "key1")
2016-08-03 22:43:10.278992Z
{:expired, "value1"}
iex(12)> f_new_value = fn -> IO.puts "new"; "value2" end
#Function<20.52032458/0 in :erl_eval.expr/5>
iex(13)> IO.puts f_now.(); SimpleMemCache.cache(tid, "key2", 1, f_new_value); # one minute
2016-08-03 22:45:10.551159Z
new
"value2"
iex(14)> IO.puts f_now.(); SimpleMemCache.cache(tid, "key2", 1, f_new_value); # one minute
2016-08-03 22:45:16.410884Z
"value2"
iex(15)> SimpleMemCache.get(tid, "key1")
{:not_cached, nil}
iex(16)> SimpleMemCache.put(tid, "key2", "value2_changed")
"value2_changed"
iex(17)> SimpleMemCache.get(tid, "key2")
{:ok, "value2_changed"}
iex(18)> SimpleMemCache.put(tid, "key3", %{"a" => 1, "b" => {1, 2, "whatever"}}) # put whatever you want
%{"a" => 1, "b" => {1, 2, "whatever"}}
iex(19)> SimpleMemCache.get!(tid, "key3") |> Map.get("b")
{1, 2, "whatever"}
iex(20)> SimpleMemCache.stop(tid)
:ok
iex(21)> SimpleMemCache.get!(tid, "key2")
** (ArgumentError) argument error
(stdlib) :ets.lookup(127009, "Elixir.SimpleMemCache_state")
(simple_mem_cache) lib/simple_mem_cache.ex:139: SimpleMemCache.get_cache_state!/1
(simple_mem_cache) lib/simple_mem_cache.ex:105: SimpleMemCache.get/3
(simple_mem_cache) lib/simple_mem_cache.ex:111: SimpleMemCache.get!/3

License

MIT