Search code examples
erlangincrementets

Does ets provide a means to do an Update & Read in one go - like an Increment Operation?


I initialize a named ets table in my start(_StartType, _StartArgs) -> function, before setting up my standard Cowboy web handling routines.

ets:new(req_stats,[named_table,public]),ets:insert(req_stats,{req_count,0})

I have this function:

 count_req()->
    [{_,Cnt}]=ets:lookup(req_stats,req_count),
    ets:insert(req_stats,Cnt+1),
    Cnt+1.

My concern is this;

If i call count_req() for each web request under high load, i WILL most likely end up with an inaccurate count, because [{_,Cnt}]=ets:lookup(req_stats,req_count) could be updated several times before I return Cnt+1

Does ets provide a means to do an update & read in one go - like an increment operation?

Thanks.


Solution

  • You can use ets:update_counter/3:

    ets:update_counter(req_stats, req_count, {2, 1})
    

    That is, increment the 2nd element of the tuple by 1, and return the new value.


    In Erlang/OTP 18.0 (released on 2015-06-24), ets:update_counter/4 was introduced. It lets you provide a default value, to be used if the key is not yet present in the table. So if you want the counter to become 1 after the first time you increment it, give 0 as the default value:

    1> ets:new(req_stats, [named_table]).
    req_stats
    2> ets:tab2list(req_stats).
    []
    3> ets:update_counter(req_stats, req_count, {2, 1}, {req_count, 0}).
    1
    4> ets:tab2list(req_stats).
    [{req_count,1}]