53
53
/* Get a key from any table structure and a tagged object */
54
54
#define TERM_GETKEY(tb, obj) db_getkey((tb)->common.keypos, (obj))
56
/* Utility macros for determining need of auto fixtable */
57
/* How safe are we from double-hits or missed objects
58
** when iterating without fixation? */
60
ITER_UNSAFE, /* Must fixate to be safe */
61
ITER_SAFE_LOCKED, /* Safe while table is locked, not between trap calls */
62
ITER_SAFE /* No need to fixate at all */
65
# define ITERATION_SAFETY(Proc,Tab) \
66
((IS_TREE_TABLE((Tab)->common.status) || ONLY_WRITER(Proc,Tab)) ? ITER_SAFE \
67
: (((Tab)->common.status & DB_FINE_LOCKED) ? ITER_UNSAFE : ITER_SAFE_LOCKED))
69
# define ITERATION_SAFETY(Proc,Tab) \
70
((IS_TREE_TABLE((Tab)->common.status) || ONLY_WRITER(Proc,Tab)) \
71
? ITER_SAFE : ITER_SAFE_LOCKED)
58
#define ONLY_WRITER(P,T) (((T)->common.status & DB_PRIVATE) || \
59
(((T)->common.status & DB_PROTECTED) && (T)->common.owner == (P)->id))
60
#define ONLY_READER(P,T) (((T)->common.status & DB_PRIVATE) && \
61
(T)->common.owner == (P)->id)
62
74
#define DID_TRAP(P,Ret) (!is_value(Ret) && ((P)->freason == TRAP))
63
#define SOLE_LOCKER(P,Fixations) ((Fixations) != NULL && \
64
(Fixations)->next == NULL && (Fixations)->pid == (P)->id && \
65
(Fixations)->counter == 1)
233
248
erts_smp_rwmtx_destroy(&tb->common.rwlock);
249
erts_smp_mtx_destroy(&tb->common.fixlock);
235
erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
251
ASSERT(is_immed(tb->common.heir_data));
252
erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
236
253
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbTable));
242
static ERTS_INLINE void db_init_lock(DbTable* tb, char *name)
259
static ERTS_INLINE void db_init_lock(DbTable* tb, char *rwname, char* fixname)
244
261
erts_refc_init(&tb->common.ref, 1);
262
erts_refc_init(&tb->common.fixref, 0);
246
#ifdef ERTS_ENABLE_LOCK_COUNT
247
erts_smp_rwmtx_init_x(&tb->common.rwlock, name, tb->common.the_name);
249
erts_smp_rwmtx_init(&tb->common.rwlock, name);
264
# ifdef ERTS_ENABLE_LOCK_COUNT
265
erts_smp_rwmtx_init_x(&tb->common.rwlock, rwname, tb->common.the_name);
266
erts_smp_mtx_init_x(&tb->common.fixlock, fixname, tb->common.the_name);
268
erts_smp_rwmtx_init(&tb->common.rwlock, rwname);
269
erts_smp_mtx_init(&tb->common.fixlock, fixname);
271
tb->common.is_thread_safe = !(tb->common.status & DB_FINE_LOCKED);
254
275
static ERTS_INLINE void db_lock_take_over_ref(DbTable* tb, db_lock_kind_t kind)
257
if (kind == LCK_WRITE)
258
erts_smp_rwmtx_rwlock(&tb->common.rwlock);
278
ASSERT(tb != meta_pid_to_tab && tb != meta_pid_to_fixed_tab);
279
if (tb->common.type & DB_FINE_LOCKED) {
280
if (kind == LCK_WRITE) {
281
erts_smp_rwmtx_rwlock(&tb->common.rwlock);
282
tb->common.is_thread_safe = 1;
284
erts_smp_rwmtx_rlock(&tb->common.rwlock);
285
ASSERT(!tb->common.is_thread_safe);
260
erts_smp_rwmtx_rlock(&tb->common.rwlock);
293
erts_smp_rwmtx_rwlock(&tb->common.rwlock);
296
erts_smp_rwmtx_rlock(&tb->common.rwlock);
298
ASSERT(tb->common.is_thread_safe);
272
311
static ERTS_INLINE void db_unlock(DbTable* tb, db_lock_kind_t kind)
275
if (kind == LCK_WRITE)
276
erts_smp_rwmtx_rwunlock(&tb->common.rwlock);
278
erts_smp_rwmtx_runlock(&tb->common.rwlock);
314
ASSERT(tb != meta_pid_to_tab && tb != meta_pid_to_fixed_tab);
316
if (tb->common.type & DB_FINE_LOCKED) {
317
if (tb->common.is_thread_safe) {
318
ASSERT(kind == LCK_WRITE);
319
tb->common.is_thread_safe = 0;
320
erts_smp_rwmtx_rwunlock(&tb->common.rwlock);
323
ASSERT(kind != LCK_WRITE);
324
erts_smp_rwmtx_runlock(&tb->common.rwlock);
328
ASSERT(tb->common.is_thread_safe);
332
erts_smp_rwmtx_rwunlock(&tb->common.rwlock);
335
erts_smp_rwmtx_runlock(&tb->common.rwlock);
280
339
(void) db_unref(tb); /* May delete table... */
343
static ERTS_INLINE void db_meta_lock(DbTable* tb, db_lock_kind_t kind)
345
ASSERT(tb == meta_pid_to_tab || tb == meta_pid_to_fixed_tab);
346
ASSERT(kind != LCK_WRITE);
347
/* As long as we only lock for READ we don't have to lock at all. */
350
static ERTS_INLINE void db_meta_unlock(DbTable* tb, db_lock_kind_t kind)
352
ASSERT(tb == meta_pid_to_tab || tb == meta_pid_to_fixed_tab);
353
ASSERT(kind != LCK_WRITE);
283
356
static ERTS_INLINE
284
DbTable* db_get_table_aux(Process *p,
288
db_lock_kind_t (*get_kind)(DbTable *))
357
DbTable* db_get_table(Process *p,
290
362
DbTable *tb = NULL;
324
396
erts_smp_rwmtx_runlock(rwlock);
329
kind = (*get_kind)(tb);
331
db_lock_take_over_ref(tb, kind);
399
db_lock_take_over_ref(tb, kind);
332
400
if (tb->common.id == id && ((tb->common.status & what) != 0 ||
333
401
p->id == tb->common.owner)) {
341
static ERTS_INLINE DbTable* db_get_table(Process *p,
346
return db_get_table_aux(p, id, what, kind, NULL);
349
static ERTS_INLINE DbTable* db_get_table2(Process *p,
352
db_lock_kind_t (*get_kind)(DbTable *))
354
return db_get_table_aux(p, id, what, LCK_WRITE, get_kind);
357
409
/* Requires meta_main_tab_locks[slot] locked.
494
561
BIF_RETTYPE ets_safe_fixtable_2(BIF_ALIST_2)
499
566
erts_fprintf(stderr,
500
567
"ets:safe_fixtable(%T,%T); Process: %T, initial: %T:%T/%bpu\n",
501
568
BIF_ARG_1, BIF_ARG_2, BIF_P->id,
502
569
BIF_P->initial[0], BIF_P->initial[1], BIF_P->initial[2]);
504
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_WRITE)) == NULL) {
505
BIF_ERROR(BIF_P, BADARG);
571
kind = (BIF_ARG_2 == am_true) ? LCK_READ : LCK_WRITE_REC;
573
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, kind)) == NULL) {
574
BIF_ERROR(BIF_P, BADARG);
508
577
if (BIF_ARG_2 == am_true) {
509
578
fix_table_locked(BIF_P, tb);
511
580
else if (BIF_ARG_2 == am_false) {
512
if (tb->common.status & DB_FIXED) {
513
582
unfix_table_locked(BIF_P, tb);
517
db_unlock(tb, LCK_WRITE);
518
587
BIF_ERROR(BIF_P, BADARG);
520
db_unlock(tb, LCK_WRITE);
521
590
BIF_RET(am_true);
525
#define STEP_LOCK_TYPE(T) \
526
(IS_TREE_TABLE((T)->common.type) ? LCK_WRITE : LCK_READ)
528
#define STEP_LOCK_TYPE(T) LCK_WRITE
531
static db_lock_kind_t
532
step_lock_type(DbTable *tb)
534
return STEP_LOCK_TYPE(tb);
538
595
** Returns the first Key in a table
784
840
Eterm incr, warp, oldcnt;
786
842
if (is_not_list(iter)) {
789
845
upop = CAR(list_val(iter));
790
846
if (is_not_tuple(upop)) {
793
849
tpl = tuple_val(upop);
794
850
switch (arityval(*tpl)) {
795
851
case 4: /* threshold specified */
796
852
if (is_not_integer(tpl[3])) {
800
856
if (is_big(warp)) {
801
857
halloc_size += BIG_NEED_SIZE(big_arity(warp));
803
859
else if (is_not_small(warp)) {
806
862
/* Fall through */
808
864
if (!is_small(tpl[1])) {
812
868
if (is_big(incr)) {
813
869
halloc_size += BIG_NEED_SIZE(big_arity(incr));
815
871
else if (is_not_small(incr)) {
818
874
position = signed_val(tpl[1]);
819
875
if (position < 1 || position == tb->common.keypos ||
820
876
position > arityval(handle.dbterm->tpl[0])) {
823
879
oldcnt = handle.dbterm->tpl[position];
824
880
if (is_big(oldcnt)) {
825
881
halloc_size += BIG_NEED_SIZE(big_arity(oldcnt));
827
883
else if (is_not_small(oldcnt)) {
834
890
halloc_size += 2; /* worst growth case: small(0)+small(0)=big(2) */
982
1042
int cret = DB_ERROR_NONE;
983
1043
Eterm ret = am_true;
1045
db_lock_kind_t kind;
990
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL) {
1049
if (is_list(BIF_ARG_2)) {
1050
if (CDR(list_val(BIF_ARG_2)) != NIL) {
1053
DbTableMethod* meth;
1055
/* More than one object, use LCK_WRITE to keep atomicy */
1057
tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, kind);
1059
BIF_ERROR(BIF_P, BADARG);
1061
meth = tb->common.meth;
1062
for (lst = BIF_ARG_2; is_list(lst); lst = CDR(list_val(lst))) {
1063
if (is_not_tuple(CAR(list_val(lst)))
1064
|| (arityval(*tuple_val(CAR(list_val(lst))))
1065
< tb->common.keypos)) {
1072
for (lst = BIF_ARG_2; is_list(lst); lst = CDR(list_val(lst))) {
1073
cret = meth->db_member(tb, TERM_GETKEY(tb,CAR(list_val(lst))),
1075
if ((cret != DB_ERROR_NONE) || (lookup_ret != am_false)) {
1081
for (lst = BIF_ARG_2; is_list(lst); lst = CDR(list_val(lst))) {
1082
cret = meth->db_put(tb,CAR(list_val(lst)), 0);
1083
if (cret != DB_ERROR_NONE)
1088
obj = CAR(list_val(BIF_ARG_2));
1093
/* Only one object (or NIL)
1095
kind = LCK_WRITE_REC;
1096
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, kind)) == NULL) {
991
1097
BIF_ERROR(BIF_P, BADARG);
993
1099
if (BIF_ARG_2 == NIL) {
994
db_unlock(tb, LCK_WRITE);
1100
db_unlock(tb, kind);
995
1101
BIF_RET(am_true);
997
meth = tb->common.meth;
998
if (is_list(BIF_ARG_2)) {
999
for (lst = BIF_ARG_2; is_list(lst); lst = CDR(list_val(lst))) {
1000
if (is_not_tuple(CAR(list_val(lst))) ||
1001
(arityval(*tuple_val(CAR(list_val(lst)))) < tb->common.keypos)) {
1009
for (lst = BIF_ARG_2; is_list(lst); lst = CDR(list_val(lst))) {
1010
cret = meth->db_member(BIF_P, tb,
1011
TERM_GETKEY(tb,CAR(list_val(lst))),
1013
if ((cret != DB_ERROR_NONE) || (lookup_ret != am_false)) {
1019
for (lst = BIF_ARG_2; is_list(lst); lst = CDR(list_val(lst))) {
1020
cret = meth->db_put(BIF_P, tb,CAR(list_val(lst)),&ret);
1021
if (cret != DB_ERROR_NONE)
1025
if (is_not_tuple(BIF_ARG_2) ||
1026
(arityval(*tuple_val(BIF_ARG_2)) < tb->common.keypos)) {
1029
cret = meth->db_member(BIF_P, tb,TERM_GETKEY(tb,BIF_ARG_2),
1031
if ((cret != DB_ERROR_NONE) || (lookup_ret != am_false))
1034
cret = meth->db_put(BIF_P,tb,BIF_ARG_2, &ret);
1103
if (is_not_tuple(obj)
1104
|| (arityval(*tuple_val(obj)) < tb->common.keypos)) {
1107
cret = tb->common.meth->db_put(tb, obj,
1108
1); /* key_clash_fail */
1039
db_unlock(tb, LCK_WRITE);
1111
db_unlock(tb, kind);
1040
1112
switch (cret) {
1041
1113
case DB_ERROR_NONE:
1115
case DB_ERROR_BADKEY:
1043
1117
case DB_ERROR_SYSRES:
1044
1118
BIF_ERROR(BIF_P, SYSTEM_LIMIT);
1046
1120
BIF_ERROR(BIF_P, BADARG);
1049
db_unlock(tb, LCK_WRITE);
1123
db_unlock(tb, kind);
1050
1124
BIF_ERROR(BIF_P, BADARG);
1148
1226
else if (is_tuple(val)) {
1149
1227
Eterm *tp = tuple_val(val);
1151
if ((arityval(tp[0]) == 2) && (tp[1] == am_keypos) &&
1152
is_small(tp[2]) && (signed_val(tp[2]) > 0)) {
1153
keypos = signed_val(tp[2]);
1156
BIF_ERROR(BIF_P, BADARG);
1228
if (arityval(tp[0]) == 2) {
1229
if (tp[1] == am_keypos
1230
&& is_small(tp[2]) && (signed_val(tp[2]) > 0)) {
1231
keypos = signed_val(tp[2]);
1233
else if (tp[1] == am_write_concurrency) {
1234
if (tp[2] == am_true) {
1236
} else if (tp[2] == am_false) {
1240
else if (tp[1] == am_heir && tp[2] == am_none) {
1242
heir_data = am_undefined;
1246
else if (arityval(tp[0]) == 3 && tp[1] == am_heir
1247
&& is_internal_pid(tp[2])) {
1159
1253
else if (val == am_public) {
1160
1254
status |= DB_PUBLIC;
1161
status &= ~DB_PROTECTED;
1255
status &= ~(DB_PROTECTED|DB_PRIVATE);
1163
1257
else if (val == am_private) {
1164
1258
status |= DB_PRIVATE;
1165
status &= ~DB_PROTECTED;
1259
status &= ~(DB_PROTECTED|DB_PUBLIC);
1167
1261
else if (val == am_named_table) {
1170
1264
else if (val == am_set || val == am_protected)
1173
BIF_ERROR(BIF_P, BADARG);
1175
1268
list = CDR(list_val(list));
1177
if (is_not_nil(list)) /* it must be a well formed list */
1178
BIF_ERROR(BIF_P, BADARG);
1270
if (is_not_nil(list)) { /* bad opt or not a well formed list */
1271
BIF_ERROR(BIF_P, BADARG);
1273
if (IS_HASH_TABLE(status)) {
1276
if (is_fine_locked && !(status & DB_PRIVATE)) {
1277
status |= DB_FINE_LOCKED;
1281
else if (IS_TREE_TABLE(status)) {
1285
BIF_ERROR(BIF_P, BADARG);
1180
1288
/* we create table outside any table lock
1181
1289
* and take the unusal cost of destroy table if it
1187
1295
erts_smp_atomic_init(&init_tb.common.memory_size, 0);
1188
1296
tb = (DbTable*) erts_db_alloc(ERTS_ALC_T_DB_TABLE,
1297
&init_tb, sizeof(DbTable));
1191
1298
ERTS_ETS_MISC_MEM_ADD(sizeof(DbTable));
1192
1299
erts_smp_atomic_init(&tb->common.memory_size,
1193
1300
erts_smp_atomic_read(&init_tb.common.memory_size));
1196
if (IS_HASH_TABLE(status))
1198
else if (IS_TREE_TABLE(status))
1203
1303
tb->common.meth = meth;
1206
1304
tb->common.the_name = BIF_ARG_1;
1207
tb->common.status = status;
1209
db_init_lock(tb, "db_tab");
1305
tb->common.status = status;
1210
1306
#ifdef ERTS_SMP
1211
1307
tb->common.type = status & ERTS_ETS_TABLE_TYPES;
1212
1308
/* Note, 'type' is *read only* from now on... */
1310
db_init_lock(tb, "db_tab", "db_tab_fix");
1214
1311
tb->common.keypos = keypos;
1215
1312
tb->common.owner = BIF_P->id;
1313
set_heir(BIF_P, tb, heir, heir_data);
1217
tb->common.nitems = 0;
1218
tb->common.kept_items = 0;
1315
erts_smp_atomic_init(&tb->common.nitems, 0);
1220
1317
tb->common.fixations = NULL;
1223
cret = DB_ERROR_UNSPEC;
1225
cret = meth->db_create(BIF_P, tb);
1226
if (cret != DB_ERROR_NONE) {
1227
erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
1228
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbTable));
1229
BIF_ERROR(BIF_P, BADARG);
1319
cret = meth->db_create(BIF_P, tb);
1320
ASSERT(cret == DB_ERROR_NONE);
1232
1322
erts_smp_spin_lock(&meta_main_tab_main_lock);
1288
1380
erts_smp_atomic_read(&meta_pid_to_fixed_tab->common.memory_size));
1291
db_lock(meta_pid_to_tab, LCK_WRITE);
1292
if (db_put_hash(NULL, meta_pid_to_tab,
1293
TUPLE2(meta_tuple, BIF_P->id,
1294
make_small(slot)),&dummy) != DB_ERROR_NONE) {
1383
db_meta_lock(meta_pid_to_tab, LCK_WRITE_REC);
1384
if (db_put_hash(meta_pid_to_tab,
1385
TUPLE2(meta_tuple, BIF_P->id, make_small(slot)),
1386
0) != DB_ERROR_NONE) {
1295
1387
erl_exit(1,"Could not update ets metadata.");
1297
db_unlock(meta_pid_to_tab, LCK_WRITE);
1389
db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC);
1434
1526
if (tb->common.owner != BIF_P->id) {
1436
1527
Eterm meta_tuple[3];
1439
* The process is being deleted by a process other than its owner.
1530
* The table is being deleted by a process other than its owner.
1440
1531
* To make sure that the table will be completely deleted if the
1441
1532
* current process will be killed (e.g. by an EXIT signal), we will
1442
1533
* now transfer the ownership to the current process.
1444
db_lock(meta_pid_to_tab, LCK_WRITE);
1535
db_meta_lock(meta_pid_to_tab, LCK_WRITE_REC);
1445
1536
db_erase_bag_exact2(meta_pid_to_tab, tb->common.owner,
1446
1537
make_small(tb->common.slot));
1448
1539
BIF_P->flags |= F_USING_DB;
1449
1540
tb->common.owner = BIF_P->id;
1542
db_put_hash(meta_pid_to_tab,
1453
1543
TUPLE2(meta_tuple,BIF_P->id,make_small(tb->common.slot)),
1455
db_unlock(meta_pid_to_tab, LCK_WRITE);
1545
db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC);
1547
/* disable inheritance */
1549
tb->common.heir = am_none;
1458
1551
free_fixations_locked(tb);
1573
** BIF ets:give_away(Tab, Pid, GiftData)
1575
BIF_RETTYPE ets_give_away_3(BIF_ALIST_3)
1577
Process* to_proc = NULL;
1578
ErtsProcLocks to_locks = ERTS_PROC_LOCK_MAIN;
1580
Eterm to_pid = BIF_ARG_2;
1584
if (!is_internal_pid(to_pid)) {
1587
to_proc = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN, to_pid, to_locks);
1588
if (to_proc == NULL) {
1592
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL
1593
|| tb->common.owner != BIF_P->id) {
1596
from_pid = tb->common.owner;
1597
if (to_pid == from_pid) {
1598
goto badarg; /* or should we be idempotent? return false maybe */
1601
db_meta_lock(meta_pid_to_tab, LCK_WRITE_REC);
1602
db_erase_bag_exact2(meta_pid_to_tab, tb->common.owner,
1603
make_small(tb->common.slot));
1605
to_proc->flags |= F_USING_DB;
1606
tb->common.owner = to_pid;
1608
db_put_hash(meta_pid_to_tab,
1609
TUPLE2(buf,to_pid,make_small(tb->common.slot)),
1611
db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC);
1613
db_unlock(tb,LCK_WRITE);
1614
erts_send_message(BIF_P, to_proc, &to_locks,
1615
TUPLE4(buf, am_ETS_TRANSFER, tb->common.id, from_pid, BIF_ARG_3),
1617
erts_smp_proc_unlock(to_proc, to_locks);
1621
if (to_proc != NULL && to_proc != BIF_P) erts_smp_proc_unlock(to_proc, to_locks);
1622
if (tb != NULL) db_unlock(tb, LCK_WRITE);
1623
BIF_ERROR(BIF_P, BADARG);
1626
BIF_RETTYPE ets_setopts_2(BIF_ALIST_2)
1633
if (is_list(BIF_ARG_2)) {
1634
if (CDR(list_val(BIF_ARG_2)) != NIL) {
1637
opt = CAR(list_val(BIF_ARG_2));
1642
if (!is_tuple(opt)) {
1645
tp = tuple_val(opt);
1648
if (arityval(tp[0]) == 3 && tp[1] == am_heir && is_internal_pid(tp[2])) {
1651
else if (arityval(tp[0]) == 2 && tp[1] == am_heir && tp[2] == am_none) {
1652
heir_data = am_undefined;
1656
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL
1657
|| tb->common.owner != BIF_P->id) {
1662
set_heir(BIF_P, tb, tp[2], heir_data);
1664
db_unlock (tb,LCK_WRITE);
1669
db_unlock(tb,LCK_WRITE);
1671
BIF_ERROR(BIF_P, BADARG);
1480
1675
** BIF to erase a whole table and release all memory it holds
1482
1677
BIF_RETTYPE ets_delete_all_objects_1(BIF_ALIST_1)
1539
1734
CHECK_TABLES();
1541
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL) {
1736
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE_REC)) == NULL) {
1542
1737
BIF_ERROR(BIF_P, BADARG);
1544
1739
if (is_not_tuple(BIF_ARG_2) ||
1545
1740
(arityval(*tuple_val(BIF_ARG_2)) < tb->common.keypos)) {
1546
db_unlock(tb, LCK_WRITE);
1741
db_unlock(tb, LCK_WRITE_REC);
1547
1742
BIF_ERROR(BIF_P, BADARG);
1550
cret = tb->common.meth->db_erase_object(BIF_P, tb,
1552
db_unlock(tb, LCK_WRITE);
1745
cret = tb->common.meth->db_erase_object(tb, BIF_ARG_2, &ret);
1746
db_unlock(tb, LCK_WRITE_REC);
1554
1748
switch (cret) {
1555
1749
case DB_ERROR_NONE:
1575
1769
CHECK_TABLES();
1578
* Make sure that the table exists.
1580
if (!is_tuple(a1)) {
1581
/* "Cannot" happen, this is not a real BIF, its trapped
1582
to under controlled conditions */
1583
erl_exit(1,"Internal error in ets:select_delete");
1770
ASSERT(is_tuple(a1));
1586
1771
tptr = tuple_val(a1);
1588
if (arityval(*tptr) < 1) {
1589
erl_exit(1,"Internal error in ets:select_delete");
1772
ASSERT(arityval(*tptr) >= 1);
1593
if ((tb = db_get_table(p, tptr[1], DB_WRITE, LCK_WRITE)) == NULL) {
1594
/* This should be OK, the emulator handles errors in BIF's that aren't
1595
exported nowdays... */
1774
if ((tb = db_get_table(p, tptr[1], DB_WRITE, LCK_WRITE_REC)) == NULL) {
1596
1775
BIF_ERROR(p,BADARG);
1599
1778
cret = tb->common.meth->db_select_delete_continue(p,tb,a1,&ret);
1601
db_unlock(tb, LCK_WRITE);
1602
/* SMP fixme table may be deleted !!! */
1780
if(!DID_TRAP(p,ret) && ITERATION_SAFETY(p,tb) != ITER_SAFE) {
1781
unfix_table_locked(p, tb);
1784
db_unlock(tb, LCK_WRITE_REC);
1604
1786
switch (cret) {
1606
if(IS_HASH_TABLE(tb->common.status) && !DID_TRAP(p,ret) &&
1607
!ONLY_READER(p,tb)) {
1608
ets_safe_fixtable_2(p, tb->common.id, am_false);
1610
1788
ERTS_BIF_PREP_RET(result, ret);
1613
if(IS_HASH_TABLE(tb->common.status) && !ONLY_READER(p,tb)) {
1614
ets_safe_fixtable_2(p, tb->common.id, am_false);
1616
1791
ERTS_BIF_PREP_ERROR(result, p, BADARG);
1620
1794
erts_match_set_release_result(p);
1806
enum DbIterSafety safety;
1633
1808
CHECK_TABLES();
1635
* Make sure that the table exists.
1638
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL) {
1639
BIF_ERROR(BIF_P, BADARG);
1641
if(eq(BIF_ARG_2, ms_delete_all)){
1642
int nitems = tb->common.nitems;
1810
if(eq(BIF_ARG_2, ms_delete_all)) {
1812
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL) {
1813
BIF_ERROR(BIF_P, BADARG);
1815
nitems = erts_smp_atomic_read(&tb->common.nitems);
1643
1816
tb->common.meth->db_delete_all_objects(BIF_P, tb);
1644
1817
db_unlock(tb, LCK_WRITE);
1645
1818
BIF_RET(erts_make_integer(nitems,BIF_P));
1821
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE_REC)) == NULL) {
1822
BIF_ERROR(BIF_P, BADARG);
1824
safety = ITERATION_SAFETY(BIF_P,tb);
1825
if (safety == ITER_UNSAFE) {
1826
local_fix_table(tb);
1647
1828
cret = tb->common.meth->db_select_delete(BIF_P, tb, BIF_ARG_2, &ret);
1830
if (DID_TRAP(BIF_P,ret) && safety != ITER_SAFE) {
1831
fix_table_locked(BIF_P,tb);
1833
if (safety == ITER_UNSAFE) {
1834
local_unfix_table(tb);
1836
db_unlock(tb, LCK_WRITE_REC);
1649
1838
switch (cret) {
1651
if(IS_HASH_TABLE(tb->common.status) && DID_TRAP(BIF_P,ret) &&
1652
!ONLY_READER(BIF_P,tb)) {
1653
/* We will trap and as we're here this call wasn't a trap... */
1654
fix_table_locked(BIF_P, tb);
1656
db_unlock(tb, LCK_WRITE);
1657
1840
ERTS_BIF_PREP_RET(result, ret);
1659
1842
case DB_ERROR_SYSRES:
1660
db_unlock(tb, LCK_WRITE);
1661
1843
ERTS_BIF_PREP_ERROR(result, BIF_P, SYSTEM_LIMIT);
1664
db_unlock(tb, LCK_WRITE);
1665
1846
ERTS_BIF_PREP_ERROR(result, BIF_P, BADARG);
1784
1964
Sint chunk_size;
1965
enum DbIterSafety safety;
1786
1967
CHECK_TABLES();
1788
* Make sure that the table exists.
1791
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_WRITE)) == NULL) {
1792
BIF_ERROR(BIF_P, BADARG);
1795
1969
/* Chunk size strictly greater than 0 */
1796
1970
if (is_not_small(BIF_ARG_3) || (chunk_size = signed_val(BIF_ARG_3)) <= 0) {
1797
db_unlock(tb, LCK_WRITE);
1798
BIF_ERROR(BIF_P, BADARG);
1971
BIF_ERROR(BIF_P, BADARG);
1973
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
1974
BIF_ERROR(BIF_P, BADARG);
1976
safety = ITERATION_SAFETY(BIF_P,tb);
1977
if (safety == ITER_UNSAFE) {
1978
local_fix_table(tb);
1801
1980
cret = tb->common.meth->db_select_chunk(BIF_P, tb,
1802
1981
BIF_ARG_2, chunk_size,
1803
0 /* not reversed */, &ret);
1982
0 /* not reversed */,
1984
if (DID_TRAP(BIF_P,ret) && safety != ITER_SAFE) {
1985
fix_table_locked(BIF_P, tb);
1987
if (safety == ITER_UNSAFE) {
1988
local_unfix_table(tb);
1990
db_unlock(tb, LCK_READ);
1804
1992
switch (cret) {
1805
1993
case DB_ERROR_NONE:
1806
if(IS_HASH_TABLE(tb->common.status) && DID_TRAP(BIF_P,ret) &&
1807
!ONLY_WRITER(BIF_P,tb)) {
1808
/* We will trap and as we're here this call wasn't a trap... */
1809
fix_table_locked(BIF_P, tb);
1810
} /* Otherwise keep it as is */
1811
db_unlock(tb, LCK_WRITE);
1812
1994
ERTS_BIF_PREP_RET(result, ret);
1814
1996
case DB_ERROR_SYSRES:
1815
db_unlock(tb, LCK_WRITE);
1816
1997
ERTS_BIF_PREP_ERROR(result, BIF_P, SYSTEM_LIMIT);
1819
db_unlock(tb, LCK_WRITE);
1820
2000
ERTS_BIF_PREP_ERROR(result, BIF_P, BADARG);
1841
2021
tptr = tuple_val(a1);
1842
2022
ASSERT(arityval(*tptr) >= 1)
1844
if ((tb = db_get_table(p, tptr[1], DB_READ, LCK_WRITE)) == NULL) {
2024
if ((tb = db_get_table(p, tptr[1], DB_READ, LCK_READ)) == NULL) {
1845
2025
BIF_ERROR(p, BADARG);
1848
cret = tb->common.meth->db_select_continue(p, tb,a1,&ret);
2028
cret = tb->common.meth->db_select_continue(p, tb, a1,
2031
if (!DID_TRAP(p,ret) && ITERATION_SAFETY(p,tb) != ITER_SAFE) {
2032
unfix_table_locked(p, tb);
2034
db_unlock(tb, LCK_READ);
1850
2036
switch (cret) {
1851
2037
case DB_ERROR_NONE:
1852
if(IS_HASH_TABLE(tb->common.status) && !DID_TRAP(p,ret) &&
1853
!ONLY_WRITER(p,tb)) {
1854
/* We did trap, but no more... */
1855
unfix_table_locked(p, tb);
1856
} /* Otherwise keep it fixed */
1857
2038
ERTS_BIF_PREP_RET(result, ret);
1859
2040
case DB_ERROR_SYSRES:
1860
if(IS_HASH_TABLE(tb->common.status) && !ONLY_WRITER(p,tb)) {
1861
unfix_table_locked(p, tb);
1863
2041
ERTS_BIF_PREP_ERROR(result, p, SYSTEM_LIMIT);
1866
if(IS_HASH_TABLE(tb->common.status) && !ONLY_WRITER(p,tb)) {
1867
unfix_table_locked(p, tb);
1869
2044
ERTS_BIF_PREP_ERROR(result, p, BADARG);
1873
db_unlock(tb, LCK_WRITE);
1875
2048
erts_match_set_release_result(p);
1899
2073
BIF_ERROR(BIF_P, BADARG);
1901
2075
tptr = tuple_val(BIF_ARG_1);
1902
if (arityval(*tptr) < 1 ||
1903
(tb = db_get_table(BIF_P, tptr[1], DB_READ, LCK_WRITE)) == NULL) {
2076
if (arityval(*tptr) < 1 ||
2077
(tb = db_get_table(BIF_P, tptr[1], DB_READ, LCK_READ)) == NULL) {
1904
2078
BIF_ERROR(BIF_P, BADARG);
2081
safety = ITERATION_SAFETY(BIF_P,tb);
2082
if (safety == ITER_UNSAFE) {
2083
local_fix_table(tb);
1907
2086
cret = tb->common.meth->db_select_continue(BIF_P,tb,
1908
2087
BIF_ARG_1, &ret);
2089
if (DID_TRAP(BIF_P,ret) && safety != ITER_SAFE) {
2090
fix_table_locked(BIF_P, tb);
2092
if (safety == ITER_UNSAFE) {
2093
local_unfix_table(tb);
2095
db_unlock(tb, LCK_READ);
1910
2097
switch (cret) {
1911
2098
case DB_ERROR_NONE:
1912
if(IS_HASH_TABLE(tb->common.status) && DID_TRAP(BIF_P,ret) &&
1913
!ONLY_WRITER(BIF_P,tb)) {
1914
/* We will trap and as we're here this call wasn't a trap... */
1915
fix_table_locked(BIF_P, tb);
1916
} /* Otherwise keep it as is */
1917
2099
ERTS_BIF_PREP_RET(result, ret);
1919
2101
case DB_ERROR_SYSRES:
1936
2116
BIF_RETTYPE result;
2119
enum DbIterSafety safety;
1941
2122
CHECK_TABLES();
1943
2125
* Make sure that the table exists.
1946
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_WRITE)) == NULL) {
2128
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
1947
2129
BIF_ERROR(BIF_P, BADARG);
2131
safety = ITERATION_SAFETY(BIF_P,tb);
2132
if (safety == ITER_UNSAFE) {
2133
local_fix_table(tb);
1949
2136
cret = tb->common.meth->db_select(BIF_P, tb, BIF_ARG_2,
1952
/* SMP fixme table may be deleted !!! */
2139
if (DID_TRAP(BIF_P,ret) && safety != ITER_SAFE) {
2140
fix_table_locked(BIF_P, tb);
2142
if (safety == ITER_UNSAFE) {
2143
local_unfix_table(tb);
2145
db_unlock(tb, LCK_READ);
1953
2147
switch (cret) {
1954
2148
case DB_ERROR_NONE:
1955
if(IS_HASH_TABLE(tb->common.status) && DID_TRAP(BIF_P,ret) &&
1956
!ONLY_WRITER(BIF_P,tb)) {
1957
/* We will trap and as we're here this call wasn't a trap... */
1958
fix_table_locked(BIF_P, tb);
1959
} /* Otherwise keep it as is */
1960
2149
ERTS_BIF_PREP_RET(result, ret);
1962
2151
case DB_ERROR_SYSRES:
1988
2175
tptr = tuple_val(a1);
1989
2176
ASSERT(arityval(*tptr) >= 1)
1990
if ((tb = db_get_table(p, tptr[1], DB_READ, LCK_WRITE)) == NULL) {
2177
if ((tb = db_get_table(p, tptr[1], DB_READ, LCK_READ)) == NULL) {
1991
2178
BIF_ERROR(p, BADARG);
1994
2181
cret = tb->common.meth->db_select_count_continue(p, tb, a1, &ret);
2183
if (!DID_TRAP(p,ret) && ITERATION_SAFETY(p,tb) != ITER_SAFE) {
2184
unfix_table_locked(p, tb);
2186
db_unlock(tb, LCK_READ);
1996
2188
switch (cret) {
1997
2189
case DB_ERROR_NONE:
1998
if(IS_HASH_TABLE(tb->common.status) &&
2000
!ONLY_WRITER(p,tb)) {
2001
/* We did trap, but no more... */
2002
unfix_table_locked(p, tb);
2003
} /* Otherwise keep it fixed */
2004
2190
ERTS_BIF_PREP_RET(result, ret);
2006
2192
case DB_ERROR_SYSRES:
2007
if(IS_HASH_TABLE(tb->common.status) && !ONLY_WRITER(p,tb)) {
2008
unfix_table_locked(p, tb);
2010
2193
ERTS_BIF_PREP_ERROR(result, p, SYSTEM_LIMIT);
2013
if(IS_HASH_TABLE(tb->common.status) && !ONLY_WRITER(p,tb)) {
2014
unfix_table_locked(p, tb);
2016
2196
ERTS_BIF_PREP_ERROR(result, p, BADARG);
2020
db_unlock(tb, LCK_WRITE);
2021
2200
erts_match_set_release_result(p);
2035
2215
* Make sure that the table exists.
2038
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_WRITE)) == NULL) {
2218
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
2039
2219
BIF_ERROR(BIF_P, BADARG);
2221
safety = ITERATION_SAFETY(BIF_P,tb);
2222
if (safety == ITER_UNSAFE) {
2223
local_fix_table(tb);
2041
2225
cret = tb->common.meth->db_select_count(BIF_P,tb,BIF_ARG_2, &ret);
2227
if (DID_TRAP(BIF_P,ret) && safety != ITER_SAFE) {
2228
fix_table_locked(BIF_P, tb);
2230
if (safety == ITER_UNSAFE) {
2231
local_unfix_table(tb);
2233
db_unlock(tb, LCK_READ);
2043
2234
switch (cret) {
2044
2235
case DB_ERROR_NONE:
2045
if(IS_HASH_TABLE(tb->common.status) &&
2046
DID_TRAP(BIF_P,ret) &&
2047
!ONLY_WRITER(BIF_P,tb)) {
2048
/* We will trap and as we're here this call wasn't a trap... */
2049
fix_table_locked(BIF_P, tb);
2050
} /* Otherwise keep it as is */
2051
2236
ERTS_BIF_PREP_RET(result, ret);
2053
2238
case DB_ERROR_SYSRES:
2078
2263
* Make sure that the table exists.
2081
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_WRITE)) == NULL) {
2266
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
2082
2267
BIF_ERROR(BIF_P, BADARG);
2085
2270
/* Chunk size strictly greater than 0 */
2086
2271
if (is_not_small(BIF_ARG_3) || (chunk_size = signed_val(BIF_ARG_3)) <= 0) {
2087
db_unlock(tb, LCK_WRITE);
2272
db_unlock(tb, LCK_READ);
2088
2273
BIF_ERROR(BIF_P, BADARG);
2275
safety = ITERATION_SAFETY(BIF_P,tb);
2276
if (safety == ITER_UNSAFE) {
2277
local_fix_table(tb);
2091
2279
cret = tb->common.meth->db_select_chunk(BIF_P,tb,
2092
2280
BIF_ARG_2, chunk_size,
2093
2281
1 /* reversed */, &ret);
2282
if (DID_TRAP(BIF_P,ret) && safety != ITER_SAFE) {
2283
fix_table_locked(BIF_P, tb);
2285
if (safety == ITER_UNSAFE) {
2286
local_unfix_table(tb);
2288
db_unlock(tb, LCK_READ);
2094
2289
switch (cret) {
2095
2290
case DB_ERROR_NONE:
2096
if(IS_HASH_TABLE(tb->common.status) &&
2097
DID_TRAP(BIF_P,ret) &&
2098
!ONLY_WRITER(BIF_P,tb)) {
2099
/* We will trap and as we're here this call wasn't a trap... */
2100
fix_table_locked(BIF_P, tb);
2101
} /* Otherwise keep it as is */
2102
2291
ERTS_BIF_PREP_RET(result, ret);
2104
2293
case DB_ERROR_SYSRES:
2133
2319
* Make sure that the table exists.
2136
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_WRITE)) == NULL) {
2322
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
2137
2323
BIF_ERROR(BIF_P, BADARG);
2325
safety = ITERATION_SAFETY(BIF_P,tb);
2326
if (safety == ITER_UNSAFE) {
2327
local_fix_table(tb);
2140
2329
cret = tb->common.meth->db_select(BIF_P,tb,BIF_ARG_2,
2141
2330
1 /*reversed*/, &ret);
2332
if (DID_TRAP(BIF_P,ret) && safety != ITER_SAFE) {
2333
fix_table_locked(BIF_P, tb);
2335
if (safety == ITER_UNSAFE) {
2336
local_unfix_table(tb);
2338
db_unlock(tb, LCK_READ);
2143
2339
switch (cret) {
2144
2340
case DB_ERROR_NONE:
2145
if(IS_HASH_TABLE(tb->common.status) && DID_TRAP(BIF_P,ret) &&
2146
!ONLY_WRITER(BIF_P,tb)) {
2147
/* We will trap and as we're here this call wasn't a trap... */
2148
fix_table_locked(BIF_P, tb);
2149
} /* Otherwise keep it as is */
2150
2341
ERTS_BIF_PREP_RET(result, ret);
2152
2343
case DB_ERROR_SYSRES:
2208
2395
BIF_RETTYPE ets_info_1(BIF_ALIST_1)
2210
2397
static Eterm fields[] = {am_protection, am_keypos, am_type, am_named_table,
2211
am_node, am_size, am_name, am_owner, am_memory};
2398
am_node, am_size, am_name, am_heir, am_owner, am_memory};
2212
2399
Eterm results[sizeof(fields)/sizeof(Eterm)];
2404
/*Process* rp = NULL;*/
2218
2407
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ)) == NULL) {
2219
2408
if (is_atom(BIF_ARG_1) || is_small(BIF_ARG_1)) {
2222
2411
BIF_ERROR(BIF_P, BADARG);
2414
owner = tb->common.owner;
2416
/* If/when we implement lockless private tables:
2417
if ((tb->common.status & DB_PRIVATE) && owner != BIF_P->id) {
2418
db_unlock(tb, LCK_READ);
2419
rp = erts_pid2proc_not_running(BIF_P, ERTS_PROC_LOCK_MAIN,
2420
owner, ERTS_PROC_LOCK_MAIN);
2422
BIF_RET(am_undefined);
2424
if (rp == ERTS_PROC_LOCK_BUSY) {
2425
ERTS_BIF_YIELD1(bif_export[BIF_ets_info_1], BIF_P, BIF_ARG_1);
2427
if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ)) == NULL
2428
|| tb->common.owner != owner) {
2430
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);
2431
if (is_atom(BIF_ARG_1) || is_small(BIF_ARG_1)) {
2432
BIF_RET(am_undefined);
2434
BIF_ERROR(BIF_P, BADARG);
2224
2437
for (i = 0; i < sizeof(fields)/sizeof(Eterm); i++) {
2225
2438
results[i] = table_info(BIF_P, tb, fields[i]);
2226
2439
ASSERT(is_value(results[i]));
2228
2441
db_unlock(tb, LCK_READ);
2443
/*if (rp != NULL && rp != BIF_P)
2444
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);*/
2230
2446
hp = HAlloc(BIF_P, 5*sizeof(fields)/sizeof(Eterm));
2232
2448
for (i = 0; i < sizeof(fields)/sizeof(Eterm); i++) {
2423
2639
meta_pid_to_tab->common.id = NIL;
2424
2640
meta_pid_to_tab->common.the_name = am_true;
2425
meta_pid_to_tab->common.status = (DB_NORMAL | DB_BAG | DB_LHASH |
2641
meta_pid_to_tab->common.status = (DB_NORMAL | DB_BAG | DB_PUBLIC | DB_FINE_LOCKED);
2427
2642
#ifdef ERTS_SMP
2428
2643
meta_pid_to_tab->common.type
2429
2644
= meta_pid_to_tab->common.status & ERTS_ETS_TABLE_TYPES;
2430
2645
/* Note, 'type' is *read only* from now on... */
2646
meta_pid_to_tab->common.is_thread_safe = 0;
2432
2648
meta_pid_to_tab->common.keypos = 1;
2433
2649
meta_pid_to_tab->common.owner = NIL;
2434
meta_pid_to_tab->common.nitems = 0;
2650
erts_smp_atomic_init(&meta_pid_to_tab->common.nitems, 0);
2435
2651
meta_pid_to_tab->common.slot = -1;
2436
2652
meta_pid_to_tab->common.meth = &db_hash;
2438
db_init_lock(meta_pid_to_tab, "meta_pid_to_tab");
2654
erts_refc_init(&meta_pid_to_tab->common.ref, 1);
2655
erts_refc_init(&meta_pid_to_tab->common.fixref, 0);
2656
/* Neither rwlock or fixlock used
2657
db_init_lock(meta_pid_to_tab, "meta_pid_to_tab", "meta_pid_to_tab_FIX");*/
2440
2659
if (db_create_hash(NULL, meta_pid_to_tab) != DB_ERROR_NONE) {
2441
2660
erl_exit(1,"Unable to create ets metadata tables.");
2452
2671
meta_pid_to_fixed_tab->common.id = NIL;
2453
2672
meta_pid_to_fixed_tab->common.the_name = am_true;
2454
meta_pid_to_fixed_tab->common.status = (DB_NORMAL | DB_BAG | DB_LHASH |
2673
meta_pid_to_fixed_tab->common.status = (DB_NORMAL | DB_BAG | DB_PUBLIC | DB_FINE_LOCKED);
2456
2674
#ifdef ERTS_SMP
2457
2675
meta_pid_to_fixed_tab->common.type
2458
2676
= meta_pid_to_fixed_tab->common.status & ERTS_ETS_TABLE_TYPES;
2459
2677
/* Note, 'type' is *read only* from now on... */
2678
meta_pid_to_fixed_tab->common.is_thread_safe = 0;
2461
2680
meta_pid_to_fixed_tab->common.keypos = 1;
2462
2681
meta_pid_to_fixed_tab->common.owner = NIL;
2463
meta_pid_to_fixed_tab->common.nitems = 0;
2682
erts_smp_atomic_init(&meta_pid_to_fixed_tab->common.nitems, 0);
2464
2683
meta_pid_to_fixed_tab->common.slot = -1;
2465
2684
meta_pid_to_fixed_tab->common.meth = &db_hash;
2467
db_init_lock(meta_pid_to_fixed_tab, "meta_pid_to_fixed_tab");
2686
erts_refc_init(&meta_pid_to_fixed_tab->common.ref, 1);
2687
erts_refc_init(&meta_pid_to_fixed_tab->common.fixref, 0);
2688
/* Neither rwlock or fixlock used
2689
db_init_lock(meta_pid_to_fixed_tab, "meta_pid_to_fixed_tab", "meta_pid_to_fixed_tab_FIX");*/
2469
2691
if (db_create_hash(NULL, meta_pid_to_fixed_tab) != DB_ERROR_NONE) {
2470
2692
erl_exit(1,"Unable to create ets metadata tables.");
2595
2817
state->slots.arr[ix]);
2597
db_unlock(meta_pid_to_fixed_tab, LCK_WRITE);
2819
db_meta_unlock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
2598
2820
state->slots.clean_ix = state->slots.ix;
2824
/* In: Table LCK_WRITE
2825
** Return TRUE : ok, table not mine and NOT locked anymore.
2826
** Return FALSE: failed, table still mine (LCK_WRITE)
2828
static int give_away_to_heir(Process* p, DbTable* tb)
2831
ErtsProcLocks to_locks = ERTS_PROC_LOCK_MAIN;
2836
ASSERT(tb->common.owner == p->id);
2837
ASSERT(is_internal_pid(tb->common.heir));
2838
ASSERT(tb->common.heir != p->id);
2840
to_pid = tb->common.heir;
2841
to_proc = erts_pid2proc_opt(p, ERTS_PROC_LOCK_MAIN,
2843
ERTS_P2P_FLG_TRY_LOCK);
2844
if (to_proc == ERTS_PROC_LOCK_BUSY) {
2845
db_ref(tb); /* while unlocked */
2846
db_unlock(tb,LCK_WRITE);
2847
to_proc = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
2849
db_lock(tb,LCK_WRITE);
2853
if (tb->common.owner != p->id) {
2854
if (to_proc != NULL ) {
2855
erts_smp_proc_unlock(to_proc, to_locks);
2857
db_unlock(tb,LCK_WRITE);
2858
return !0; /* ok, someone already gave my table away */
2860
if (tb->common.heir != to_pid) { /* someone changed the heir */
2861
if (to_proc != NULL ) {
2862
erts_smp_proc_unlock(to_proc, to_locks);
2864
if (to_pid == p->id || to_pid == am_none) {
2865
return 0; /* no real heir, table still mine */
2870
if (to_proc == NULL) {
2871
return 0; /* heir not alive, table still mine */
2873
if (erts_cmp_timeval(&to_proc->started, &tb->common.heir_started) != 0) {
2874
erts_smp_proc_unlock(to_proc, to_locks);
2875
return 0; /* heir dead and pid reused, table still mine */
2877
db_meta_lock(meta_pid_to_tab, LCK_WRITE_REC);
2878
db_erase_bag_exact2(meta_pid_to_tab, tb->common.owner,
2879
make_small(tb->common.slot));
2881
to_proc->flags |= F_USING_DB;
2882
tb->common.owner = to_pid;
2884
db_put_hash(meta_pid_to_tab,
2885
TUPLE2(buf,to_pid,make_small(tb->common.slot)),
2887
db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC);
2889
db_unlock(tb,LCK_WRITE);
2890
heir_data = tb->common.heir_data;
2891
if (!is_immed(heir_data)) {
2892
Eterm* tpv = DBTERM_BUF((DbTerm*)heir_data); /* tuple_val */
2893
ASSERT(arityval(*tpv) == 1);
2896
erts_send_message(p, to_proc, &to_locks,
2897
TUPLE4(buf, am_ETS_TRANSFER, tb->common.id, p->id, heir_data),
2899
erts_smp_proc_unlock(to_proc, to_locks);
2603
2904
* erts_db_process_exiting() is called when a process terminates.
2604
2905
* It returns 0 when completely done, and !0 when it wants to
2742
3049
meta_main_tab_unlock(ix);
2747
db_lock_take_over_ref(tb, LCK_WRITE);
3054
db_lock_take_over_ref(tb, LCK_WRITE_REC);
3056
erts_smp_mtx_lock(&tb->common.fixlock);
2750
for (pp = &(tb->common.fixations);
2752
pp = &((*pp)->next)) {
3060
for (pp = &tb->common.fixations; *pp != NULL;
3061
pp = &(*pp)->next) {
2753
3062
if ((*pp)->pid == pid) {
2754
DbFixation *fix = *pp;
3063
DbFixation* fix = *pp;
3064
erts_refc_add(&tb->common.fixref,-fix->counter,0);
2756
3066
erts_db_free(ERTS_ALC_T_DB_FIXATION,
2759
sizeof(DbFixation));
3067
tb, fix, sizeof(DbFixation));
2760
3068
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation));
2764
if (tb->common.fixations == NULL) {
2765
if (IS_HASH_TABLE(tb->common.status)) {
2766
db_unfix_table_hash(&(tb->hash));
2769
tb->common.status &= ~DB_FIXED;
3073
erts_smp_mtx_unlock(&tb->common.fixlock);
3075
if (!IS_FIXED(tb) && IS_HASH_TABLE(tb->common.status)) {
3076
db_unfix_table_hash(&(tb->hash));
2771
db_unlock(tb, LCK_WRITE);
3079
db_unlock(tb, LCK_WRITE_REC);
2772
3080
BUMP_REDS(c_p, reds);
2774
3082
state->slots.ix++;
2822
/* SMP note: table must be WRITE locked */
3130
/* SMP note: table only need to be LCK_READ locked */
2823
3131
static void fix_table_locked(Process* p, DbTable* tb)
2825
3133
DbFixation *fix;
2827
3134
Eterm meta_tuple[3];
2829
if (!(tb->common.status & DB_FIXED)) {
2830
tb->common.status |= DB_FIXED;
3137
erts_smp_mtx_lock(&tb->common.fixlock);
3139
erts_refc_inc(&tb->common.fixref,1);
3140
fix = tb->common.fixations;
2831
3142
get_now(&(tb->common.megasec),
2832
3143
&(tb->common.sec),
2833
3144
&(tb->common.microsec));
2835
for (fix = tb->common.fixations; fix != NULL; fix = fix->next) {
2836
if (fix->pid == p->id) {
3147
for (; fix != NULL; fix = fix->next) {
3148
if (fix->pid == p->id) {
3151
erts_smp_mtx_unlock(&tb->common.fixlock);
2842
fix = (DbFixation *) erts_db_alloc(ERTS_ALC_T_DB_FIXATION,
2843
tb, sizeof(DbFixation));
2844
ERTS_ETS_MISC_MEM_ADD(sizeof(DbFixation));
2847
fix->next = tb->common.fixations;
2848
tb->common.fixations = fix;
2849
p->flags |= F_USING_DB;
2850
db_lock(meta_pid_to_fixed_tab, LCK_WRITE);
2851
if (db_put_hash(NULL,meta_pid_to_fixed_tab,
2854
make_small(tb->common.slot)),
2857
erl_exit(1,"Could not insert ets metadata"
2858
" in safe_fixtable.");
2860
db_unlock(meta_pid_to_fixed_tab, LCK_WRITE);
3157
fix = (DbFixation *) erts_db_alloc(ERTS_ALC_T_DB_FIXATION,
3158
tb, sizeof(DbFixation));
3159
ERTS_ETS_MISC_MEM_ADD(sizeof(DbFixation));
3162
fix->next = tb->common.fixations;
3163
tb->common.fixations = fix;
3165
erts_smp_mtx_unlock(&tb->common.fixlock);
3167
p->flags |= F_USING_DB;
3168
db_meta_lock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
3169
if (db_put_hash(meta_pid_to_fixed_tab,
3170
TUPLE2(meta_tuple, p->id, make_small(tb->common.slot)),
3171
0) != DB_ERROR_NONE) {
3172
erl_exit(1,"Could not insert ets metadata in safe_fixtable.");
3174
db_meta_unlock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
2864
/* SMP note: table must be WRITE locked */
3177
/* SMP note: hash table need to be at least LCK_WRITE_REC locked
3178
tree need only to be LCK_READ */
2865
3179
static void unfix_table_locked(Process* p, DbTable* tb)
2870
for (pp = &(tb->common.fixations); *pp != NULL; pp = &((*pp)->next)) {
3184
erts_smp_mtx_lock(&tb->common.fixlock);
3186
for (pp = &tb->common.fixations; *pp != NULL; pp = &(*pp)->next) {
2871
3187
if ((*pp)->pid == p->id) {
2873
ASSERT((*pp)->counter >= 0);
2874
if ((*pp)->counter == 0) {
2877
db_lock(meta_pid_to_fixed_tab, LCK_WRITE);
2878
db_erase_bag_exact2(meta_pid_to_fixed_tab,
2880
make_small(tb->common.slot));
2881
db_unlock(meta_pid_to_fixed_tab, LCK_WRITE);
2882
erts_db_free(ERTS_ALC_T_DB_FIXATION,
2883
tb, (void *) fix, sizeof(DbFixation));
2884
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation));
3188
DbFixation* fix = *pp;
3189
erts_refc_dec(&tb->common.fixref,0);
3191
ASSERT(fix->counter >= 0);
3192
if (fix->counter > 0) {
3197
erts_smp_mtx_unlock(&tb->common.fixlock);
3199
db_meta_lock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
3200
db_erase_bag_exact2(meta_pid_to_fixed_tab,
3201
p->id, make_small(tb->common.slot));
3202
db_meta_unlock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
3203
erts_db_free(ERTS_ALC_T_DB_FIXATION,
3204
tb, (void *) fix, sizeof(DbFixation));
3205
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation));
2889
if (tb->common.fixations == NULL) {
2890
if (IS_HASH_TABLE(tb->common.status)) {
2891
db_unfix_table_hash(&(tb->hash));
2893
tb->common.status &= ~DB_FIXED;
3210
erts_smp_mtx_unlock(&tb->common.fixlock);
3214
if (!IS_FIXED(tb) && IS_HASH_TABLE(tb->common.status)) {
3215
db_unfix_table_hash(&(tb->hash));
2897
/* Assume that tb is locked (write) */
3219
/* Assume that tb is WRITE locked */
2898
3220
static void free_fixations_locked(DbTable *tb)
2900
3222
DbFixation *fix;
2903
3225
fix = tb->common.fixations;
2904
3226
while (fix != NULL) {
2905
3227
next_fix = fix->next;
2906
db_lock(meta_pid_to_fixed_tab, LCK_WRITE);
3228
db_meta_lock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
2907
3229
db_erase_bag_exact2(meta_pid_to_fixed_tab,
2909
3231
make_small(tb->common.slot));
2910
db_unlock(meta_pid_to_fixed_tab, LCK_WRITE);
3232
db_meta_unlock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
2911
3233
erts_db_free(ERTS_ALC_T_DB_FIXATION,
2912
3234
tb, (void *) fix, sizeof(DbFixation));
2913
3235
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation));
2917
3239
tb->common.fixations = NULL;
3242
static void set_heir(Process* me, DbTable* tb, Eterm heir, Eterm heir_data)
3244
tb->common.heir = heir;
3245
if (heir == am_none) {
3248
if (heir == me->id) {
3249
tb->common.heir_started = me->started;
3252
Process* heir_proc= erts_pid2proc_opt(me, ERTS_PROC_LOCK_MAIN, heir,
3253
0, ERTS_P2P_FLG_SMP_INC_REFC);
3254
if (heir_proc != NULL) {
3255
tb->common.heir_started = heir_proc->started;
3256
erts_smp_proc_dec_refc(heir_proc);
3258
tb->common.heir = am_none;
3262
if (!is_immed(heir_data)) {
3264
/* Make a dummy 1-tuple around data to use db_get_term() */
3265
heir_data = (Eterm) db_get_term(&tb->common, NULL, 0,
3266
TUPLE1(tmp,heir_data));
3267
ASSERT(!is_immed(heir_data));
3269
tb->common.heir_data = heir_data;
3272
static void free_heir_data(DbTable* tb)
3274
if (tb->common.heir != am_none && !is_immed(tb->common.heir_data)) {
3275
DbTerm* p = (DbTerm*) tb->common.heir_data;
3276
db_free_term_data(p);
3277
erts_db_free(ERTS_ALC_T_DB_TERM, tb, (void *)p,
3278
sizeof(DbTerm) + (p->size-1)*sizeof(Eterm));
3281
tb->common.heir_data = am_undefined;
2921
3285
static BIF_RETTYPE ets_delete_trap(Process *p, Eterm cont)
3036
3402
print_table(ERTS_PRINT_STDOUT, NULL, 1, tb);
3038
3404
} else if (What == am_atom_put("fixed",5)) {
3039
if (tb->common.status & DB_FIXED)
3042
3408
ret = am_false;
3043
3409
} else if (What == am_atom_put("kept_objects",12)) {
3044
ret = make_small(tb->common.kept_items);
3045
} else if (What == am_atom_put("safe_fixed",10)) {
3046
if (tb->common.fixations != NULL) {
3410
ret = make_small(IS_HASH_TABLE(tb->common.status)
3411
? db_kept_items_hash(&tb->hash) : 0);
3412
} else if (What == am_atom_put("safe_fixed",10)) {
3414
erts_smp_mtx_lock(&tb->common.fixlock);
3049
3419
Eterm tpl, lst;