🎓 A1Learner
🔍
0 of 46 lessons completed

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?