/* * %CopyrightBegin% * * Copyright Ericsson AB 1996-2018. 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% */ /* * This file now contains only the definitions needed for the * meta table. * */ #ifndef ERTS_DB_SCHED_SPEC_TYPES__ #define ERTS_DB_SCHED_SPEC_TYPES__ union db_table; typedef union db_table DbTable; typedef struct ErtsEtsAllReq_ ErtsEtsAllReq; typedef struct { ErtsEtsAllReq *next; ErtsEtsAllReq *prev; } ErtsEtsAllReqList; typedef struct { ErtsEtsAllReq *ongoing; ErlHeapFragment *hfrag; DbTable *tab; ErtsEtsAllReq *queue; } ErtsEtsAllYieldData; typedef struct { erts_atomic_t count; DbTable *clist; } ErtsEtsTables; #endif /* ERTS_DB_SCHED_SPEC_TYPES__ */ #ifndef ERTS_ONLY_SCHED_SPEC_ETS_DATA #ifndef ERL_DB_H__ #define ERL_DB_H__ #include "sys.h" #undef ERL_THR_PROGRESS_TSD_TYPE_ONLY #define ERL_THR_PROGRESS_TSD_TYPE_ONLY #include "erl_thr_progress.h" #undef ERL_THR_PROGRESS_TSD_TYPE_ONLY #include "bif.h" #include "erl_db_util.h" /* Flags */ #include "erl_db_hash.h" /* DbTableHash */ #include "erl_db_tree.h" /* DbTableTree */ #include "erl_db_catree.h" /* DbTableCATree */ /*TT*/ Uint erts_get_ets_misc_mem_size(void); Uint erts_ets_table_count(void); typedef struct { DbTableCommon common; ErtsThrPrgrLaterOp data; } DbTableRelease; struct ErtsSchedulerData_; int erts_handle_yielded_ets_all_request(struct ErtsSchedulerData_ *esdp, ErtsEtsAllYieldData *eadp); void erts_ets_sched_spec_data_init(struct ErtsSchedulerData_ *esdp); /* * So, the structure for a database table, NB this is only * interesting in db.c. */ union db_table { DbTableCommon common; /* Any type of db table */ DbTableHash hash; /* Linear hash array specific data */ DbTableTree tree; /* AVL tree specific data */ DbTableCATree catree; /* CA tree specific data */ DbTableRelease release; /*TT*/ }; #define DB_DEF_MAX_TABS 8192 /* Superseeded by environment variable "ERL_MAX_ETS_TABLES" */ #define ERL_MAX_ETS_TABLES_ENV "ERL_MAX_ETS_TABLES" typedef enum { ERTS_DB_SPNCNT_NONE, ERTS_DB_SPNCNT_VERY_LOW, ERTS_DB_SPNCNT_LOW, ERTS_DB_SPNCNT_NORMAL, ERTS_DB_SPNCNT_HIGH, ERTS_DB_SPNCNT_VERY_HIGH, ERTS_DB_SPNCNT_EXTREMELY_HIGH } ErtsDbSpinCount; void init_db(ErtsDbSpinCount); int erts_db_process_exiting(Process *, ErtsProcLocks, void **); int erts_db_execute_free_fixation(Process*, DbFixation*); void db_info(fmtfn_t, void *, int); void erts_db_foreach_table(void (*)(DbTable *, void *), void *, int); void erts_db_foreach_offheap(DbTable *, void (*func)(ErlOffHeap *, void *), void *); void erts_db_foreach_thr_prgr_offheap(void (*func)(ErlOffHeap *, void *), void *); extern int erts_ets_rwmtx_spin_count; extern int user_requested_db_max_tabs; /* set in erl_init */ extern int erts_ets_realloc_always_moves; /* set in erl_init */ extern int erts_ets_always_compress; /* set in erl_init */ extern Export ets_select_delete_continue_exp; extern Export ets_select_count_continue_exp; extern Export ets_select_replace_continue_exp; extern Export ets_select_continue_exp; extern erts_atomic_t erts_ets_misc_mem_size; Eterm erts_ets_colliding_names(Process*, Eterm name, Uint cnt); int erts_ets_force_split(Eterm tid, int on); int erts_ets_debug_random_split_join(Eterm tid, int on); Uint erts_db_get_max_tabs(void); Eterm erts_db_make_tid(Process *c_p, DbTableCommon *tb); #ifdef ERTS_ENABLE_LOCK_COUNT void erts_lcnt_enable_db_lock_count(DbTable *tb, int enable); void erts_lcnt_update_db_locks(int enable); #endif #ifdef ETS_DBG_FORCE_TRAP extern erts_aint_t erts_ets_dbg_force_trap; #endif #endif /* ERL_DB_H__ */ #if defined(ERTS_WANT_DB_INTERNAL__) && !defined(ERTS_HAVE_DB_INTERNAL__) #define ERTS_HAVE_DB_INTERNAL__ #include "erl_alloc.h" /* * _fnf : Failure Not Fatal (same as for erts_alloc/erts_realloc/erts_free) * _nt : No Table (i.e. memory not associated with a specific table) */ #define ERTS_DB_ALC_MEM_UPDATE_(TAB, FREE_SZ, ALLOC_SZ) \ do { \ erts_aint_t sz__ = (((erts_aint_t) (ALLOC_SZ)) \ - ((erts_aint_t) (FREE_SZ))); \ ASSERT((TAB)); \ erts_flxctr_add(&(TAB)->common.counters, \ ERTS_DB_TABLE_MEM_COUNTER_ID, \ sz__); \ } while (0) #define ERTS_ETS_MISC_MEM_ADD(SZ) \ erts_atomic_add_nob(&erts_ets_misc_mem_size, (SZ)); ERTS_GLB_INLINE void *erts_db_alloc(ErtsAlcType_t type, DbTable *tab, Uint size); ERTS_GLB_INLINE void *erts_db_alloc_fnf(ErtsAlcType_t type, DbTable *tab, Uint size); ERTS_GLB_INLINE void *erts_db_alloc_nt(ErtsAlcType_t type, Uint size); ERTS_GLB_INLINE void *erts_db_alloc_fnf_nt(ErtsAlcType_t type, Uint size); #if ERTS_GLB_INLINE_INCL_FUNC_DEF ERTS_GLB_INLINE void * erts_db_alloc(ErtsAlcType_t type, DbTable *tab, Uint size) { void *res = erts_alloc(type, size); ERTS_DB_ALC_MEM_UPDATE_(tab, 0, size); return res; } ERTS_GLB_INLINE void * erts_db_alloc_fnf(ErtsAlcType_t type, DbTable *tab, Uint size) { void *res = erts_alloc_fnf(type, size); if (!res) return NULL; ERTS_DB_ALC_MEM_UPDATE_(tab, 0, size); return res; } ERTS_GLB_INLINE void * erts_db_alloc_nt(ErtsAlcType_t type, Uint size) { void *res = erts_alloc(type, size); return res; } ERTS_GLB_INLINE void * erts_db_alloc_fnf_nt(ErtsAlcType_t type, Uint size) { void *res = erts_alloc_fnf(type, size); if (!res) return NULL; return res; } #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ ERTS_GLB_INLINE void *erts_db_realloc(ErtsAlcType_t type, DbTable *tab, void *ptr, Uint old_size, Uint size); ERTS_GLB_INLINE void *erts_db_realloc_fnf(ErtsAlcType_t type, DbTable *tab, void *ptr, Uint old_size, Uint size); ERTS_GLB_INLINE void *erts_db_realloc_nt(ErtsAlcType_t type, void *ptr, Uint old_size, Uint size); ERTS_GLB_INLINE void *erts_db_realloc_fnf_nt(ErtsAlcType_t type, void *ptr, Uint old_size, Uint size); #if ERTS_GLB_INLINE_INCL_FUNC_DEF ERTS_GLB_INLINE void * erts_db_realloc(ErtsAlcType_t type, DbTable *tab, void *ptr, Uint old_size, Uint size) { void *res; ASSERT(!ptr || old_size == ERTS_ALC_DBG_BLK_SZ(ptr)); res = erts_realloc(type, ptr, size); ERTS_DB_ALC_MEM_UPDATE_(tab, old_size, size); return res; } ERTS_GLB_INLINE void * erts_db_realloc_fnf(ErtsAlcType_t type, DbTable *tab, void *ptr, Uint old_size, Uint size) { void *res; ASSERT(!ptr || old_size == ERTS_ALC_DBG_BLK_SZ(ptr)); res = erts_realloc_fnf(type, ptr, size); if (!res) return NULL; ERTS_DB_ALC_MEM_UPDATE_(tab, old_size, size); return res; } ERTS_GLB_INLINE void * erts_db_realloc_nt(ErtsAlcType_t type, void *ptr, Uint old_size, Uint size) { void *res; ASSERT(!ptr || old_size == ERTS_ALC_DBG_BLK_SZ(ptr)); res = erts_realloc(type, ptr, size); return res; } ERTS_GLB_INLINE void * erts_db_realloc_fnf_nt(ErtsAlcType_t type, void *ptr, Uint old_size, Uint size) { void *res; ASSERT(!ptr || old_size == ERTS_ALC_DBG_BLK_SZ(ptr)); res = erts_realloc_fnf(type, ptr, size); if (!res) return NULL; return res; } #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ ERTS_GLB_INLINE void erts_db_free(ErtsAlcType_t type, DbTable *tab, void *ptr, Uint size); ERTS_GLB_INLINE void erts_schedule_db_free(DbTableCommon* tab, void (*free_func)(void *), void *ptr, ErtsThrPrgrLaterOp *lop, Uint size); ERTS_GLB_INLINE void erts_db_free_nt(ErtsAlcType_t type, void *ptr, Uint size); #if ERTS_GLB_INLINE_INCL_FUNC_DEF ERTS_GLB_INLINE void erts_db_free(ErtsAlcType_t type, DbTable *tab, void *ptr, Uint size) { ASSERT(ptr != 0); ASSERT(size == ERTS_ALC_DBG_BLK_SZ(ptr)); ERTS_DB_ALC_MEM_UPDATE_(tab, size, 0); ASSERT(((void *) tab) != ptr || tab->common.counters.is_decentralized || 0 == erts_flxctr_read_centralized(&tab->common.counters, ERTS_DB_TABLE_MEM_COUNTER_ID)); erts_free(type, ptr); } ERTS_GLB_INLINE void erts_schedule_db_free(DbTableCommon* tab, void (*free_func)(void *), void *ptr, ErtsThrPrgrLaterOp *lop, Uint size) { ASSERT(ptr != 0); ASSERT(((void *) tab) != ptr); ASSERT(size == ERTS_ALC_DBG_BLK_SZ(ptr)); /* * We update table memory stats here as table may already be gone * when 'free_func' is finally called. */ ERTS_DB_ALC_MEM_UPDATE_((DbTable*)tab, size, 0); erts_schedule_thr_prgr_later_cleanup_op(free_func, ptr, lop, size); } ERTS_GLB_INLINE void erts_db_free_nt(ErtsAlcType_t type, void *ptr, Uint size) { ASSERT(ptr != 0); ASSERT(size == ERTS_ALC_DBG_BLK_SZ(ptr)); erts_free(type, ptr); } #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ #endif /* #if defined(ERTS_WANT_DB_INTERNAL__) && !defined(ERTS_HAVE_DB_INTERNAL__) */ #endif /* !ERTS_ONLY_SCHED_SPEC_ETS_DATA */