ets:select_delete not atomic?

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

ets:select_delete not atomic?

obi458
Hi,

EtsName = ets:new(test,[named_table,ordered_set]),
Res = ets:select_delete(EtsName,[{{Key},[],[true]}]).

Res should be 1 or 0!

But if i do this with a lot of process, at the same time,
it happend that two process get 1!

Start with: ets:insert(EtsName,{Key}).

Process One: ets:select_delete(EtsName,[{{Key},[],[true]}]).
Process Two: ets:select_delete(EtsName,[{{Key},[],[true]}]).

Process One get 1 AND Process Two get 1, with the same key, of course! 


Is this correct?
-- 
Grüße
Oliver Bollmann

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: ets:select_delete not atomic?

Sverker Eriksson-5
On mån, 2019-08-12 at 14:16 +0200, Oliver Bollmann wrote:

> Hi,
>
> EtsName = ets:new(test,[named_table,ordered_set]),
> Res = ets:select_delete(EtsName,[{{Key},[],[true]}]).
>
> Res should be 1 or 0!
>
> But if i do this with a lot of process, at the same time,
> it happend that two process get 1!
>
> Start with: ets:insert(EtsName,{Key}).
>
> Process One: ets:select_delete(EtsName,[{{Key},[],[true]}]).
> Process Two: ets:select_delete(EtsName,[{{Key},[],[true]}]).
>
> Process One get 1 AND Process Two get 1, with the same key, of course! 
>
>
> Is this correct?
>

No, that does not seem right.

The table traversals done by ets:select* and ets:match* functions are not
atomic, but the operation done on each found object should be atomic.

That is, if you do ets:insert(T,{Key}) once and then several
ets:select_delete(T, [{{Key},[],[true]}]) in parallel, only of of them should
find {Key} and delete it.

What OTP version is this?

/Sverker

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: ets:select_delete not atomic?

obi458

Your are right, everything is ok!

A simple example of key pool without gen_servers call, thanks to ets:select_delete!!

-module(key_pool).

%% API
-export([new/1, in/2, in_new/2, out/1, out_compare/1, clear/1]).

-spec(new(atom()) -> {ok,atom() | {already_exists,atom()}}).
new(Pool) when is_atom(Pool) ->
  case ets:info(Pool,name) of
    undefined ->
      {ok,ets:new(Pool,
        [ordered_set,named_table,public,
          {write_concurrency,true},{read_concurrency,true}])};
    Pool -> {already_exists,Pool}
  end.

-spec(in(atom(),{any(),any()}) -> true).
in(Pool,{Key,Val}) ->
  ets:insert(Pool,{Key,Val}).

-spec(in_new(atom(),{any(),any()}) -> boolean()).
in_new(Pool,{Key,Val}) ->
  ets:insert_new(Pool,{Key,Val}).

-spec(out(atom()) -> {ok,{any(),any()} | empty}).
out(Pool) ->
  case ets:select(Pool,[{'_',[],['$_']}],1) of
    {[{Key,_} = Item],_} ->
      case ets:select_delete(Pool,[{{Key,'_'},[],[true]}]) of
        1 ->
          {ok,Item};
        0 ->
          % context switch
          receive
          after 0 -> out(Pool)
          end
      end;
    '$end_of_table' ->
      empty
  end.

-spec(out_compare(atom()) -> {ok,{any(),any()} | empty}).
out_compare(Pool) ->
  case ets:select(Pool,[{'_',[],['$_']}],1) of
    {[{Key,Val} = Item],_} ->
      case ets:select_delete(Pool,[{{Key,Val},[],[true]}]) of
        1 ->
          {ok,Item};
        0 ->
          % context switch
          receive
          after 0 -> out(Pool)
          end
      end;
    '$end_of_table' ->
      empty
  end.

-spec(clear(atom()) -> true).
clear(Pool) -> ets:delete_all_objects(Pool).

Oliver
On 12.08.19 16:33, Sverker Eriksson wrote:
On mån, 2019-08-12 at 14:16 +0200, Oliver Bollmann wrote:
Hi,

EtsName = ets:new(test,[named_table,ordered_set]),
Res = ets:select_delete(EtsName,[{{Key},[],[true]}]).

Res should be 1 or 0!

But if i do this with a lot of process, at the same time,
it happend that two process get 1!

Start with: ets:insert(EtsName,{Key}).

Process One: ets:select_delete(EtsName,[{{Key},[],[true]}]).
Process Two: ets:select_delete(EtsName,[{{Key},[],[true]}]).

Process One get 1 AND Process Two get 1, with the same key, of course! 


Is this correct?

No, that does not seem right.

The table traversals done by ets:select* and ets:match* functions are not
atomic, but the operation done on each found object should be atomic.

That is, if you do ets:insert(T,{Key}) once and then several
ets:select_delete(T, [{{Key},[],[true]}]) in parallel, only of of them should
find {Key} and delete it.

What OTP version is this?

/Sverker

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
-- 
Grüße
Oliver Bollmann

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions