Nebulex v2.0.0-rc.0 Nebulex.Adapters.Local View Source

Adapter module for Local Generational Cache; inspired by epocxy.

Generational caching using an ets table (or multiple ones when used with :shards) for each generation of cached data. Accesses hit the newer generation first, and migrate from the older generation to the newer generation when retrieved from the stale table. When a new generation is started, the oldest one is deleted. This is a form of mass garbage collection which avoids using timers and expiration of individual cached elements.

This implementation of generation cache uses only two generations (which is more than enough) also referred like the newer and the older.

Features

  • Configurable backend (ets or :shards).
  • Expiration – A status based on TTL (Time To Live) option. To maintain cache performance, expired entries may not be immediately flushed or evicted, they are expired or evicted on-demand, when the key is read.
  • Eviction – Generational Garbage Collection.
  • Sharding – For intensive workloads, the Cache may also be partitioned (by using :shards backend and specifying the :partitions option).
  • Support for transactions via Erlang global name registration facility.

Options

This adapter supports the following options and all of them can be given via the cache configuration:

  • :backend - Defines the backend or storage to be used for the adapter. Supported backends are: :ets and :shards. Defaults to :ets.

  • :read_concurrency - Since this adapter uses ETS tables internally, this option is used when a new table is created. See :ets.new/2. Defaults to true.

  • :write_concurrency - Since this adapter uses ETS tables internally, this option is used when a new table is created. See :ets.new/2. Defaults to true.

  • :compressed - This option is used when a new ETS table is created and it defines whether or not it includes X as an option. See :ets.new/2. Defaults to false.

  • :backend_type - This option defines the type of ETS to be used (Defaults to :set). However, it is highly recommended to keep the default value, since there are commands not supported (unexpected exception may be raised) for types like :bag or : duplicate_bag. Please see the ETS docs for more information.

  • :partitions - The number of partitions in the Cache. This option is only available for :shards backend. Defaults to System.schedulers_online().

  • :gc_interval - Interval time in milliseconds to garbage collection to run, delete the oldest generation and create a new one. If this option is not set, garbage collection is never executed, so new generations must be created explicitly, e.g.: Generation.new_generation(cache_name, []).

  • :max_size - Max number of cached entries (cache limit). If it is not set (nil), the check to release memory is not performed (the default).

  • :allocated_memory - Max size in bytes allocated for a cache generation. If this option is set and the configured value is reached, a new cache generation is created so the oldest is deleted and force releasing memory space. If it is not set (nil), the cleanup check to release memory is not performed (the default).

  • :gc_cleanup_min_timeout - The min timeout in milliseconds for triggering the next cleanup and memory check. This will be the timeout to use when the max allocated memory is reached. Defaults to 30_000.

  • :gc_cleanup_max_timeout - The max timeout in milliseconds for triggering the next cleanup and memory check. This is the timeout used when the cache starts or the consumed memory is 0. Defaults to 300_000.

Example

Nebulex.Cache is the wrapper around the cache. We can define a local cache as follows:

defmodule MyApp.LocalCache do
  use Nebulex.Cache,
    otp_app: :my_app,
    adapter: Nebulex.Adapters.Local
end

Where the configuration for the cache must be in your application environment, usually defined in your config/config.exs:

config :my_app, MyApp.LocalCache,
  backend: :shards,
  gc_interval: 86_400_000,
  max_size: 200_000,
  allocated_memory: 2_000_000_000,
  gc_cleanup_min_timeout: 10_000,
  gc_cleanup_max_timeout: 600_000

For intensive workloads, the Cache may also be partitioned (by using :shards backend and specifying the :partitions option). If partitioning is required then a good default is to set the number of partitions to the number of schedulers available (the default):

config :my_app, MyApp.LocalCache,
  backend: :shards,
  gc_interval: 86_400_000,
  max_size: 200_000,
  allocated_memory: 2_000_000_000,
  gc_cleanup_min_timeout: 10_000,
  gc_cleanup_max_timeout: 600_000,
  partitions: System.schedulers_online()

For more information about the usage, check out Nebulex.Cache.

Queryable API

The adapter supports as query parameter the following values:

  • query - nil | :unexpired | :expired | :ets.match_spec()

Internally, an entry is represented by the tuple {key, val, vsn, exp}, which means the match pattern within the :ets.match_spec() must be something like {:"$1", :"$2", :"$3", :"$4"}. In order to make query building easier, you can use Ex2ms library.

Examples

# built-in queries
MyCache.all()
MyCache.all(:unexpired)
MyCache.all(:expired)

# using a custom match spec (all values > 10)
spec = [{{:"$1", :"$2", :_, :_}, [{:>, :"$2", 10}], [{{:"$1", :"$2"}}]}]
MyCache.all(spec)

# using Ex2ms
import Ex2ms

spec =
  fun do
    {key, value, _version, _expire_at} when value > 10 -> {key, value}
  end

MyCache.all(spec)

The :return option applies only for built-in queries, such as: nil | :unexpired | :expired, if you are using a custom :ets.match_spec(), the return value depends on it.

The same applies to the stream function.

Link to this section Summary

Link to this section Functions

Link to this macro

entry(args \\ [])

View Source (macro)
Link to this macro

entry(record, args)

View Source (macro)