Elixir ETS Patterns
An ETS pattern is a ready-made way of using a table for a common job. This lesson uses two patterns, a read-heavy cache and a counter.
A cache miss becomes a cache hit
Look a value up, find nothing, insert it, and look it up again.
table = :ets.new(:store, [:set, :public])
IO.inspect(:ets.lookup(table, "greeting"))
:ets.insert(table, {"greeting", "hello"})
IO.inspect(:ets.lookup(table, "greeting"))A counter grows in steps
Start a counter at zero, then add 1, 1, and 5 in turn.
table = :ets.new(:store, [:set, :public])
:ets.insert(table, {"hits", 0})
IO.inspect(:ets.update_counter(table, "hits", 1))
IO.inspect(:ets.update_counter(table, "hits", 1))
IO.inspect(:ets.update_counter(table, "hits", 5))Separate counters for separate keys
Keep one counter per page and bump each page a different number of times.
table = :ets.new(:store, [:set, :public])
:ets.insert(table, {"home", 0})
:ets.insert(table, {"about", 0})
:ets.update_counter(table, "home", 1)
:ets.update_counter(table, "home", 1)
:ets.update_counter(table, "about", 1)
IO.inspect(:ets.lookup(table, "home"))
IO.inspect(:ets.lookup(table, "about"))Example
table = :ets.new(:store, [:set, :public])
:ets.insert(table, {"greeting", "hello"})
:ets.insert(table, {"hits", 0})
Enum.each(1..3, fn _ ->
:ets.update_counter(table, "hits", 1)
:ets.lookup(table, "greeting")
end)
IO.inspect(:ets.lookup(table, "greeting"))
IO.inspect(:ets.lookup(table, "hits"))Key points
- Cache: Use a cache table to store a value once and read it many times without computing it again.
- Cache miss: A lookup that returns an empty list means the value is not cached yet, so compute it and insert it.
- Cache hit: A lookup that returns a row means the cached value is ready to use.
- Counter: Use :ets.update_counter to add to a stored number in one step.
- Counter start: A counter row must exist before :ets.update_counter runs, or the call fails.
In this example, a table holds a cached greeting and a hits counter starting at zero. Each of three reads bumps the counter and looks the greeting up. The final lookups show the cached greeting unchanged and the counter at 3.
Note
A counter suits a count that many processes update, because each update happens in one step.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What must exist before :ets.update_counter runs?