简体   繁体   中英

What is the best way, to traverse and update all elements in an Erlang ETS table?

Could you help me out with a "best practice" approach, to iterate over all the elements in an ETS table only once, while updating each element? My table is a private set, and I was about to traverse through it with ets:foldl , using ets:update_element in my input function, but I am not sure, if this is a safe approach, as updating elements destructively may give me the same element one other time - according to the documentation. I am not about to insert new keys, only update values, please, tell me, if this approach is safe, or show me an alternative way to achieve the updates efficiently!

Thank you!

You can use first/1 and next/2 . See next/2 doco here: http://www.erlang.org/doc/man/ets.html#next-2

I think the ets documentation already answered your concern:

No other support is available within ETS that would guarantee consistency between objects. However, the safe_fixtable/2 function can be used to guarantee that a sequence of first/1 and next/2 calls will traverse the table without errors and that each existing object in the table is visited exactly once, even if another process (or the same process) simultaneously deletes or inserts objects into the table. Nothing more is guaranteed; in particular objects that are inserted or deleted during such a traversal may be visited once or not at all. Functions that internally traverse over a table, like select and match, will give the same guarantee as safe_fixtable.

Here is, what I ended up with, maybe someone will find it useful:

%% @doc
%% Traverses each element in an ETS table, and calls Fun on them.
%% Use with caution, when inserting or deleting elements, see the
%% ETS documentation for details!
-spec ets_each(
    TableRef :: ets:tid( ),
    Fun      :: fun( ( Key :: term( ), [ Element :: term( ) ], Extra :: term( ) ) -> ok ),
    Extra    :: term( )
) ->
    ok.
ets_each( TableRef, Fun, Extra ) ->
    ets:safe_fixtable( TableRef, true ),
    First = ets:first( TableRef ),
    try
        do_ets_each( TableRef, Fun, Extra, First )
    after
        ets:safe_fixtable( TableRef, false )
    end.

%% @doc
%% Recursive helper function for ets_each.
-spec do_ets_each(
    TableRef :: ets:tid( ),
    Fun      :: fun( ( Key :: term( ), [ Element :: term( ) ], Extra :: term( ) ) -> ok ),
    Extra    :: term( ),
    Key      :: term( )
) ->
    ok.
do_ets_each( _TableRef, _Fun, _Extra, '$end_of_table' ) ->
    ok;    
do_ets_each( TableRef, Fun, Extra, Key ) ->
    Fun( Key, ets:lookup( TableRef, Key ), Extra ),
    do_ets_each( TableRef, Fun, Extra, ets:next( TableRef, Key ) ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM