📄 erl_db_util.c
字号:
*/Eterm db_make_mp_binary(Process *p, Binary *mp, Eterm **hpp) { ProcBin *pb; erts_refc_inc(&mp->refc, 1); pb = (ProcBin *) *hpp; *hpp += PROC_BIN_SIZE; pb->thing_word = HEADER_PROC_BIN; pb->size = 0; pb->next = MSO(p).mso; MSO(p).mso = pb; pb->val = mp; pb->bytes = (byte*) mp->orig_bytes; return make_binary(pb);}DMCErrInfo *db_new_dmc_err_info(void) { DMCErrInfo *ret = erts_alloc(ERTS_ALC_T_DB_DMC_ERR_INFO, sizeof(DMCErrInfo)); ret->var_trans = NULL; ret->num_trans = 0; ret->error_added = 0; ret->first = NULL; return ret;}Eterm db_format_dmc_err_info(Process *p, DMCErrInfo *ei){ int ll,sl; int vnum; DMCError *tmp; Eterm *lhp, *shp; Eterm ret = NIL, tpl, sev; char buff[DMC_ERR_STR_LEN + 20 /* for the number */]; ll = 0; for (tmp = ei->first; tmp != NULL; tmp = tmp->next) ++ll; lhp = HAlloc(p, ll * (2 /*cons cell*/ + 3 /*tuple of arity 2*/)); for (tmp = ei->first; tmp != NULL; tmp = tmp->next) { if (tmp->variable >= 0 && tmp->variable < ei->num_trans && ei->var_trans != NULL) { vnum = (int) ei->var_trans[tmp->variable]; } else { vnum = tmp->variable; } if (vnum >= 0) sprintf(buff,tmp->error_string, vnum); else strcpy(buff,tmp->error_string); sl = strlen(buff); shp = HAlloc(p, sl * 2); sev = (tmp->severity == dmcWarning) ? am_atom_put("warning",7) : am_error; tpl = TUPLE2(lhp, sev, buf_to_intlist(&shp, buff, sl, NIL)); lhp += 3; ret = CONS(lhp, tpl, ret); lhp += 2; } return ret;}void db_free_dmc_err_info(DMCErrInfo *ei){ while (ei->first != NULL) { DMCError *ll = ei->first->next; erts_free(ERTS_ALC_T_DB_DMC_ERROR, ei->first); ei->first = ll; } if (ei->var_trans) erts_free(ERTS_ALC_T_DB_TRANS_TAB, ei->var_trans); erts_free(ERTS_ALC_T_DB_DMC_ERR_INFO, ei);}#define FIX_BIG_SIZE 16#define MAX_NEED(x,y) (((x)>(y)) ? (x) : (y))static Eterm big_tmp[2];static Eterm db_big_buf[FIX_BIG_SIZE];static Eterm add_counter(Eterm counter, Eterm incr){ Eterm res; Sint ires; Eterm arg1; Eterm arg2; Uint sz1; Uint sz2; Uint need; Eterm *ptr; int i; if (is_small(counter) && is_small(incr)) { ires = signed_val(counter) + signed_val(incr); if (IS_SSMALL(ires)) return make_small(ires); else return small_to_big(ires, db_big_buf); } else { switch(i = NUMBER_CODE(counter, incr)) { case SMALL_BIG: arg1 = small_to_big(signed_val(counter), big_tmp); arg2 = incr; break; case BIG_SMALL: arg1 = counter; arg2 = small_to_big(signed_val(incr), big_tmp); break; case BIG_BIG: arg1 = incr; arg2 = counter; break; default: return THE_NON_VALUE; } sz1 = big_size(arg1); sz2 = big_size(arg2); sz1 = MAX_NEED(sz1,sz2)+1; need = BIG_NEED_SIZE(sz1); if (need <= FIX_BIG_SIZE) ptr = db_big_buf; else { ptr = (Eterm *) erts_alloc_fnf(ERTS_ALC_T_DB_TMP, need*sizeof(Eterm)); if (!ptr) return NIL; /* system limit */ } res = big_plus(arg1, arg2, ptr); if (is_small(res) || is_nil(res)) { if (ptr != db_big_buf) erts_free(ERTS_ALC_T_DB_TMP, (void *) ptr); } return res; }}/*** The actual update of a counter, a lot of parameters are needed:** p: The calling process (BIF_P), ** bp: A pointer to the pointer to the object to be updated (extra ** indirection for the reallocation), this pointer is only used to** pass information to the realloc function.** tpl: A pointer to the tuple in the DbTerm.** keypos: The key position in the DbTerm.** realloc_fun: A function that does the reallocation, it takes ** bp, new size, new_value and keypos as parameter. ** ret: pointer to where the result is put.** Returns normal DB error code.*/int db_do_update_counter(Process *p, DbTableCommon *tb, void *bp /* XDbTerm **bp */, Eterm *tpl, int counterpos, int (*realloc_fun)(DbTableCommon *, void *, Uint, Eterm, int), Eterm incr, int warp, Eterm *ret){ Eterm counter; Eterm *counterp; Eterm res; /* In register? */ if (arityval(*tpl) < counterpos || !(is_small(tpl[counterpos]) || is_big(tpl[counterpos]))) return DB_ERROR_BADITEM; counterp = tpl + counterpos; counter = *counterp; if (warp) { if (is_small(incr)) { res = incr; } else { /* copy to buffer */ Eterm *tmp; Eterm *p = big_val(incr); Uint psz = BIG_ARITY(p)+1; if (psz > FIX_BIG_SIZE) { tmp = db_big_buf; } else { tmp = (Eterm *) erts_alloc_fnf(ERTS_ALC_T_DB_TMP, psz*sizeof(Eterm)); if (!tmp) return DB_ERROR_SYSRES; } sys_memcpy(tmp, p, psz*sizeof(Eterm)); res = make_big(tmp); } } else { if ((res = add_counter(counter, incr)) == NIL) { return DB_ERROR_SYSRES; } else if (is_non_value(res)) { return DB_ERROR_UNSPEC; } } if (is_small(res)) { if (is_small(counter)) { *counterp = res; } else { if ((*realloc_fun)(tb, bp, 0, res, counterpos) < 0) return DB_ERROR_SYSRES; } *ret = res; return DB_ERROR_NONE; } else { Eterm *ptr = big_val(res); Uint sz = BIG_ARITY(ptr) + 1; Eterm *hp; if ((*realloc_fun)(tb, bp, sz, res, counterpos) < 0) return DB_ERROR_SYSRES; hp = HAlloc(p, sz); sys_memcpy(hp, ptr, sz*sizeof(Eterm)); res = make_big(hp); hp += sz; if (ptr != db_big_buf) erts_free(ERTS_ALC_T_DB_TMP, (void *) ptr); *ret = res; return DB_ERROR_NONE; }} /*** Copy the object into a possibly new DbTerm, ** offset is the offset of the DbTerm from the start** of the sysAllocaed structure, The possibly realloced and copied** structure is returned. Make sure (((char *) old) - offset) is a ** pointer to a ERTS_ALC_T_DB_TERM allocated data area.*/void* db_get_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj){ int size = size_object(obj); void *structp = ((char*) old) - offset; DbTerm* p; Eterm copy; Eterm *top; if (old != 0) { erts_cleanup_offheap(&old->off_heap); if (size == old->size) { p = old; } else { Uint new_sz = offset + sizeof(DbTerm) + sizeof(Eterm)*(size-1); Uint old_sz = offset + sizeof(DbTerm) + sizeof(Eterm)*(old->size-1); if (erts_ets_realloc_always_moves) { void *nstructp = erts_db_alloc(ERTS_ALC_T_DB_TERM, (DbTable *) tb, new_sz); memcpy(nstructp,structp,offset); erts_db_free(ERTS_ALC_T_DB_TERM, (DbTable *) tb, structp, old_sz); structp = nstructp; } else { structp = erts_db_realloc(ERTS_ALC_T_DB_TERM, (DbTable *) tb, structp, old_sz, new_sz); } p = (DbTerm*) ((void *)(((char *) structp) + offset)); } } else { structp = erts_db_alloc(ERTS_ALC_T_DB_TERM, (DbTable *) tb, (offset + sizeof(DbTerm) + sizeof(Eterm)*(size-1))); p = (DbTerm*) ((void *)(((char *) structp) + offset)); } p->size = size; p->off_heap.mso = NULL; p->off_heap.externals = NULL;#ifndef HYBRID /* FIND ME! */ p->off_heap.funs = NULL;#endif p->off_heap.overhead = 0; top = p->v; copy = copy_struct(obj, size, &top, &p->off_heap); p->tpl = tuple_val(copy); return structp;}void db_free_term_data(DbTerm* p){ erts_cleanup_offheap(&p->off_heap);}/*** Copy the new counter value into the DbTerm at ((char *) *bp) + offset,** Allocate new structure of (needed size + offset) if that DbTerm** is to small. When changing size, the old structure is ** freed using ERTS_ALC_T_DB_TERM, make sure this can be done** (((char *) b) - offset is a pointer to a ERTS_ALC_T_DB_TERM area).** bp is a pure out parameter, i e it does not have to** point to (((char *) b) - offset) when calling.*/int db_realloc_counter(DbTableCommon *tb, void** bp, DbTerm *b, Uint offset, Uint sz, Eterm new_counter, int counterpos){ DbTerm* new; void *newbp; Eterm old_counter; Uint old_sz; Uint new_sz; Uint basic_sz; Eterm copy; Eterm *top; Eterm *ptr; old_counter = b->tpl[counterpos]; if (is_small(old_counter)) old_sz = 0; else { top = big_val(old_counter); old_sz = BIG_ARITY(top) + 1; if (sz == old_sz) { /* OK we fit in old space */ sys_memcpy(top, big_val(new_counter), sz*sizeof(Eterm)); return 0; } } basic_sz = b->size - old_sz; new_sz = basic_sz + sz; newbp = erts_db_alloc(ERTS_ALC_T_DB_TERM, (DbTable *) tb, sizeof(DbTerm)+sizeof(Eterm)*(new_sz-1)+offset); if (newbp == NULL) return -1; new = (DbTerm*) ((void *)(((char *) newbp) + offset)); memcpy(newbp, ((char *) b) - offset, offset); new->size = new_sz; new->off_heap.mso = NULL; new->off_heap.externals = NULL;#ifndef HYBRID /* FIND ME! */ new->off_heap.funs = NULL;#endif new->off_heap.overhead = 0; top = new->v; b->tpl[counterpos] = SMALL_ZERO; /* zap, do not copy */ /* copy term (except old counter) */ copy = copy_struct(make_tuple(b->tpl), basic_sz, &top, &new->off_heap); new->tpl = tuple_val(copy); db_free_term_data(b); /* free old term */ erts_db_free(ERTS_ALC_T_DB_TERM, (DbTable *) tb, (void *) (((char *) b) - offset), offset + sizeof(DbTerm) + sizeof(Eterm)*(b->size-1)); *bp = newbp; /* patch new */ /* copy new counter */ if (sz == 0) new->tpl[counterpos] = new_counter; /* must be small !!! */ else { ptr = big_val(new_counter); sys_memcpy(top, ptr, sz*sizeof(Eterm)); new->tpl[counterpos] = make_big(top); } return 0;}/*** Check if object represents a "match" variable ** i.e and atom $N where N is an integer ***/int db_is_variable(Eterm obj){ byte *b; int n; int N; if (is_not_atom(obj)) return -1; b = atom_tab(atom_val(obj))->name; if ((n = atom_tab(atom_val(obj))->len) < 2) return -1; if (*b++ != '$') return -1; n--; /* Handle first digit */ if (*b == '0') return (n == 1) ? 0 : -1; if (*b >= '1' && *b <= '9') N = *b++ - '0'; else return -1; n--; while(n--) { if (*b >= '0' && *b <= '9') { N = N*10 + (*b - '0'); b++; } else return -1; } return N;}/* check if obj is (or contains) a variable *//* return 1 if obj contains a variable or underscore *//* return 0 if obj is fully ground */int db_has_variable(Eterm obj){ switch(obj & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_LIST: { while (is_list(obj)) { if (db_has_variable(CAR(list_val(obj)))) return 1; obj = CDR(list_val(obj)); } return(db_has_variable(obj)); /* Non wellformed list or [] */ } case TAG_PRIMARY_BOXED: if (!BOXED_IS_TUPLE(obj)) { return 0; } else { Eterm *tuple = tuple_val(obj); int arity = arityval(*tuple++); while(arity--) { if (db_has_variable(*tuple)) return 1; tuple++; } return(0); } case TAG_PRIMARY_IMMED1: if (obj == am_Underscore || db_is_variable(obj) >= 0) return 1; } return 0;}int erts_db_is_compiled_ms(Eterm term){ return (!is_binary(term) || !(thing_subtag(*binary_val(term)) == REFC_BINARY_SUBTAG) || !((((ProcBin *) binary_val(term))->val)->flags & BIN_FLAG_MATCH_PROG)) ? 0 : 1;}/* ** Local (static) utilities.*//****************************************************************************** Compiled matches ****************************************************************************//*** Utility to add an error*/static void add_dmc_err(DMCErrInfo *err_info, char *str, int variable, Eterm term, DMCErrorSeverity severity){ /* Linked in in reverse order, to ease the formatting */ DMCError *e = erts_alloc(ERTS_ALC_T_DB_DMC_ERROR, sizeof(DMCError)); if (term != 0UL) { erts_snprintf(e->error_string, DMC_ERR_STR_LEN, str, term); } else { strncpy(e->error_string, str, DMC_ERR_STR_LEN); e->error_string[DMC_ERR_STR_LEN] ='\0'; } e->variable = variable; e->severity = severity; e->next = err_info->first;#ifdef HARDDEBUG erts_fprintf(stderr,"add_dmc_err: %s\n",e->error_string);#endif err_info->first = e; if (severity >= dmcError) err_info->error_added = 1;} /*** Handle one term in the match expression (not the guard) */static DMCRet dmc_one_term(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(Eterm) *stack, DMC_STACK_TYPE(Uint) *text, Eterm c){ Sint n; Eterm *hp; ErlHeapFragment *tmp_mb; Uint sz, sz2, sz3; Uint i, j; switch (c & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_IMMED1: if ((n = db_is_variable(c)) >= 0) { /* variable */ if (n >= heap->size) { /* ** Ouch, big integer in match variable. */ Eterm *save_hp; ASSERT(heap->data == heap->def); sz = sz2 = sz3 = 0; for (j = 0; j < context->num_match; ++j) { sz += size_object(context->matchexpr[j]); sz2 += size_object(context->guardexpr[j]); sz3 += size_object(context->bodyexpr[j]); } context->copy = new_message_buffer(sz + sz2 + sz3 + context->num_match); save_hp = hp = context->copy->mem; hp += context->num_match; for (j = 0; j < context->num_match; ++j) { context->matchexpr[j] = copy_struct(context->matchexpr[j], size_object(context->matchexpr[j]), &hp, &(context->copy->off_heap)); context->guardexpr[j] = copy_struct(context->guardexpr[j], size_object(context->guardexpr[j]), &hp, &(context->copy->off_heap)); context->bodyexpr[j] = copy_struct(context->bodyexpr[j], size_object(context->bodyexpr[j]), &hp, &(context->copy->off_heap)); } for (j = 0; j < context->num_match; ++j) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -