Unexpected ETS behavior - when I delete the first record, the whole table seems to get wiped

Hi folks,

I am developing some fun project where I allow a multitude of Edge agents to connect to a Phoenix backend. I plan to store “edge info” in some ETS table, but the strange thing is that when I delete the first record, the whole table seems to get wiped.
Here is the code for the cache.
Any help much appreciated (especially at the “delete” part

1 Like

Is there a process that owns the ETS table?


+1 to @cmo’s question about ownership - some of the places that could ultimately end up calling :ets.new are Cowboy workers and Liveviews, which will lead to the table disappearing before you want it to.

Giving the table a more-reliable parent can also reduce the need for all the “does the table exist” guards, since the table should be created during system boot.

Some other thoughts:

  • :ets.info/2 will return :undefined if the table doesn’t exist yet. Clearer + faster than searching the output of :ets.all

  • this call to :ets.lookup will not succeed… ever, because the second argument to lookup should be the key (edge_init.id) and not the whole tuple.

    edge_kv = {edge_init.id, edge_init}
    case :ets.lookup(:edges, edge_kv) do
      [] ->
        :ets.insert_new(:edges, edge_kv)
      _ ->
        :ets.insert(:edges, edge_kv)
  • also in that code chunk: the case between insert and insert_new is odd. The only difference between the two functions is their behavior if there’s an existing element with the same key, and the lookup prevents that from being relevant. What’s the intent of this structure?

  • get_raw_by_id is inefficient; look into :ets.select to avoid copying the entire table into your process. Alternatively, if lookups by edge_id are very frequent, you could maintain a separate bag table of {edge_id, edge} pairs.

  • delete_raw_by_id tries to pass a list of tuples to :ets.delete - like lookup, that function expects a single key.


Big thanks to @cmo and @al2o3cr for your input. It seems, I’ll be better off transforming this Cache into a GenServer,…Also, apologies for so much messy code, but one starts to experiment… In any case, I’ll follow your hints and report on the results

Thanks for the help @al2o3cr and @cmo. I refactored the Cache to a GenServer and now everything is much cleaner and working as expected! Lessons learned :slight_smile: :pray:

Why not use Cachex? It’s battle tested, works flawlessly, and has a ton of features.


Thank you for the input @dimitarvp, I am still very new to the whole BEAM ecosystem, so I will have a look at this package for certain!