Search code examples
erlangets

ets:foldl vs deleted elements


The documentation for ets:foldl/3 says:

If Function inserts objects into the table, or another process inserts objects into the table, those objects may (depending on key ordering) be included in the traversal.

But what happens if Function deletes objects from the table? Is there any guarantee that all remaining objects will be included in the traversal in that case?


Solution

  • According to the source of ets.erl if one process is iterating the table and during that it deletes records those records won't be processed if they haven't processed so far.

    foldl(F, Accu, T) ->
      ets:safe_fixtable(T, true),
      First = ets:first(T),
      try
        do_foldl(F, Accu, First, T)
      after
        ets:safe_fixtable(T, false)
      end.
    

    and the helper function is

    do_foldl(F, Accu0, Key, T) ->
      case Key of
        '$end_of_table' ->
          Accu0;
        _ ->
          do_foldl(F,
                   lists:foldl(F, Accu0, ets:lookup(T, Key)),
                   ets:next(T, Key), T)
      end.
    

    At first foldl fixes the table. When a process fixes a table it will be recorded into a {Time, Pid} list. In a fixed table ets:first and ets:next are guaranteed to succeed and each object will be only returned once. In case of ordered tables ets:next can give back a key whose object no longer exists. But it is not a problem since ets:lookup give back an empty list in case the record is not in the table. lists:foldl won't fail in that case.

    So the answer is yes, the other records will be processed by ets:foldl.

    If you have multiple processes manipulating the tables concurrently, the safe_fixtable will protect the table from the concurrent manipulations. Docs of safe_fixtable/2 says:

    A process fixes a table by calling safe_fixtable(Tab, true). The table remains fixed until the process releases it by calling safe_fixtable(Tab, false), or until the process terminates.

    Take care what the documentation say here:

    Note that no deleted objects are actually removed from a fixed table until it has been released. If a process fixes a table but never releases it, the memory used by the deleted objects will never be freed. The performance of operations on the table will also degrade significantly.

    So fixing the table for traversal has a price. Don't do too much manipulations in the foldl function, and it shouldn't take too long either.