View Source SimpleMemCache (simple_mem_cache v1.0.1)

In-memory key-value cache with expiration-time after creation/modification/access, automatic value loading and time travel support.

Prepare ETS table to be used by SimpleMemCache

Example 1: plain ETS:

  tid = :ets.new(__MODULE__, [:set,
                               :public,
                              {:read_concurrency,  true},
                              {:write_concurrency, true}
                             ])

Example 2: use Eternal to create the ETS table:


  defmodule MyProject do
    use Application

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

      Eternal.start_link(SimpleMemCache,
                         [:set,
                          {:read_concurrency,  true},
                          {:write_concurrency, true}
                         ])

Only ETS types: set and ordered_set are supported.

Usage

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

  • Example: scrape news and keep it 10 minutes in cache

    us_news = SimpleMemCache.cache(SimpleMemCache, "news_us", 10,
                                   &Scraper.scrape_news_us/0)
  • or with anonymous function:

      def news(country) do
        SimpleMemCache.cache(SimpleMemCache, "news_" <> country, 10,
                             fn -> Scraper.scrape_news(country) end)
      end

Note about automatically new value loading:

  • How long does this function take to get the new value, and is this acceptable when the old value is expired? If it takes too long, consider to use an scheduler to regularly recalculate the new value and update the cache with that.

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

  • Example: cache http response of countries rest service for at least 20 minutes

    countries_response = SimpleMemCache.cache(SimpleMemCache,
             "countries_response",
             20,
             true,
             fn -> HTTPoison.get! "http://restcountries.eu/rest/v1/" end)

Keep as long as the ETS table exists

  • Example: Cache products retrieved from csv file. Not a good example, because nowadays files are stored on SSD and there will be no performance gain.

    products = SimpleMemCache.cache(SimpleMemCache, "products", fn -> "products.csv"
                                                                      |> File.stream!
                                                                      |> CSV.parse_stream
                                                                      |> Enum.to_list
                                                                end)
  • updates are still possible:

    SimpleMemCache.put(SimpleMemCache, "products", new_value)

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

Invalidate cached item

  • Example: remove products from cache

    old_value = SimpleMemCache.remove(SimpleMemCache, "products")

Summary

Types

The table id (Tid) or table name

Functions

Cache value returned by the supplied function.

Get status and value of cached item. Status can be :ok, :expired or :not_cached

Get value of cached item. Nil if is not cached or when value is nil.

Returns function that generates Unix/Posix UTC time in seconds.

Create or update an item in cache.

Remove an item from cache. Returns the value of the removed object.

Remove expired entries. This is automatically called once a minute during SimpleMemCache usage.

Delete the ETS table.

Types

@type table() :: atom() | :ets.tid()

The table id (Tid) or table name

Functions

Link to this function

cache(table, key, minutes_valid \\ nil, keep_alive \\ false, f_new_value)

View Source
@spec cache(table(), Map.key(), integer() | nil, boolean() | nil, (-> any())) :: any()

Cache value returned by the supplied function.

  • table - Name of the ETS table.
  • key - Key name
  • minutes_valid - Minutes to keep the item in cache. Default: nil - do not expire.
  • keep_alive - Keep the item in cache if it still accessed. It expires if it is not retrieved in minutes_valid minutes. Default: false
  • f_new_value - function that supplies the value. Enables automatic value loading. When minutes_valid is not nil and keep_alive is false, this function can be launched in a new Erlang process, and it can do this proactively up to 30 seconds before expiration.

Examples

products = SimpleMemCache.cache(SimpleMemCache, "products", 30, true,
   fn() -> File.read!(filename) end
)

news_page = SimpleMemCache.cache(SimpleMemCache, "news", 10, &scrape_news/0)
Link to this function

get(table, key, minutes_keep_alive \\ nil)

View Source
@spec get(table(), Map.key(), integer() | nil) :: {term(), any()}

Get status and value of cached item. Status can be :ok, :expired or :not_cached

The minutes_keep_alive parameter is the number of minutes to keep the item at least in cache. Does not shorten a previously set expiration time (use put for that). However, if there wasn't an expiration time it will take the new value. Default: nil - do not change the expire time.

Example

iex(1)> products = SimpleMemCache.get(SimpleMemCache, "products", 20)
{:expired, "Fret dots"}
Link to this function

get!(table, key, minutes_keep_alive \\ nil)

View Source
@spec get!(table(), Map.key(), integer() | nil) :: any()

Get value of cached item. Nil if is not cached or when value is nil.

Link to this function

get_system_time_function(table)

View Source
@spec get_system_time_function(table()) :: (-> integer())

Returns function that generates Unix/Posix UTC time in seconds.

Link to this function

put(table, key, minutes_valid \\ nil, value)

View Source
@spec put(table(), Map.key(), integer() | nil, Map.value()) :: any()

Create or update an item in cache.

@spec remove(table(), Map.key()) :: any()

Remove an item from cache. Returns the value of the removed object.

Link to this function

remove_expired_entries(table)

View Source
@spec remove_expired_entries(table()) :: :ok

Remove expired entries. This is automatically called once a minute during SimpleMemCache usage.

Link to this function

set_system_time_function(table, f_system_time \\ nil)

View Source
@spec set_system_time_function(table(), (-> integer()) | nil) :: :ok

Time travel for SimpleMemCache.

The f_system_time parameter is meant for time travel support. You can provide a function that returns the Unix/Posix UTC time in seconds. Set nil to restore the normal system time.

@spec stop(table()) :: :ok

Delete the ETS table.