diff options
Diffstat (limited to 'erts/emulator/beam/erl_db.c')
-rw-r--r-- | erts/emulator/beam/erl_db.c | 76 |
1 files changed, 42 insertions, 34 deletions
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 9c597afabf..2f188b5391 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -356,9 +356,9 @@ static void fix_table_locked(Process* p, DbTable* tb); static void unfix_table_locked(Process* p, DbTable* tb, db_lock_kind_t* kind); static void set_heir(Process* me, DbTable* tb, Eterm heir, UWord heir_data); static void free_heir_data(DbTable*); -static void free_fixations_locked(Process* p, DbTable *tb); +static SWord free_fixations_locked(Process* p, DbTable *tb); -static int free_table_cont(Process *p, DbTable *tb); +static SWord free_table_continue(Process *p, DbTable *tb, SWord reds); static void print_table(fmtfn_t to, void *to_arg, int show, DbTable* tb); static BIF_RETTYPE ets_select_delete_1(BIF_ALIST_1); static BIF_RETTYPE ets_select_count_1(BIF_ALIST_1); @@ -393,8 +393,6 @@ free_dbtable(void *vtb) erts_smp_atomic_read_nob(&tb->common.memory_size)-sizeof(DbTable), tb->common.fixations); } - erts_fprintf(stderr, "ets: free_dbtable(%T) deleted!!!\r\n", - tb->common.id); #endif #ifdef ERTS_SMP erts_smp_rwmtx_destroy(&tb->common.rwlock); @@ -1904,7 +1902,8 @@ BIF_RETTYPE ets_lookup_element_3(BIF_ALIST_3) */ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) { - int trap; + SWord initial_reds = ERTS_BIF_REDS_LEFT(BIF_P); + SWord reds = initial_reds; DbTable* tb; #ifdef HARDDEBUG @@ -1958,11 +1957,10 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) free_heir_data(tb); tb->common.heir = am_none; - free_fixations_locked(BIF_P, tb); + reds -= free_fixations_locked(BIF_P, tb); db_unlock(tb, LCK_WRITE); - trap = free_table_cont(BIF_P, tb); - if (trap) { + if (free_table_continue(BIF_P, tb, reds) < 0) { /* * Package the DbTable* pointer into a bignum so that it can be safely * passed through a trap. We used to pass the DbTable* pointer directly @@ -1972,9 +1970,11 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) Eterm *hp = HAlloc(BIF_P, 2); hp[0] = make_pos_bignum_header(1); hp[1] = (Eterm) tb; + BUMP_ALL_REDS(BIF_P); BIF_TRAP1(&ets_delete_continue_exp, BIF_P, make_big(hp)); } else { + BUMP_REDS(BIF_P, (initial_reds - reds)); BIF_RET(am_true); } } @@ -3471,9 +3471,10 @@ send_ets_transfer_message(Process *c_p, Process *proc, /* Auto-release fixation from exiting process */ -static void proc_cleanup_fixed_table(Process* p, DbFixation* fix) +static SWord proc_cleanup_fixed_table(Process* p, DbFixation* fix) { DbTable* tb = btid2tab(fix->tabs.btid); + SWord work = 0; ASSERT(fix->procs.p == p); (void)p; if (tb) { @@ -3496,7 +3497,7 @@ static void proc_cleanup_fixed_table(Process* p, DbFixation* fix) erts_smp_mtx_unlock(&tb->common.fixlock); #endif if (!IS_FIXED(tb) && IS_HASH_TABLE(tb->common.status)) { - db_unfix_table_hash(&(tb->hash)); + work += db_unfix_table_hash(&(tb->hash)); } ASSERT(sizeof(DbFixation) == ERTS_ALC_DBG_BLK_SZ(fix)); @@ -3516,6 +3517,9 @@ static void proc_cleanup_fixed_table(Process* p, DbFixation* fix) } erts_free(ERTS_ALC_T_DB_FIXATION, fix); ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation)); + ++work; + + return work; } @@ -3543,6 +3547,8 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks) CleanupState *state = (CleanupState *) c_p->u.terminate; Eterm pid = c_p->common.id; CleanupState default_state; + SWord initial_reds = ERTS_BIF_REDS_LEFT(c_p); + SWord reds = initial_reds; if (!state) { state = &default_state; @@ -3588,17 +3594,17 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks) remove_named_tab(tb, 0); free_heir_data(tb); - free_fixations_locked(c_p, tb); + reds -= free_fixations_locked(c_p, tb); db_unlock(tb, LCK_WRITE); state->op = FREE_OWNED_TABLE; - /* fall through */ + break; } case FREE_OWNED_TABLE: - if (free_table_cont(c_p, state->tb)) + reds = free_table_continue(c_p, state->tb, reds); + if (reds < 0) goto yield; state->op = GET_OWNED_TABLE; - break; case UNFIX_TABLES: { @@ -3612,20 +3618,21 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks) if (state != &default_state) erts_free(ERTS_ALC_T_DB_PROC_CLEANUP, state); c_p->u.terminate = NULL; + + BUMP_REDS(c_p, (initial_reds - reds)); return 0; } fixed_tabs_delete(c_p, fix); - proc_cleanup_fixed_table(c_p, fix); + reds -= proc_cleanup_fixed_table(c_p, fix); - BUMP_REDS(c_p, 10); break; } default: ERTS_DB_INTERNAL_ERROR("Bad internal state"); } - } while (ERTS_BIF_REDS_LEFT(c_p) > 0); + } while (reds > 0); yield: @@ -3740,6 +3747,7 @@ struct free_fixations_ctx { Process* p; DbTable* tb; + SWord cnt; }; static void free_fixations_op(DbFixation* fix, void* vctx) @@ -3785,6 +3793,7 @@ static void free_fixations_op(DbFixation* fix, void* vctx) ctx->tb, (void *) fix, sizeof(DbFixation)); ERTS_ETS_MISC_MEM_ADD(-sizeof(DbFixation)); } + ctx->cnt++; } #ifdef ERTS_SMP @@ -3802,7 +3811,7 @@ int erts_db_execute_free_fixation(Process* p, DbFixation* fix) } #endif -static void free_fixations_locked(Process* p, DbTable *tb) +static SWord free_fixations_locked(Process* p, DbTable *tb) { struct free_fixations_ctx ctx; @@ -3810,9 +3819,11 @@ static void free_fixations_locked(Process* p, DbTable *tb) ctx.p = p; ctx.tb = tb; + ctx.cnt = 0; fixing_procs_rbt_foreach_destroy(&tb->common.fixing_procs, free_fixations_op, &ctx); tb->common.fixing_procs = NULL; + return ctx.cnt; } static void set_heir(Process* me, DbTable* tb, Eterm heir, UWord heir_data) @@ -3876,42 +3887,40 @@ static void free_heir_data(DbTable* tb) static BIF_RETTYPE ets_delete_trap(BIF_ALIST_1) { - Process *p = BIF_P; + SWord initial_reds = ERTS_BIF_REDS_LEFT(BIF_P); + SWord reds = initial_reds; Eterm cont = BIF_ARG_1; - int trap; Eterm* ptr = big_val(cont); DbTable *tb = *((DbTable **) (UWord) (ptr + 1)); ASSERT(*ptr == make_pos_bignum_header(1)); - trap = free_table_cont(p, tb); - - if (trap) { - BIF_TRAP1(&ets_delete_continue_exp, p, cont); + if (free_table_continue(BIF_P, tb, reds) < 0) { + BUMP_ALL_REDS(BIF_P); + BIF_TRAP1(&ets_delete_continue_exp, BIF_P, cont); } else { + BUMP_REDS(BIF_P, (initial_reds - reds)); BIF_RET(am_true); } } /* - * free_table_cont() returns 0 when done and !0 when more work is needed. + * free_table_continue() returns reductions left + * done if >= 0 + * yield if < 0 */ -static int free_table_cont(Process *p, DbTable *tb) +static SWord free_table_continue(Process *p, DbTable *tb, SWord reds) { - Eterm result; - - result = tb->common.meth->db_free_table_continue(tb); + reds = tb->common.meth->db_free_table_continue(tb, reds); - if (result == 0) { + if (reds < 0) { #ifdef HARDDEBUG erts_fprintf(stderr,"ets: free_table_cont %T (continue begin)\r\n", tb->common.id); #endif /* More work to be done. Let other processes work and call us again. */ - BUMP_ALL_REDS(p); - return !0; } else { #ifdef HARDDEBUG @@ -3921,9 +3930,8 @@ static int free_table_cont(Process *p, DbTable *tb) /* Completely done - we will not get called again. */ delete_owned_table(p, tb); table_dec_refc(tb, 0); - BUMP_REDS(p, 100); - return 0; } + return reds; } struct fixing_procs_info_ctx |