1
votes

I would like to apply a function to all the tuples in an ETS table :

The table is a set, each key appears only once.

My table contains only tuples of the same type:

{Key, X, Y, VX, VY}

All values are ::integer()

What i want to do is have a certain value Elapsed and update all my tuples with a function apply_vector/2

apply_vector({K, X, Y, 0, 0}, _Elapsed) ->
    {K, X, Y, 0, 0};

apply_vector({K, X, Y, VX, VY}, Elapsed) ->
    NewX = X + (VX * Elapsed),
    NewY = Y + (VY * Elapsed),
    {K, NewX, NewY, VX, VY}.

Possible solutions

  • If i use ets:foldl, my inserts could be traversed during the fold, and result in an infinite (very long) loop.

  • I could prepare the new tuples with a ets:foldl, and then insert the whole list.

  • I could insert to a new table, then replace the old table by the new, but i don't want to limit access to the table with calls to a gen_server, the table must be accessible at any time.

  • I can not use ets:update_element because I need to read VX and VY values to update X and Y.

  • I know there are some iterators utilities but no one seems to allow to pass a fun.

I need to make this update every 1 - 5 seconds. So, wich solution is the most efficient with 10 tuples ? With 100 tuples ? With more ?

Thank You !

I Keep a list of boats, the Key is the Boat ID, X and Y are geographic coordinates, VX and VY represents a vector of movement: a deplacement for one second. Elapsed is a ratio, a number of seconds since the last update. The table helps to know at any time the position of each boat.

2
With 100 tuples you won't have any performance issue at all.yilmazhuseyin
Yes my question is badly asked, say 10 000 or 100 000lud

2 Answers

1
votes

I probably use ets:foldl for this.

Seems to me like you only need iterative access on this data. So you could just use list of records here.

Another approach (which I would go for) is to put a boat supervisor and create a gen_server for every boat. That way every boat will have its own state and you won't actually need to traverse any list.

Also checkout qlc http://www.erlang.org/doc/man/qlc.html qlc let's you use list comrehensions on ets or mnesia tables. It will probably have the same performance as foldl though.

1
votes

There's no great way to do what you are doing.

Recently, I ran in to a similar issue (Updating ~5000 rows, once a second)

Which led me to just take a totally different approach.
So, do you NEED to store the interpreted value? Or can you compute the value upon lookup?

How about storing: {K,X,Y,VX,VY,LastUpdateTime}

And then doing something like (uncompilable example):

boats:get_all() -> % Record syntax would be smarter here, but it's an example...
  ets:foldl(?TABLE,[],fun(Row={Id,_,_,_,_,_},Acc) -> [{Id,calc(Row)}|Acc] end).

boats:get(Id) ->
  [Row] = ets:lookup(?TABLE,Id),
  calc(Row).

calc({_K,X,Y,VX,VY,LastUpdate}) ->
  {X + (VX * (now() - LastUpdate)), Y + (VY * (now() - LastUpdate)}

This allows you not to block on a genserver, but also not to have to update the table every 5 seconds. You'd basically only update the table every time a boat reports in.