nebulex v1.0.0-rc.2 Nebulex.Cache behaviour View Source

Cache Main Interface.

A Cache maps to an underlying implementation, controlled by the adapter. For example, Nebulex ships with a default adapter that implements a local generational cache.

When used, the Cache expects the :otp_app as option. The :otp_app should point to an OTP application that has the Cache configuration. For example, the Cache:

defmodule MyCache do
  use Nebulex.Cache, otp_app: :my_app
end

Could be configured with:

config :my_app, MyCache,
  adapter: Nebulex.Adapters.Local,
  n_shards: 2

Most of the configuration that goes into the config is specific to the adapter, so check Nebulex.Adapters.Local documentation for more information. However, some configuration is shared across all adapters, they are:

  • :adapter - a compile-time option that specifies the adapter itself. As a compile-time option, it may also be given as an option to use Nebulex.Cache.

  • :stats - a compile-time option that specifies if cache statistics is enabled or not (defaults to false).

  • :pre_hooks_strategy - a compile-time option that determinates the strategy how pre-hooks will be executed – see pre/post hooks below.

  • :post_hooks_strategy - a compile-time option that determinates the strategy how post-hooks will be executed – see pre/post hooks below.

  • :version_generator - this option specifies the module that implements the Nebulex.Version interface. This interface defines only one callback generate/1 that is invoked by the adapters to generate new object versions. If this option is not set, then the version is set to nil by default.

Pre/Post hooks

The cache can also provide its own pre/post hooks implementation; see Nebulex.Cache.Hook behaviour. By default, pre/post hooks are empty lists, but again, you can override the functions of Nebulex.Cache.Hook behaviour.

Besides, it is possible to configure the strategy how the hooks are evaluated, the available strategies are:

  • :async - (the default) all hooks are evaluated asynchronously (in parallel) and their results are ignored.

  • :sync - hooks are evaluated synchronously (sequentially) and their results are ignored.

  • :pipe - similar to :sync but each hook result is passed to the next one and so on, until the last hook evaluation is returned.

These strategy values applies to the compile-time options :pre_hooks_strategy and :post_hooks_strategy.

Shared options

Almost all of the Cache operations below accept the following options:

  • :return - selects return type. When :value (the default), returns the object value. When :object, returns the Nebulex.Object.t.

  • :version - The version of the object on which the operation will take place. The version can be any term (default: nil).

  • :ttl - Time To Live (TTL) or expiration time in milliseconds for a key (default: :infinity) – applies only to set/3.

Such cases will be explicitly documented as well as any extra option.

Extended API

Some adapters might extend the API with additional functions, therefore, it is important to review the adapters documentation.

Link to this section Summary

Callbacks

Returns the adapter tied to the cache

Returns the adapter configuration stored in the :otp_app environment

Deletes the cached entry in for a specific key

Flushes the cache

Fetches a value or object from Cache where the key matches the given key

Similar to get/2 but raises KeyError if no value associated with the given key was found

Gets the value from key and updates it, all in one pass

Returns whether the given key exists in Cache

Returns true if the current process is inside a transaction

A callback executed when the cache starts or when configuration is read

Returns all cached keys

Returns and removes the value/object associated with key in Cache

Invokes reducer for each entry in the cache, passing the key, the return and the accumulator acc as arguments. reducer’s return value is stored in acc

Sets the given value under key in the Cache

Returns the cache size (total number of cached entries)

Starts a supervision and return {:ok, pid} or just :ok if nothing needs to be done

Shuts down the cache represented by the given pid

Returns a map with all cache entries (key/value). If you want the map values be the cache object, pass the option :return set to :object

Runs the given function inside a transaction

Updates the cached key with the given function

Updates (increment or decrement) the counter mapped to the given key

Link to this section Types

Link to this type reducer() View Source
reducer() :: ({key(), return()}, acc_in :: any() -> acc_out :: any())
Link to this type return() View Source
return() :: key() | value() | object()
Link to this type value() View Source
value() :: any()

Link to this section Callbacks

Returns the adapter tied to the cache.

Returns the adapter configuration stored in the :otp_app environment.

If the c:init/2 callback is implemented in the cache, it will be invoked.

Link to this callback delete(key, opts) View Source
delete(key(), opts()) :: key() | no_return()

Deletes the cached entry in for a specific key.

It always returns the key, either it exists or not. It the key exists, it’s removed from cache, otherwise nothing happens.

Options

  • :on_conflict - It may be one of :raise (the default), :nothing, :delete. See the “OnConflict” section for more information.

Note that for this function :return option hasn’t any effect since it always returns the key either success or not.

See the “Shared options” section at the module documentation.

Example

nil =
  :a
  |> MyCache.set(1, return: :key)
  |> MyCache.delete()
  |> MyCache.get()

:non_existent_key = MyCache.delete :non_existent_key

OnConflict

The :on_conflict option supports the following values:

  • :raise - raises if there is a conflicting key
  • :nothing - ignores the error in case of conflicts
  • :delete - deletes the value on the existing key

Examples

# Set a value
1 = MyCache.set :a, 1

# Delete with an invalid version but do nothing on conflicts.
# Keep in mind that, although this returns successfully, the returned
# `kwy` does not reflect the data in the Cache. For instance, in case
# of "on_conflict: :nothing", the returned `key` isn't deleted.
:a = MyCache.delete :a, version: :invalid, on_conflict: :nothing
1 = MyCache.get :a

# Delete with the same invalid version but force to delete the current
# value on conflicts (if it exist).
:a = MyCache.delete :a, version: :invalid, on_conflict: :delete
nil = MyCache.get :a
Link to this callback flush() View Source
flush() :: :ok | no_return()

Flushes the cache.

Examples

for x <- 1..5, do: MyCache.set(x, x)

:ok = MyCache.flush

for x <- 1..5, do: nil = MyCache.get(x)
Link to this callback get(key, opts) View Source
get(key(), opts()) :: nil | return() | no_return()

Fetches a value or object from Cache where the key matches the given key.

Returns nil if no result was found.

Options

  • :on_conflict - It may be one of :raise (the default), :nothing, nil. See the “OnConflict” section for more information.

See the “Shared options” section at the module documentation.

Example

"some value" =
  :a
  |> MyCache.set("some value", return: :key)
  |> MyCache.get

nil = MyCache.get :non_existent_key

OnConflict

The :on_conflict option supports the following values:

  • :raise - raises if there is a conflicting key
  • :nothing - ignores the error in case of conflicts
  • nil - forces to return nil

Examples

# Set a value
1 = MyCache.set :a, 1

# Gets with an invalid version but do nothing on conflicts.
# Keep in mind that, although this returns successfully, the returned
# struct does not reflect the data in the Cache. For instance, in case
# of "on_conflict: :nothing", it returns the latest version of the
# cached object.
%Nebulex.Object{key: :a, value: 1} =
  MyCache.get :a, return: :object, version: :invalid, on_conflict: :nothing
1 = MyCache.get :a

# Gets with the same invalid version but force to return `nil`
nil = MyCache.get :a, version: :invalid, on_conflict: nil
1 = MyCache.get :a
Link to this callback get!(key, opts) View Source
get!(key(), opts()) :: return() | no_return()

Similar to get/2 but raises KeyError if no value associated with the given key was found.

Options

See the “Shared options” section at the module documentation.

Example

MyCache.get!(:a)
Link to this callback get_and_update(key, function, opts) View Source
get_and_update(key(), (value() -> {get, update} | :pop), opts()) ::
  no_return() |
  {get, update} when get: value(), update: value()

Gets the value from key and updates it, all in one pass.

fun is called with the current cached value under key (or nil if key hasn’t been cached) and must return a two-element tuple: the “get” value (the retrieved value, which can be operated on before being returned) and the new value to be stored under key. fun may also return :pop, which means the current value shall be removed from Cache and returned.

The returned value is a tuple with the “get” value returned by fun and the new updated value under key.

Options

  • :on_conflict - same as callback get/2.

Note that for this function :return option hasn’t any effect, since it always returns a tuple {get :: value, update :: value} in case of success.

See the “Shared options” section at the module documentation.

Examples

# update a nonexistent key
{nil, "value!"} = MyCache.get_and_update(:a, fn current_value ->
  {current_value, "value!"}
end)

# update a existent key
{"value!", "new value!"} = MyCache.get_and_update(:a, fn current_value ->
  {current_value, "new value!"}
end)

# pop/remove value if it exists
{"new value!", nil} = MyCache.get_and_update(:a, fn _ -> :pop end)

# pop/remove a nonexistent key
{nil, nil} = MyCache.get_and_update(:b, fn _ -> :pop end)
Link to this callback has_key?(key) View Source
has_key?(key()) :: boolean()

Returns whether the given key exists in Cache.

Examples

1 = MyCache.set(:a, 1)

true = MyCache.has_key?(:a)

false = MyCache.has_key?(:b)
Link to this callback in_transaction?() View Source (optional)
in_transaction?() :: boolean()

Returns true if the current process is inside a transaction.

Examples

MyCache.in_transaction?
#=> false

MyCache.transaction(fn ->
  MyCache.in_transaction? #=> true
end)
Link to this callback init(config) View Source (optional)
init(config :: Keyword.t()) :: {:ok, Keyword.t()} | :ignore

A callback executed when the cache starts or when configuration is read.

Returns all cached keys.

Examples

for x <- 1..3, do: MyCache.set(x, x*2, return: :key)

[1, 2, 3] = MyCache.keys

WARNING: This is an expensive operation, beware of using it in prod.

Link to this callback pop(key, opts) View Source
pop(key(), opts()) :: return() | no_return()

Returns and removes the value/object associated with key in Cache.

Returns nil if no result was found.

Options

  • :on_conflict - same as callback get/2.

See the “Shared options” section at the module documentation.

Examples

1 = MyCache.set(:a, 1)

1 = MyCache.pop(:a)
nil = MyCache.pop(:b)

%Nebulex.Object{key: :a, value: 1} =
  :a |> MyCache.set(1, return: :key) |> MyCache.pop(return: :object)
Link to this callback reduce(acc, reducer, opts) View Source
reduce(acc :: any(), reducer(), opts()) :: any()

Invokes reducer for each entry in the cache, passing the key, the return and the accumulator acc as arguments. reducer’s return value is stored in acc.

Returns the accumulator.

Options

See the “Shared options” section at the module documentation.

Examples

for x <- 1..5, do: MyCache.set(x, x)

15 = MyCache.reduce(0, fn({_key, value}, acc) ->
  acc + value
end)

MyCache.reduce({%{}, 0}, fn({key, value}, {acc1, acc2}) ->
  if Map.has_key?(acc1, key),
    do: {acc1, acc2},
    else: {Map.put(acc1, key, value), value + acc2}
end)

WARNING: This is an expensive operation, beware of using it in prod.

Link to this callback set(key, value, opts) View Source
set(key(), value(), opts()) :: return() | no_return()

Sets the given value under key in the Cache.

It returns value or Nebulex.Object.t (depends on :return option) if the value has been successfully inserted.

Options

  • :on_conflict - It may be one of :raise (the default), :nothing, :replace. See the “OnConflict” section for more information.

See the “Shared options” section at the module documentation.

Example

%Nebulex.Object{key: :a} =
  MyCache.set :a, "anything", ttl: 100000, return: :object

OnConflict

The :on_conflict option supports the following values:

  • :raise - raises if there is a conflicting key
  • :nothing - ignores the error in case of conflicts
  • :replace - replace the value on the existing key with the given value

Examples

# Set twice
%Nebulex.Object{key: :a, version: v1} = MyCache.set :a, 1, return: :object
%Nebulex.Object{key: :a, version: v2}
  MyCache.set :a, 2, return: :object, version: v1

# Set with the same key and wrong version but do nothing on conflicts.
# Keep in mind that, although this returns successfully, the returned
# struct does not reflect the data in the Cache. For instance, in case
# of "on_conflict: :nothing", the returned object isn't set.
%Nebulex.Object{key: :a, value: 2} =
  MyCache.set :a, 3, return: :object, version: v1, on_conflict: :nothing
2 = MyCache.get :a

# Set with the same key and wrong version but replace the current
# value on conflicts.
3 = MyCache.set :a, 3, version: v1, on_conflict: :replace
3 = MyCache.get :a
Link to this callback size() View Source
size() :: integer()

Returns the cache size (total number of cached entries).

Examples

for x <- 1..10, do: MyCache.set(x, x)

10 = MyCache.size

for x <- 1..5, do: MyCache.delete(x)

5 = MyCache.size
Link to this callback start_link(opts) View Source
start_link(opts()) ::
  {:ok, pid()} |
  {:error, {:already_started, pid()}} |
  {:error, term()}

Starts a supervision and return {:ok, pid} or just :ok if nothing needs to be done.

Returns {:error, {:already_started, pid}} if the cache is already started or {:error, term} in case anything else goes wrong.

Options

See the configuration in the moduledoc for options shared between adapters, for adapter-specific configuration see the adapter’s documentation.

Link to this callback stop(pid, timeout) View Source
stop(pid(), timeout()) :: :ok

Shuts down the cache represented by the given pid.

Link to this callback to_map(opts) View Source
to_map(opts()) :: map()

Returns a map with all cache entries (key/value). If you want the map values be the cache object, pass the option :return set to :object.

Options

See the “Shared options” section at the module documentation.

Examples

for x <- 1..3, do: MyCache.set(x, x*2)

%{1 => 2, 2 => 4, 3 => 6} = MyCache.to_map

%Nebulex.Object{key: 1} = Map.get(MyCache.to_map(return: :object), 1)

WARNING: This is an expensive operation, beware of using it in prod.

Link to this callback transaction(function, opts) View Source (optional)
transaction(function :: (... -> any()), opts()) :: any()

Runs the given function inside a transaction.

A successful transaction returns the value returned by the function.

Options

See the “Shared options” section at the module documentation.

Examples

MyCache.transaction fn ->
  1 = MyCache.set(:a, 1)
  true = MyCache.has_key?(:a)
  MyCache.get(:a)
end
Link to this callback update(key, initial, function, opts) View Source
update(key(), initial :: value(), (value() -> value()), opts()) ::
  value() |
  no_return()

Updates the cached key with the given function.

If key is present in Cache with value value, fun is invoked with argument value and its result is used as the new value of key.

If key is not present in Cache, initial is inserted as the value of key.

Options

  • :on_conflict - same as callback get/2.

Note that for this function :return option hasn’t any effect, since it always returns the object value.

See the “Shared options” section at the module documentation.

Examples

1 = MyCache.update(:a, 1, &(&1 * 2))

2 = MyCache.update(:a, 1, &(&1 * 2))
Link to this callback update_counter(key, incr, opts) View Source
update_counter(key(), incr :: integer(), opts()) ::
  integer() |
  no_return()

Updates (increment or decrement) the counter mapped to the given key.

If incr >= 0 then the current value is incremented by that amount, otherwise the current value is decremented.

If incr is not a valid integer, then an ArgumentError exception is raised.

Options

See the “Shared options” section at the module documentation.

Examples

1 = MyCache.update_counter(:a)

3 = MyCache.update_counter(:a, 2)

2 = MyCache.update_counter(:a, -1)

%Nebulex.Object{key: :a, value: 2} = MyCache.update_counter(:a, 0, return: :object)