File 1091-Add-ets-whereis-1-for-resolving-table-names-tid.patch of Package erlang

From 8f3536583a6338e3a61dbf008d674f54a77e401c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Wed, 21 Feb 2018 12:57:25 +0100
Subject: [PATCH 1/2] Add ets:whereis/1 for resolving table names -> tid()

---
 erts/emulator/beam/bif.tab    |  1 +
 erts/emulator/beam/erl_db.c   | 28 +++++++++++++++++++++++++++-
 lib/stdlib/doc/src/ets.xml    | 20 ++++++++++++++++++++
 lib/stdlib/src/ets.erl        | 11 +++++++++--
 lib/stdlib/test/ets_SUITE.erl | 35 ++++++++++++++++++++++++++++++++++-
 5 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index c0d5e8ce74..b5725e4185 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -685,3 +685,8 @@ bif erlang:iolist_to_iovec/1
 #
 
 bif erlang:iolist_to_iovec/1
+#
+# New in 21.0
+#
+
+bif ets:whereis/1
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 3ba0886464..1ab1c4a363 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -1753,6 +1753,28 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
     BIF_RET(ret);
 }
 
+/*
+** Retrieves the tid() of a named ets table.
+*/
+BIF_RETTYPE ets_whereis_1(BIF_ALIST_1)
+{
+    DbTable* tb;
+    Eterm res;
+
+    if (is_not_atom(BIF_ARG_1)) {
+        BIF_ERROR(BIF_P, BADARG);
+    }
+
+    if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ)) == NULL) {
+        BIF_RET(am_undefined);
+    }
+
+    res = make_tid(BIF_P, tb);
+    db_unlock(tb, LCK_READ);
+
+    BIF_RET(res);
+}
+
 /* 
 ** The lookup BIF 
 */
@@ -3126,7 +3148,8 @@ BIF_RETTYPE ets_info_1(BIF_ALIST_1)
     static Eterm fields[] = {am_protection, am_keypos, am_type, am_named_table,
                              am_node, am_size, am_name, am_heir, am_owner, am_memory, am_compressed,
                              am_write_concurrency,
-                             am_read_concurrency};
+                             am_read_concurrency,
+                             am_id};
     Eterm results[sizeof(fields)/sizeof(Eterm)];
     DbTable* tb;
     Eterm res;
@@ -4016,7 +4039,10 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What)
 	ret = is_table_named(tb) ? am_true : am_false;
     } else if (What == am_compressed) {
 	ret = tb->common.compress ? am_true : am_false;
+    } else if (What == am_id) {
+        ret = make_tid(p, tb);
     }
+
     /*
      * For debugging purposes
      */
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index 1b31a1ec9d..b616e97714 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -487,6 +487,11 @@ Error: fun containing local Erlang function calls
             <p>The pid of the heir of the table, or <c>none</c> if no heir
               is set.</p>
           </item>
+          <tag><c>{id,</c><seealso marker="#type-tid">
+              <c>tid()</c></seealso><c>}</c></tag>
+          <item>
+            <p>The table identifier.</p>
+          </item>
           <tag><c>{keypos, integer() >= 1}</c></tag>
           <item>
             <p>The key position.</p>
@@ -2037,6 +2042,21 @@ true</pre>
         </list>
       </desc>
     </func>
+
+    <func>
+      <name name="whereis" arity="1"/>
+      <fsummary>Retrieves the tid() of a named table.</fsummary>
+      <desc>
+        <p>This function returns the
+          <seealso marker="#type-tid"><c>tid()</c></seealso> of the named table
+          identified by <c><anno>TableName</anno></c>, or <c>undefined</c> if
+          no such table exists. The <c>tid()</c> can be used in place of the
+          table name in all operations, which is slightly faster since the name
+          does not have to be resolved on each call.</p>
+        <p>If the table is deleted, the <c>tid()</c> will be invalid even if
+          another named table is created with the same name.</p>
+      </desc>
+    </func>
   </funcs>
 </erlref>
 
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 039ab45868..6a559f0be5 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -73,7 +73,8 @@
          select_count/2, select_delete/2, select_replace/2, select_reverse/1,
          select_reverse/2, select_reverse/3, setopts/2, slot/2,
          take/2,
-         update_counter/3, update_counter/4, update_element/3]).
+         update_counter/3, update_counter/4, update_element/3,
+         whereis/1]).
 
 %% internal exports
 -export([internal_request_all/0]).
@@ -145,6 +146,7 @@ give_away(_, _, _) ->
       InfoList :: [InfoTuple],
       InfoTuple :: {compressed, boolean()}
                  | {heir, pid() | none}
+                 | {id, tid()}
                  | {keypos, pos_integer()}
                  | {memory, non_neg_integer()}
                  | {name, atom()}
@@ -162,7 +164,7 @@ info(_) ->
 
 -spec info(Tab, Item) -> Value | undefined when
       Tab :: tab(),
-      Item :: compressed | fixed | heir | keypos | memory
+      Item :: compressed | fixed | heir | id | keypos | memory
             | name | named_table | node | owner | protection
             | safe_fixed | safe_fixed_monotonic_time | size | stats | type
 	    | write_concurrency | read_concurrency,
@@ -512,6 +514,11 @@ update_counter(_, _, _, _) ->
 update_element(_, _, _) ->
     erlang:nif_error(undef).
 
+-spec whereis(TableName) -> tid() | undefined when
+    TableName :: atom().
+whereis(_) ->
+    erlang:nif_error(undef).
+
 %%% End of BIFs
 
 -opaque comp_match_spec() :: reference().
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 0cfb1b5516..8b651f4b43 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -78,6 +78,7 @@
 -export([ets_all/1]).
 -export([massive_ets_all/1]).
 -export([take/1]).
+-export([whereis_table/1]).
 
 -export([init_per_testcase/2, end_per_testcase/2]).
 %% Convenience for manual testing
@@ -137,7 +138,8 @@ all() ->
      otp_9423,
      ets_all,
      massive_ets_all,
-     take].
+     take,
+     whereis_table].
 
 groups() ->
     [{new, [],
@@ -4099,6 +4101,7 @@ info_do(Opts) ->
     {value, {keypos, 2}} = lists:keysearch(keypos, 1, Res),
     {value, {protection, protected}} =
 	lists:keysearch(protection, 1, Res),
+    {value, {id, Tab}} = lists:keysearch(id, 1, Res),
     true = ets:delete(Tab),
     undefined = ets:info(non_existing_table_xxyy),
     undefined = ets:info(non_existing_table_xxyy,type),
@@ -5892,6 +5895,36 @@ take(Config) when is_list(Config) ->
     ets:delete(T3),
     ok.
 
+whereis_table(Config) when is_list(Config) ->
+    %% Do we return 'undefined' when the named table doesn't exist?
+    undefined = ets:whereis(whereis_test),
+
+    %% Does the tid() refer to the same table as the name?
+    whereis_test = ets:new(whereis_test, [named_table]),
+    Tid = ets:whereis(whereis_test),
+
+    ets:insert(whereis_test, [{hello}, {there}]),
+
+    [[{hello}],[{there}]] = ets:match(whereis_test, '$1'),
+    [[{hello}],[{there}]] = ets:match(Tid, '$1'),
+
+    true = ets:delete_all_objects(Tid),
+
+    [] = ets:match(whereis_test, '$1'),
+    [] = ets:match(Tid, '$1'),
+
+    %% Does the name disappear when deleted through the tid()?
+    true = ets:delete(Tid),
+    undefined = ets:info(whereis_test),
+    {'EXIT',{badarg, _}} = (catch ets:match(whereis_test, '$1')),
+
+    %% Is the old tid() broken when the table is re-created with the same
+    %% name?
+    whereis_test = ets:new(whereis_test, [named_table]),
+    [] = ets:match(whereis_test, '$1'),
+    {'EXIT',{badarg, _}} = (catch ets:match(Tid, '$1')),
+
+    ok.
 
 %%
 %% Utility functions:
-- 
2.16.2