At the end of last week’s Erlang Thursday, I said we would continue looking at the behavior of the `select`

functions in the `ets`

module.

So before we do any experimentation, we setup our test ETS tables, and this time we will also create a table of type `ordered_set`

.

Fun = fun() -> receive after infinity -> ok end end. % #Fun<erl_eval.20.54118792> SomeProcess = spawn(Fun). % <0.52.0> TestOrderedSetTable = ets:new(ordered_set_table, [public, ordered_set]). % 16402 TestTable = ets:new(ets_table, [public]). % 20499 ets:give_away(TestTable, SomeProcess, []). % true ets:give_away(TestOrderedSetTable, SomeProcess, []). % true

Next we will load our test ETS table with some dummy data, leaving some gaps in the sequence, allowing us to fill those gaps in later.

[[ets:insert(TestTable, {X, X}) || X <- lists:seq(1, 30, 2)]]. % [[true,true,true,true,true,true,true,true,true,true,true, % true,true,true,true]] [[ets:insert(TestOrderedSetTable, {X, X}) || X <- lists:seq(1, 30, 2)]]. % [[true,true,true,true,true,true,true,true,true,true,true, % true,true,true,true]]

We then do a select to get all of the records from the table so we can see how the results are ordered for the different table types.

ets:select(TestTable, [{{'$1', '$2'}, [], [{{'$1', '$2'}}]}]). % [{15,15}, % {25,25}, % {13,13}, % {21,21}, % {11,11}, % {1,1}, % {23,23}, % {7,7}, % {3,3}, % {9,9}, % {19,19}, % {29,29}, % {27,27}, % {17,17}, % {5,5}] ets:select(TestOrderedSetTable, [{{'$1', '$2'}, [], [{{'$1', '$2'}}]}]). % [{1,1}, % {3,3}, % {5,5}, % {7,7}, % {9,9}, % {11,11}, % {13,13}, % {15,15}, % {17,17}, % {19,19}, % {21,21}, % {23,23}, % {25,25}, % {27,27}, % {29,29}]

The `ets`

module also has a function ets:select_reverse, so let’s take a quick stop and see what that does for our ETS tables.

ets:select_reverse(TestTable, [{{'$1', '$2'}, [], [{{'$1', '$2'}}]}]). % [{15,15}, % {25,25}, % {13,13}, % {21,21}, % {11,11}, % {1,1}, % {23,23}, % {7,7}, % {3,3}, % {9,9}, % {19,19}, % {29,29}, % {27,27}, % {17,17}, % {5,5}] ets:select_reverse(TestOrderedSetTable, [{{'$1', '$2'}, [], [{{'$1', '$2'}}]}]). % [{29,29}, % {27,27}, % {25,25}, % {23,23}, % {21,21}, % {19,19}, % {17,17}, % {15,15}, % {13,13}, % {11,11}, % {9,9}, % {7,7}, % {5,5}, % {3,3}, % {1,1}]

If we look at the results of `ets:select/2`

and `ets:select_reverse/2`

, we see that for `TestTable`

we get the same result, and for `TestOrderedSetTable`

we get the results in a reverse order, which is what the documentation for `ets:select_reverse/2`

states. Which makes sense if you think about it,

With that brief diversion out of the way, lets run our same `match_spec()`

s from above, but limit the results to `5`

records so we get a continuation back.

{Result, Continuation} = ets:select(TestTable, [{{'$1', '$2'}, [], [{{'$1', '$2'}}]}], 5). % {[{19,19},{29,29},{27,27},{17,17},{5,5}], % {20499,214,5,<<>>,[],0}} {OrdSetResult, OrdSetContinuation} = ets:select(TestOrderedSetTable, [{{'$1', '$2'}, [], [{{'$1', '$2'}}]}], 5). % {[{1,1},{3,3},{5,5},{7,7},{9,9}],{16402,9,[],5,<<>>,[],0,0}}

And with those continuations, we will see what the next results we would fetch would be.

ets:select(Continuation). % {[{1,1},{23,23},{7,7},{3,3},{9,9}],{20499,111,5,<<>>,[],0}} ets:select(OrdSetContinuation). % {[{11,11},{13,13},{15,15},{17,17},{19,19}], % {16402,19,[],5,<<>>,[],0,0}}

Remember those “gaps” we left in our sequence of numbers we used to create tuples?

Time to “fill in” those gaps of the sequence to see what happens if we fetch with our existing continuation as data gets populated concurrently.

[[ets:insert(TestOrderedSetTable, {X, X}) || X <- lists:seq(2, 30, 2)]]. % [[true,true,true,true,true,true,true,true,true,true,true, % true,true,true,true]] [[ets:insert(TestTable, {X, X}) || X <- lists:seq(2, 30, 2)]]. % [[true,true,true,true,true,true,true,true,true,true,true, % true,true,true,true]]

Now we re-run our `ets:select/1`

functions with the same continuations as before.

ets:select(Continuation). % {[{12,12},{7,7},{3,3},{10,10},{9,9}], % {20499,224,5,<<>>,[],0}} ets:select(OrdSetContinuation). % {[{10,10},{11,11},{12,12},{13,13},{14,14}], % {16402,14,[],5,<<>>,[],0,0}}

If we compare that to before we can see the we now have even number items in the list. For our `TestTable`

if we look above at the `Continuation`

value itself, we ahve the continuation point as `214`

, since that is the only thing that has changed between that continuation and the resulting continuations from calling `ets:select(Continuation).`

. So with just a number it is hard to infer just how we might expect the continuation to change.

The `OrdSetContinuation`

on the other hand, has a `9`

as its second element in the tuple, after the ETS table id of `16402`

. This also happens to be the key of the last tuple in the result set, which matches up with the `19`

and `14`

in the other continuations. So in the case of the ordered set, we can infer that as part of the continuation for an ETS table of type `ordered_set`

, the continuation tells us the specific key of the last record that was returned, and we continue from that record regardless of any concurrent inserts that may have taken place.

Next time we will take a look at ets:is_compiled_ms/1 and how match specs might play in with continuations based off reading the documentation about `ets:is_compiled_ms/1`

.

–Proctor