Why not ets Why not support update_with_fun

In ets, concurrently write a key whose value is a list or map. In order to ensure data consistency, the current scheme is to cast/call the write operation request to the special write process for processing. In most cases, the code is not natural to write in this way, and the write process may have performance bottlenecks.

I would like to ask why ets:update_with_fun(Table, Key, Fun) doesn’t exist in ets api. It seems that implementing such a function is not easy.

Then I saw that there was now a function that did just that :ets:select_replace(Table, MatchSpec), But MatchSpec does not support lists:delete() maps:remove() setelement() calls.

Or is there a better way to do it in erlang scenarios?

1 Like

I guess the main reason is that ets is implemented as a NIF/BIF (native C functions). And currently BEAM does not allow to execute erlang code (call erlang functions, execute funs) from BIF/NIF.

I think the only way currently is, as you said, to use a separate writer process. I think Mnesia does exactly this to implement transactions on top of ETS/DETS (this process is called mnesia_locker if I remember correctly)

3 Likes

You can implement update_with_fun(Table, Key, Fun) with ets:select_replace like this:

update_with_fun(Table, Key, Fun) ->
  [Old] = ets:lookup(Table, Key),
  New = Fun(Old),
  Success = (1 =:= ets:select_replace(Table, [{Old, [], [{const, New}]}])),
  case Success of
    true -> New;
    false -> update_with_fun(Table, Key, Fun)
  end.

It can work ok as long as you don’t have too much concurrent writes toward the same keys.

7 Likes

I guess so, but ets:select_replace supports a few functions, so it should be OK to add select_replace as written

1 Like

oh, I learned, It seems like a wonderful way

1 Like