-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
ets.erl
3485 lines (2960 loc) · 119 KB
/
ets.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2024. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(ets).
-moduledoc """
Built-in term storage.
This module is an interface to the Erlang built-in term storage BIFs. These
provide the ability to store very large quantities of data in an Erlang runtime
system, and to have constant access time to the data. (In the case of
`ordered_set`, see below, access time is proportional to the logarithm of the
number of stored objects.)
Data is organized as a set of dynamic tables, which can store tuples. Each table
is created by a process. When the process terminates, the table is automatically
destroyed. Every table has access rights set at creation.
Tables are divided into four different types, `set`, `ordered_set`, `bag`, and
`duplicate_bag`. A `set` or `ordered_set` table can only have one object
associated with each key. A `bag` or `duplicate_bag` table can have many objects
associated with each key.
Insert and lookup times in tables of type `set` are constant, regardless of the
table size. For table types `bag` and `duplicate_bag` time is proportional to
the number of objects with the same key. Even seemingly unrelated keys may
inflict linear search to be skipped past while looking for the key of interest
(due to hash collision).
> #### Warning {: .warning }
>
> For tables of type `bag` and `duplicate_bag`, avoid inserting an extensive
> amount of objects with the same key. It will hurt insert and lookup
> performance as well as real time characteristics of the runtime environment
> (hash bucket linear search do not yield).
The `ordered_set` table type uses a binary search tree. Insert and lookup times
are proportional to the logarithm of the number of objects in the table.
[](){: #max_ets_tables }
> #### Note {: .info }
>
> The number of tables stored at one Erlang node _used_ to be limited. This is
> no longer the case (except by memory usage). The previous default limit was
> about 1400 tables and could be increased by setting the environment variable
> `ERL_MAX_ETS_TABLES` or the command line option
> [`+e`](`e:erts:erl_cmd.md#%2Be`) before starting the Erlang runtime system.
> This hard limit has been removed, but it is currently useful to set the
> `ERL_MAX_ETS_TABLES` anyway. It should be set to an approximate of the maximum
> amount of tables used since an internal table for named tables is sized using
> this value. If large amounts of named tables are used and `ERL_MAX_ETS_TABLES`
> hasn't been increased, the performance of named table lookup will degrade.
Notice that there is no automatic garbage collection for tables. Even if there
are no references to a table from any process, it is not automatically destroyed
unless the owner process terminates. To destroy a table explicitly, use function
`delete/1`. The default owner is the process that created the table. To transfer
table ownership at process termination, use option [`heir`](`m:ets#heir`) or
call `give_away/3`.
Some implementation details:
- In the current implementation, every object insert and look-up operation
results in a copy of the object.
- `'$end_of_table'` is not to be used as a key, as this atom is used to mark the
end of the table when using functions `first/1` and `next/2`.
Notice the subtle difference between _matching_ and _comparing equal_, which is
demonstrated by table types `set` and `ordered_set`:
- Two Erlang terms `match` if they are of the same type and have the same value,
so that `1` matches `1`, but not `1.0` (as `1.0` is a `t:float/0` and not an
`t:integer/0`).
- Two Erlang terms _compare equal_ if they either are of the same type and
value, or if both are numeric types and extend to the same value, so that `1`
compares equal to both `1` and `1.0`.
- The `ordered_set` works on the _Erlang term order_ and no defined order exists
between an `t:integer/0` and a `t:float/0` that extends to the same value.
Hence the key `1` and the key `1.0` are regarded as equal in an `ordered_set`
table.
[](){: #ets_failures }
## Failures
Functions in this module fail by raising an error exception with error reason:
- **`badarg`** - If any argument has the wrong format.
- **`badarg`** - If the table identifier is invalid.
- **`badarg`** - If the operation is denied because of table access rights
([protected](`m:ets#protected`) or [private](`m:ets#private`)).
- **`system_limit`** - Modification of a value causes it to not be representable
internally in the VM. For example, incrementation of a counter past the
largest integer representable.
- **`system_limit`** - If a match specification passed as argument has excessive
nesting which causes scheduler stack exhaustion for the scheduler that the
calling process is executing on.
[Scheduler stack size](`e:erts:erl_cmd.md#sched_thread_stack_size`) can be
configured when starting the runtime system.
[](){: #concurrency }
## Concurrency
This module provides some limited support for concurrent access. All updates to
single objects are guaranteed to be both _atomic_ and _isolated_. This means
that an updating operation to a single object either succeeds or fails
completely without any effect (atomicity) and that no intermediate results of
the update can be seen by other processes (isolation). Some functions that
update many objects state that they even guarantee atomicity and isolation for
the entire operation. In database terms the isolation level can be seen as
"serializable", as if all isolated operations are carried out serially, one
after the other in a strict order.
[](){: #traversal }
## Table traversal
There are different ways to traverse through the objects of a table.
- _Single-step_ traversal one key at at time, using `first/1`, `next/2`,
`last/1` and `prev/2`.
- _Single-step_ traversal one key at at time, but using `first_lookup/1`,
`next_lookup/2`, `last_lookup/1` and `prev_lookup/2`. This is more efficient
when you also need to lookup the objects for the keys.
- Search with simple _match patterns_, using [`match/1/2/3`](`match/1`),
`match_delete/2` and [`match_object/1/2/3`](`match_object/1`).
- Search with more powerful _match specifications_, using
[`select/1/2/3`](`select/1`), `select_count/2`, `select_delete/2`,
`select_replace/2` and [`select_reverse/1/2/3`](`select_reverse/1`).
- _Table conversions_, using [`tab2file/2/3`](`tab2file/2`) and `tab2list/1`.
No table traversal will guarantee a consistent snapshot of the entire table if
the table is also updated by concurrent processes during the traversal. The
result of each concurrently updated object may be seen (or not) depending on if
it has happened when the traversal visits that part of the table. The only way
to guarantee a full consistent table snapshot (if you really need that) is to
disallow concurrent updates during the entire traversal.
Moreover, traversals not done in a _safe_ way, on tables where keys are inserted
or deleted during the traversal, may yield the following undesired effects:
- Any key may be missed.
- Any key may be found more than once.
- The traversal may fail with `badarg` exception if keys are deleted.
A table traversal is _safe_ if either
- the table is of type `ordered_set`.
- the entire table traversal is done within one ETS function call.
- function `safe_fixtable/2` is used to keep the table fixated during the entire
traversal.
> #### Note {: .info }
>
> Even though the access of a single object is always guaranteed to be
> [atomic and isolated](`m:ets#module-concurrency`), each traversal through a table to
> find the next key is not done with such guarantees. This is often not a
> problem, but may cause rare subtle "unexpected" effects if a concurrent
> process inserts objects during a traversal. For example, consider one process
> doing
>
> ```erlang
> ets:new(t, [ordered_set, named_table]),
> ets:insert(t, {1}),
> ets:insert(t, {2}),
> ets:insert(t, {3}),
> ```
>
> A concurrent call to `ets:first(t)`, done by another process, may then in rare
> cases return `2` even though `2` has never existed in the table ordered as the
> first key. In the same way, a concurrent call to `ets:next(t, 1)` may return
> `3` even though `3` never existed in the table ordered directly after `1`.
>
> Effects like this are improbable but possible. The probability will further be
> reduced (if not vanish) if table option
> [`write_concurrency`](`m:ets#new_2_write_concurrency`) is not enabled. This
> can also only be a potential concern for `ordered_set` where the traversal
> order is defined.
Traversals using `match` and `select` functions may not need to scan the entire
table depending on how the key is specified. A match pattern with a _fully bound
key_ (without any match variables) will optimize the operation to a single key
lookup without any table traversal at all. For `ordered_set` a _partially bound
key_ will limit the traversal to only scan a subset of the table based on term
order. A partially bound key is either a list or a tuple with a prefix that is
fully bound. Example:
```erlang
1> T = ets:new(t,[ordered_set]), ets:insert(T, {"555-1234", "John Smith"}).
true
2> %% Efficient search of all with area code 555
2> ets:match(T,{[$5,$5,$5,$- |'$1'],'$2'}).
[["1234","John Smith"]]
```
[](){: #match_spec }
## Match Specifications
Some of the functions use a _match specification_, `match_spec`. For a brief
explanation, see `select/2`. For a detailed description, see section
[Match Specifications in Erlang](`e:erts:match_spec.md`) in ERTS User's Guide.
A match specifications with excessive nesting will cause a
[`system_limit`](`m:ets#ets_failures`) error exception to be raised.
""".
%% Interface to the Term store BIF's
%% ets == Erlang Term Store
-export([file2tab/1,
file2tab/2,
foldl/3, foldr/3,
match_delete/2,
tab2file/2,
tab2file/3,
tabfile_info/1,
from_dets/2,
to_dets/2,
init_table/2,
test_ms/2,
tab2list/1,
table/1,
table/2,
fun2ms/1,
match_spec_run/2,
repair_continuation/2]).
-export([i/0, i/1, i/2, i/3]).
-export_type([table/0, table_access/0, table_type/0,
tid/0, match_spec/0, compiled_match_spec/0, match_pattern/0]).
%%-----------------------------------------------------------------------------
-type table_access() :: public | protected | private.
-type table() :: atom() | tid().
-type table_type() :: set | ordered_set | bag | duplicate_bag.
-doc """
Opaque continuation used by [`select/1,3`](`select/1`),
[`select_reverse/1,3`](`select_reverse/1`), [`match/1,3`](`match/1`), and
[`match_object/1,3`](`match_object/1`).
""".
-type continuation() :: '$end_of_table'
| {table(),integer(),integer(),compiled_match_spec(),list(),integer()}
| {table(),_,_,integer(),compiled_match_spec(),list(),integer(),integer()}.
-doc "A table identifier, as returned by `new/2`.".
-opaque tid() :: reference().
-type match_pattern() :: atom() | tuple().
-doc "A match specification, see [Match Specifications](`m:ets#match_spec`).".
-type match_spec() :: [{match_pattern(), [_], [_]}].
%% Keep for backwards compatibility
-export_type([tab/0, comp_match_spec/0]).
-type tab() :: table().
%%-----------------------------------------------------------------------------
%%% BIFs
-export([all/0, delete/1, delete/2, delete_all_objects/1,
delete_object/2, first/1, first_lookup/1, give_away/3, info/1, info/2,
insert/2, insert_new/2, is_compiled_ms/1, last/1, last_lookup/1, lookup/2,
lookup_element/3, lookup_element/4, match/1, match/2, match/3, match_object/1,
match_object/2, match_object/3, match_spec_compile/1,
match_spec_run_r/3, member/2, new/2, next/2, next_lookup/2, prev/2, prev_lookup/2,
rename/2, safe_fixtable/2, select/1, select/2, select/3,
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_element/4,
whereis/1]).
%% internal exports
-export([internal_request_all/0,
internal_delete_all/2,
internal_select_delete/2]).
-doc """
Returns a list of all tables at the node. Named tables are specified by their
names, unnamed tables are specified by their table identifiers.
There is no guarantee of consistency in the returned list. Tables created or
deleted by other processes "during" the `ets:all()` call either are or are not
included in the list. Only tables created/deleted _before_ `ets:all()` is called
are guaranteed to be included/excluded.
""".
-spec all() -> [Table] when
Table :: table().
all() ->
receive_all(ets:internal_request_all(),
erlang:system_info(schedulers),
[]).
receive_all(_Ref, 0, All) ->
All;
receive_all(Ref, N, All) ->
receive
{Ref, SchedAll} ->
receive_all(Ref, N-1, SchedAll ++ All)
end.
-doc false.
-spec internal_request_all() -> reference().
internal_request_all() ->
erlang:nif_error(undef).
-doc "Deletes the entire table `Table`.".
-spec delete(Table) -> true when
Table :: table().
delete(_) ->
erlang:nif_error(undef).
-doc """
Deletes all objects with key `Key` from table `Table`. This function succeeds
even if no objects with key `Key` exist.
""".
-spec delete(Table, Key) -> true when
Table :: table(),
Key :: term().
delete(_, _) ->
erlang:nif_error(undef).
-doc """
Delete all objects in the ETS table `Table`. The operation is guaranteed to be
[atomic and isolated](`m:ets#module-concurrency`).
""".
-spec delete_all_objects(Table) -> true when
Table :: table().
delete_all_objects(Table) ->
_ = ets:internal_delete_all(Table, undefined),
true.
-doc false.
-spec internal_delete_all(Table, undefined) -> NumDeleted when
Table :: table(),
NumDeleted :: non_neg_integer().
internal_delete_all(_, _) ->
erlang:nif_error(undef).
-doc """
Delete the exact object `Object` from the ETS table, leaving objects with the
same key but other differences (useful for type `bag`). In a `duplicate_bag`
table, all instances of the object are deleted.
""".
-spec delete_object(Table, Object) -> true when
Table :: table(),
Object :: tuple().
delete_object(_, _) ->
erlang:nif_error(undef).
-doc """
Returns the first key `Key` in table `Table`. For an `ordered_set` table, the
first key in Erlang term order is returned. For other table types, the first key
according to the internal order of the table is returned. If the table is empty,
`'$end_of_table'` is returned.
To find subsequent keys in the table, use `next/2`.
""".
-spec first(Table) -> Key | '$end_of_table' when
Table :: table(),
Key :: term().
first(_) ->
erlang:nif_error(undef).
-doc """
Similar to `first/1` except that it returns the object(s) along with the key
stored in the table. This is equivalent to doing `first/1` followed by a
`lookup/2`. If the table is empty, `'$end_of_table'` is returned.
To find subsequent objects in the table, use `next_lookup/2`.
""".
-doc(#{since => <<"OTP 27.0">>}).
-spec first_lookup(Table) -> {Key, [Object]} | '$end_of_table' when
Table :: table(),
Key :: term(),
Object :: tuple().
first_lookup(_) ->
erlang:nif_error(undef).
-doc """
Make process `Pid` the new owner of table `Table`. If successful, message
`{'ETS-TRANSFER',Table,FromPid,GiftData}` is sent to the new owner.
The process `Pid` must be alive, local, and not already the owner of the table.
The calling process must be the table owner.
Notice that this function does not affect option [`heir`](`m:ets#heir`) of the
table. A table owner can, for example, set `heir` to itself, give the table
away, and then get it back if the receiver terminates.
""".
-spec give_away(Table, Pid, GiftData) -> true when
Table :: table(),
Pid :: pid(),
GiftData :: term().
give_away(_, _, _) ->
erlang:nif_error(undef).
-doc """
Returns information about table `Table` as a list of tuples. If `Table` has the
correct type for a table identifier, but does not refer to an existing ETS
table, `undefined` is returned. If `Table` is not of the correct type, a
`badarg` exception is raised.
- **`{compressed, boolean()}`** - Indicates if the table is compressed.
- **`{decentralized_counters, boolean()}`** - Indicates whether the table uses
`decentralized_counters`.
- **`{heir, pid() | none}`** - The pid of the heir of the table, or `none` if no
heir is set.
- **`{id,`[ `tid()`](`t:tid/0`)`}`** - The table identifier.
- **`{keypos, integer() >= 1}`** - The key position.
- **`{memory, integer() >= 0}`** - The number of words allocated to the table.
- **`{name, atom()}`** - The table name.
- **`{named_table, boolean()}`** - Indicates if the table is named.
- **`{node, node()}`** - The node where the table is stored. This field is no
longer meaningful, as tables cannot be accessed from other nodes.
- **`{owner, pid()}`** - The pid of the owner of the table.
- **`{protection,` [`access()`](`t:table_access/0`)`}`** - The table access
rights.
- **`{size, integer() >= 0}`** - The number of objects inserted in the table.
- **`{type,` [`type()`](`t:table_type/0`)`}`** - The table type.
- **`{read_concurrency, boolean()}`** - Indicates whether the table uses
`read_concurrency` or not.
- **`{write_concurrency, WriteConcurrencyAlternative}`** - Indicates which
`write_concurrency` option the table uses.
> #### Note {: .info }
>
> The execution time of this function is affected by the
> [`decentralized_counters`](`m:ets#new_2_decentralized_counters`) table option.
> The execution time is much longer when the `decentralized_counters` option is
> set to `true` than when the `decentralized_counters` option is set to `false`.
""".
-spec info(Table) -> InfoList | undefined when
Table :: table(),
InfoList :: [InfoTuple],
InfoTuple :: {compressed, boolean()}
| {decentralized_counters, boolean()}
| {heir, pid() | none}
| {id, tid()}
| {keypos, pos_integer()}
| {memory, non_neg_integer()}
| {name, atom()}
| {named_table, boolean()}
| {node, node()}
| {owner, pid()}
| {protection, table_access()}
| {size, non_neg_integer()}
| {type, table_type()}
| {write_concurrency, boolean()}
| {read_concurrency, boolean()}.
info(_) ->
erlang:nif_error(undef).
-doc """
Returns the information associated with `Item` for table `Table`, or returns
`undefined` if `Table` does not refer an existing ETS table. If `Table` is not
of the correct type, or if `Item` is not one of the allowed values, a `badarg`
exception is raised.
In addition to the `{Item,Value}` pairs defined for `info/1`, the following
items are allowed:
- `Item=binary, Value=BinInfo`
`BinInfo` is a list containing miscellaneous information about binaries kept
by the table. This `Item` can be changed or removed without prior notice. In
the current implementation `BinInfo` is a list of tuples
`{BinaryId,BinarySize,BinaryRefcCount}`.
- `Item=fixed, Value=boolean()`
Indicates if the table is fixed by any process.
- [](){: #info_2_safe_fixed_monotonic_time }
`Item=safe_fixed|safe_fixed_monotonic_time, Value={FixationTime,Info}|false`
If the table is fixed using `safe_fixtable/2`, the call returns a tuple where
`FixationTime` is the last time when the table changed from unfixed to fixed.
The format and value of `FixationTime` depends on `Item`:
- **`safe_fixed`** - `FixationTime` corresponds to the result returned by
`erlang:timestamp/0` at the time of fixation. Notice that when the system
uses single or multi
[time warp modes](`e:erts:time_correction.md#time-warp-modes`) this can
produce strange results, as the use of `safe_fixed` is not
[time warp safe](`e:erts:time_correction.md#time-warp-safe-code`). Time warp
safe code must use `safe_fixed_monotonic_time` instead.
- **`safe_fixed_monotonic_time`** - `FixationTime` corresponds to the result
returned by `erlang:monotonic_time/0` at the time of fixation. The use of
`safe_fixed_monotonic_time` is
[time warp safe](`e:erts:time_correction.md#time-warp-safe-code`).
`Info` is a possibly empty lists of tuples `{Pid,RefCount}`, one tuple for
every process the table is fixed by now. `RefCount` is the value of the
reference counter and it keeps track of how many times the table has been
fixed by the process.
Table fixations are not limited to `safe_fixtable/2`. Temporary fixations may
also be done by for example [traversing functions](`m:ets#traversal`) like
`select` and `match`. Such table fixations are automatically released before
the corresponding functions returns, but they may be seen by a concurrent call
to `ets:info(T,safe_fixed|safe_fixed_monotonic_time)`.
If the table is not fixed at all, the call returns `false`.
- `Item=stats, Value=tuple()`
Returns internal statistics about tables on an internal format used by OTP
test suites. Not for production use.
> #### Note {: .info }
>
> The execution time of this function is affected by the
> [`decentralized_counters`](`m:ets#new_2_decentralized_counters`) table option
> when the second argument of the function is `size` or `memory`. The execution
> time is much longer when the `decentralized_counters` option is set to `true`
> than when the `decentralized_counters` option is set to `false`.
""".
-spec info(Table, Item) -> Value | undefined when
Table :: table(),
Item :: binary | compressed | decentralized_counters | fixed | heir | id | keypos | memory
| name | named_table | node | owner | protection
| safe_fixed | safe_fixed_monotonic_time | size | stats | type
| write_concurrency | read_concurrency,
Value :: term().
info(_, _) ->
erlang:nif_error(undef).
-doc """
Inserts the object or all of the objects in list `ObjectOrObjects` into table
`Table`.
- If the table type is `set` and the key of the inserted objects _matches_ the
key of any object in the table, the old object is replaced.
- If the table type is `ordered_set` and the key of the inserted object
_compares equal_ to the key of any object in the table, the old object is
replaced.
- If the table type is `bag` and the object _matches_ any whole object in the
table, the object is not inserted.
- If the list contains more than one object with _matching_ keys and the table
type is `set`, one is inserted, which one is not defined. The same holds for
table type `ordered_set` if the keys _compare equal_.
The entire operation is guaranteed to be
[atomic and isolated](`m:ets#module-concurrency`), even when a list of objects is
inserted.
[](){: #insert_list_order }
For `bag` and `duplicate_bag`, objects in the list with identical keys will be
inserted in list order (from head to tail). That is, a subsequent call to
[`lookup(T,Key)`](`lookup/2`) will return them in that inserted order.
> #### Note {: .info }
>
> For `bag` the insertion order of indentical keys described above was
> accidentally reverted in OTP 23.0 and later fixed in OTP 25.3. That is, from
> OTP 23.0 up until OTP 25.3 the objects in a list are inserted in reverse order
> (from tail to head).
>
> For `duplicate_bag` the same faulty reverse insertion exist from OTP 23.0
> until OTP 25.3. However, it is unpredictable and may or may not happen. A
> longer list will increase the probabiliy of the insertion being done in
> reverse.
""".
-spec insert(Table, ObjectOrObjects) -> true when
Table :: table(),
ObjectOrObjects :: tuple() | [tuple()].
insert(_, _) ->
erlang:nif_error(undef).
-doc """
Same as `insert/2` except that instead of overwriting objects with the same key
(for `set` or `ordered_set`) or adding more objects with keys already existing
in the table (for `bag` and `duplicate_bag`), `false` is returned.
If `ObjectOrObjects` is a list, the function checks _every_ key before inserting
anything. Nothing is inserted unless _all_ keys present in the list are absent
from the table. Like [`insert/2`](`insert/2`), the entire operation is
guaranteed to be [atomic and isolated](`m:ets#module-concurrency`).
""".
-spec insert_new(Table, ObjectOrObjects) -> boolean() when
Table :: table(),
ObjectOrObjects :: tuple() | [tuple()].
insert_new(_, _) ->
erlang:nif_error(undef).
-doc """
Checks if a term represent a valid compiled
[match specification](`m:ets#match_spec`). A compiled match specification is
only valid on the Erlang node where it was compiled by calling
`match_spec_compile/1`.
> #### Note {: .info }
>
> Before STDLIB 3.4 (OTP 20.0) compiled match specifications did not have an
> external representation. If passed through
> [`binary_to_term(term_to_binary(CMS))`](`binary_to_term/1`) or sent to another
> node and back, the result was always an empty binary `<<>>`.
>
> After STDLIB 3.4 (OTP 20.0) compiled match specifications have an external
> representation as a node specific reference to the original compiled match
> specification. If passed through
> [`binary_to_term(term_to_binary(CMS))`](`binary_to_term/1`) or sent to another
> node and back, the result _may or may not_ be a valid compiled match
> specification depending on if the original compiled match specification was
> still alive.
""".
-spec is_compiled_ms(Term) -> boolean() when
Term :: term().
is_compiled_ms(_) ->
erlang:nif_error(undef).
-doc """
Returns the last key `Key` according to Erlang term order in table `Table` of
type `ordered_set`. For other table types, the function is synonymous to
`first/1`. If the table is empty, `'$end_of_table'` is returned.
To find preceding keys in the table, use `prev/2`.
""".
-spec last(Table) -> Key | '$end_of_table' when
Table :: table(),
Key :: term().
last(_) ->
erlang:nif_error(undef).
-doc """
Similar to `last/1` except that it returns the object(s) along with the key
stored in the table. This is equivalent to doing `last/1` followed by a
`lookup/2`. If the table is empty, `'$end_of_table'` is returned.
To find preceding objects in the table, use `prev_lookup/2`.
""".
-doc(#{since => <<"OTP 27.0">>}).
-spec last_lookup(Table) -> {Key, [Object]} | '$end_of_table' when
Table :: table(),
Key :: term(),
Object :: tuple().
last_lookup(_) ->
erlang:nif_error(undef).
-doc """
Returns a list of all objects with key `Key` in table `Table`.
- For tables of type `set`, `bag`, or `duplicate_bag`, an object is returned
only if the specified key _matches_ the key of the object in the table.
- For tables of type `ordered_set`, an object is returned if the specified key
_compares equal_ to the key of an object in the table.
The difference is the same as between `=:=` and `==`.
As an example, one can insert an object with `t:integer/0` `1` as a key in an
`ordered_set` and get the object returned as a result of doing a
[`lookup/2`](`lookup/2`) with `t:float/0` `1.0` as the key to search for.
For tables of type `set` or `ordered_set`, the function returns either the empty
list or a list with one element, as there cannot be more than one object with
the same key. For tables of type `bag` or `duplicate_bag`, the function returns
a list of arbitrary length.
Notice that the sequential order of object insertions is preserved; the first
object inserted with the specified key is the first in the resulting list, and
so on. See also the note about
[list insertion order](`m:ets#insert_list_order`).
""".
-spec lookup(Table, Key) -> [Object] when
Table :: table(),
Key :: term(),
Object :: tuple().
lookup(_, _) ->
erlang:nif_error(undef).
-doc """
For a table `Table` of type `set` or `ordered_set`, the function returns the
`Pos`:th element of the object with key `Key`.
For tables of type `bag` or `duplicate_bag`, the functions returns a list with
the `Pos`:th element of every object with key `Key`.
If no object with key `Key` exists, the function exits with reason `badarg`.
If `Pos` is larger than the size of the tuple, the function exits with reason
`badarg`.
The difference between `set`, `bag`, and `duplicate_bag` on one hand, and
`ordered_set` on the other, regarding the fact that `ordered_set` view keys as
equal when they _compare equal_ whereas the other table types regard them equal
only when they _match_, holds for [`lookup_element/3`](`lookup_element/3`).
""".
-spec lookup_element(Table, Key, Pos) -> Elem when
Table :: table(),
Key :: term(),
Pos :: pos_integer(),
Elem :: term() | [term()].
lookup_element(_, _, _) ->
erlang:nif_error(undef).
-doc """
For a table `Table` of type `set` or `ordered_set`, the function returns the
`Pos`:th element of the object with key `Key`.
For tables of type `bag` or `duplicate_bag`, the functions returns a list with
the `Pos`:th element of every object with key `Key`.
If no object with key `Key` exists, the function returns `Default`.
If `Pos` is larger than the size of any tuple with a matching key, the function
exits with reason `badarg`.
The difference between `set`, `bag`, and `duplicate_bag` on one hand, and
`ordered_set` on the other, regarding the fact that `ordered_set` view keys as
equal when they _compare equal_ whereas the other table types regard them equal
only when they _match_, holds for [`lookup_element/4`](`lookup_element/4`).
""".
-doc(#{since => <<"OTP 26.0">>}).
-spec lookup_element(Table, Key, Pos, Default) -> Elem when
Table :: table(),
Key :: term(),
Pos :: pos_integer(),
Default :: term(),
Elem :: term() | [term()].
lookup_element(_, _, _, _) ->
erlang:nif_error(undef).
-doc """
Matches the objects in table `Table` against pattern `Pattern`.
A pattern is a term that can contain:
- Bound parts (Erlang terms)
- `'_'` that matches any Erlang term
- Pattern variables `'$N'`, where `N`=0,1,...
The function returns a list with one element for each matching object, where
each element is an ordered list of pattern variable bindings, for example:
```erlang
6> ets:match(T, '$1'). % Matches every object in table
[[{rufsen,dog,7}],[{brunte,horse,5}],[{ludde,dog,5}]]
7> ets:match(T, {'_',dog,'$1'}).
[[7],[5]]
8> ets:match(T, {'_',cow,'$1'}).
[]
```
If the key is specified in the pattern, the match is very efficient. If the key
is not specified, that is, if it is a variable or an underscore, the entire
table must be searched. The search time can be substantial if the table is very
large.
For tables of type `ordered_set`, the result is in the same order as in a
`first`/`next` traversal.
""".
-spec match(Table, Pattern) -> [Match] when
Table :: table(),
Pattern :: match_pattern(),
Match :: [term()].
match(_, _) ->
erlang:nif_error(undef).
-doc """
Works like `match/2`, but returns only a limited (`Limit`) number of matching
objects. Term `Continuation` can then be used in subsequent calls to `match/1`
to get the next chunk of matching objects. This is a space-efficient way to work
on objects in a table, which is faster than traversing the table object by
object using `first/1` and `next/2`.
If the table is empty, `'$end_of_table'` is returned.
Use `safe_fixtable/2` to guarantee [safe traversal](`m:ets#traversal`) for
subsequent calls to `match/1`.
""".
-spec match(Table, Pattern, Limit) -> {[Match], Continuation} |
'$end_of_table' when
Table :: table(),
Pattern :: match_pattern(),
Limit :: pos_integer(),
Match :: [term()],
Continuation :: continuation().
match(_, _, _) ->
erlang:nif_error(undef).
-doc """
Continues a match started with `match/3`. The next chunk of the size specified
in the initial [`match/3`](`match/3`) call is returned together with a new
`Continuation`, which can be used in subsequent calls to this function.
When there are no more objects in the table, `'$end_of_table'` is returned.
""".
-spec match(Continuation) -> {[Match], Continuation} |
'$end_of_table' when
Match :: [term()],
Continuation :: continuation().
match(_) ->
erlang:nif_error(undef).
-doc """
Matches the objects in table `Table` against pattern `Pattern`. For a
description of patterns, see `match/2`. The function returns a list of all
objects that match the pattern.
If the key is specified in the pattern, the match is very efficient. If the key
is not specified, that is, if it is a variable or an underscore, the entire
table must be searched. The search time can be substantial if the table is very
large.
For tables of type `ordered_set`, the result is in the same order as in a
`first`/`next` traversal.
""".
-spec match_object(Table, Pattern) -> [Object] when
Table :: table(),
Pattern :: match_pattern(),
Object :: tuple().
match_object(_, _) ->
erlang:nif_error(undef).
-doc """
Works like `match_object/2`, but only returns a limited (`Limit`) number of
matching objects. Term `Continuation` can then be used in subsequent calls to
`match_object/1` to get the next chunk of matching objects. This is a
space-efficient way to work on objects in a table, which is faster than
traversing the table object by object using `first/1` and `next/2`.
If the table is empty, `'$end_of_table'` is returned.
Use `safe_fixtable/2` to guarantee [safe traversal](`m:ets#traversal`) for
subsequent calls to `match_object/1`.
""".
-spec match_object(Table, Pattern, Limit) -> {[Object], Continuation} |
'$end_of_table' when
Table :: table(),
Pattern :: match_pattern(),
Limit :: pos_integer(),
Object :: tuple(),
Continuation :: continuation().
match_object(_, _, _) ->
erlang:nif_error(undef).
-doc """
Continues a match started with `match_object/3`. The next chunk of the size
specified in the initial [`match_object/3`](`match_object/3`) call is returned
together with a new `Continuation`, which can be used in subsequent calls to
this function.
When there are no more objects in the table, `'$end_of_table'` is returned.
""".
-spec match_object(Continuation) -> {[Object], Continuation} |
'$end_of_table' when
Object :: tuple(),
Continuation :: continuation().
match_object(_) ->
erlang:nif_error(undef).
-doc """
Transforms a [match specification](`m:ets#match_spec`) into an internal
representation that can be used in subsequent calls to `match_spec_run/2`. The
internal representation is opaque. To check the validity of a compiled match
specification, use `is_compiled_ms/1`.
If term `MatchSpec` does not represent a valid match specification, a `badarg`
exception is raised.
> #### Note {: .info }
>
> This function has limited use in normal code. It is used by the `m:dets`
> module to perform the `dets:select/1` operations.
""".
-spec match_spec_compile(MatchSpec) -> CompiledMatchSpec when
MatchSpec :: match_spec(),
CompiledMatchSpec :: compiled_match_spec().
match_spec_compile(_) ->
erlang:nif_error(undef).
-doc false.
-spec match_spec_run_r(List, CompiledMatchSpec, list()) -> list() when
List :: [term()],
CompiledMatchSpec :: compiled_match_spec().
match_spec_run_r(_, _, _) ->
erlang:nif_error(undef).
-doc """
Works like `lookup/2`, but does not return the objects. Returns `true` if one or
more elements in the table has key `Key`, otherwise `false`.
""".
-spec member(Table, Key) -> boolean() when
Table :: table(),
Key :: term().
member(_, _) ->
erlang:nif_error(undef).
-doc """
Creates a new table and returns a table identifier that can be used in
subsequent operations. The table identifier can be sent to other processes so
that a table can be shared between different processes within a node.
Parameter `Options` is a list of options that specifies table type, access
rights, key position, and whether the table is named. Default values are used
for omitted options. This means that not specifying any options (`[]`) is the
same as specifying
`[set, protected, {keypos,1}, {heir,none}, {write_concurrency,false}, {read_concurrency,false}, {decentralized_counters,false}]`.
- **`set`** - The table is a `set` table: one key, one object, no order among
objects. This is the default table type.
- **`ordered_set`** - The table is a `ordered_set` table: one key, one object,
ordered in Erlang term order, which is the order implied by the < and >
operators. Tables of this type have a somewhat different behavior in some
situations than tables of other types. Most notably, the `ordered_set` tables
regard keys as equal when they _compare equal_, not only when they match. This
means that to an `ordered_set` table, `t:integer/0` `1` and `t:float/0` `1.0`
are regarded as equal. This also means that the key used to lookup an element
does not necessarily _match_ the key in the returned elements, if
`t:float/0`'s and `t:integer/0`'s are mixed in keys of a table.
- **`bag`** - The table is a `bag` table, which can have many objects, but only
one instance of each object, per key.
- **`duplicate_bag`** - The table is a `duplicate_bag` table, which can have
many objects, including multiple copies of the same object, per key.
- **`public`** - Any process can read or write to the table.
[](){: #protected }
- **`protected`** - The owner process can read and write to the table. Other
processes can only read the table. This is the default setting for the access
rights.
[](){: #private }