⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 erl_db_tree.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 5 页
字号:
	RET_TO_BIF(erts_make_integer(sc.accum,p),DB_ERROR_NONE);    }    if (mpi.some_limitation) {	if ((this = find_next_from_pb_key(tb, mpi.most)) != NULL) {	    lastkey = GETKEY(tb, this->dbterm.tpl);	}	sc.end_condition = mpi.least;    }    traverse_backwards(tb, lastkey, &doit_select_delete, &sc);    BUMP_REDS(p, 1000 - sc.max);    if (sc.max > 0) {	RET_TO_BIF(erts_make_integer(sc.accum,p), DB_ERROR_NONE);    }    key = GETKEY(tb, (sc.lastterm)->dbterm.tpl);    sz = size_object(key);    if (IS_USMALL(0, sc.accum)) {	hp = HAlloc(p, sz + PROC_BIN_SIZE + 6);	eaccsum = make_small(sc.accum);    }    else {	hp = HAlloc(p, BIG_UINT_HEAP_SIZE + sz + PROC_BIN_SIZE + 6);	eaccsum = uint_to_big(sc.accum, hp);	hp += BIG_UINT_HEAP_SIZE;    }    key = copy_struct(key, sz, &hp, &MSO(p));    mpb = db_make_mp_binary(p,mpi.mp,&hp);        continuation = TUPLE5	(hp,	 tb->common.id,	 key,	 sc.end_condition, /* From the match program, needn't be copied */	 mpb,	 eaccsum);    /* Don't free mpi.mp, so don't use macro */    if (sc.erase_lastterm) {	free_term(tb, sc.lastterm);    }    *ret = bif_trap1(&ets_select_delete_continue_exp, p, continuation);     return DB_ERROR_NONE;#undef RET_TO_BIF}/*** Other interface routines (not directly coupled to one bif)*//* Display hash table contents (for dump) */static void db_print_tree(int to, void *to_arg, 			  int show,			  DbTable *tbl){    DbTableTree *tb = &tbl->tree;#ifdef TREE_DEBUG    if (show)	erts_print(to, to_arg, "\nTree data dump:\n"		   "------------------------------------------------\n");    do_dump_tree2(to, to_arg, show, tb->root, 0);    if (show)	erts_print(to, to_arg, "\n"		   "------------------------------------------------\n");#else    erts_print(to, to_arg, "Ordered set (AVL tree), Elements: %d\n", tb->common.nitems);    do_dump_tree(to, to_arg, tb->root);#endif}/* release all memory occupied by a single table */static int db_free_table_tree(DbTable *tbl){    DbTableTree *tb = &tbl->tree;    if (!tb->deletion) {	tb->stack_pos = 0;	tb->deletion = 1;	PUSH_NODE(tb, tb->root);    }    do_free_tree(tb);    erts_db_free(ERTS_ALC_T_DB_STK,		 (DbTable *) tb,		 (void *) tb->stack,		 sizeof(TreeDbTerm *) * STACK_NEED);    ASSERT(erts_smp_atomic_read(&tb->common.memory_size) == sizeof(DbTable));    return 1;}static int db_free_table_continue_tree(DbTable *tbl, int first){    DbTableTree *tb = &tbl->tree;    int result;    if (first) {	tb->stack_pos = 0;	tb->deletion = 1;	PUSH_NODE(tb, tb->root);    }    result = do_free_tree_cont(tb, DELETE_RECORD_LIMIT);    if (result) {		/* Completely done. */	erts_db_free(ERTS_ALC_T_DB_STK,		     (DbTable *) tb,		     (void *) tb->stack,		     sizeof(TreeDbTerm *) * STACK_NEED);	ASSERT(erts_smp_atomic_read(&tb->common.memory_size)	       == sizeof(DbTable));    }    return result;}static int db_delete_all_objects_tree(Process* p, DbTable* tbl){    db_free_table_tree(tbl);    db_create_tree(p, tbl);    tbl->tree.common.nitems = 0;    return 0;}static void do_db_tree_foreach_offheap(TreeDbTerm *,				       void (*)(ErlOffHeap *, void *),				       void *);static void db_foreach_offheap_tree(DbTable *tbl,				    void (*func)(ErlOffHeap *, void *),				    void * arg){    do_db_tree_foreach_offheap(tbl->tree.root, func, arg);}/*** Functions for internal use*/static voiddo_db_tree_foreach_offheap(TreeDbTerm *tdbt,			   void (*func)(ErlOffHeap *, void *),			   void * arg){    if(!tdbt)	return;    do_db_tree_foreach_offheap(tdbt->left, func, arg);    (*func)(&(tdbt->dbterm.off_heap), arg);    do_db_tree_foreach_offheap(tdbt->right, func, arg);}static TreeDbTerm *linkout_tree(DbTableTree *tb, 				Eterm key){    TreeDbTerm **tstack[STACK_NEED];    int tpos = 0;    int dstack[STACK_NEED+1];    int dpos = 0;    int state = 0;    TreeDbTerm **this = &tb->root;    Sint c;    int dir;    TreeDbTerm *q = NULL;    /*     * Somewhat complicated, deletion in an AVL tree,     * The two helpers balance_left and balance_right are used to     * keep the balance. As in insert, we do the stacking ourselves.     */    tb->stack_pos = tb->slot_pos = 0;    dstack[dpos++] = DIR_END;    for (;;) {	if (!*this) { /* Failure */	    return NULL;	} else if ((c = cmp(key,GETKEY(tb,(*this)->dbterm.tpl))) < 0) { 	    dstack[dpos++] = DIR_LEFT;	    tstack[tpos++] = this;	    this = &((*this)->left);	} else if (c > 0) { /* go right */	    dstack[dpos++] = DIR_RIGHT;	    tstack[tpos++] = this;	    this = &((*this)->right);	} else { /* Equal key, found the one to delete*/	    q = (*this);	    if (q->right == NULL) {		(*this) = q->left;		state = 1;	    } else if (q->left == NULL) {		(*this) = q->right;		state = 1;	    } else {		dstack[dpos++] = DIR_LEFT;		tstack[tpos++] = this;		state = delsub(this);	    }	    --(tb->common.nitems);	    break;	}    }    while (state && ( dir = dstack[--dpos] ) != DIR_END) {	this = tstack[--tpos];	if (dir == DIR_LEFT) {	    state = balance_left(this);	} else {	    state = balance_right(this);	}    }    return q;}static TreeDbTerm *linkout_object_tree(DbTableTree *tb, 				       Eterm object){    TreeDbTerm **tstack[STACK_NEED];    int tpos = 0;    int dstack[STACK_NEED+1];    int dpos = 0;    int state = 0;    TreeDbTerm **this = &tb->root;    Sint c;    int dir;    TreeDbTerm *q = NULL;    Eterm key;    /*     * Somewhat complicated, deletion in an AVL tree,     * The two helpers balance_left and balance_right are used to     * keep the balance. As in insert, we do the stacking ourselves.     */        key = GETKEY(tb, tuple_val(object));    tb->stack_pos = tb->slot_pos = 0;    dstack[dpos++] = DIR_END;    for (;;) {	if (!*this) { /* Failure */	    return NULL;	} else if ((c = cmp(key,GETKEY(tb,(*this)->dbterm.tpl))) < 0) { 	    dstack[dpos++] = DIR_LEFT;	    tstack[tpos++] = this;	    this = &((*this)->left);	} else if (c > 0) { /* go right */	    dstack[dpos++] = DIR_RIGHT;	    tstack[tpos++] = this;	    this = &((*this)->right);	} else { /* Equal key, found the only possible matching object*/	    if (!eq(object,make_tuple((*this)->dbterm.tpl))) {		return NULL;	    }	    q = (*this);	    if (q->right == NULL) {		(*this) = q->left;		state = 1;	    } else if (q->left == NULL) {		(*this) = q->right;		state = 1;	    } else {		dstack[dpos++] = DIR_LEFT;		tstack[tpos++] = this;		state = delsub(this);	    }	    --(tb->common.nitems);	    break;	}    }    while (state && ( dir = dstack[--dpos] ) != DIR_END) {	this = tstack[--tpos];	if (dir == DIR_LEFT) {	    state = balance_left(this);	} else {	    state = balance_right(this);	}    }    return q;}/*** For the select functions, analyzes the pattern and determines which** part of the tree should be searched. Also compiles the match program*/static int analyze_pattern(DbTableTree *tb, Eterm pattern, 			   struct mp_info *mpi){    Eterm lst, tpl, ttpl;    Eterm *matches,*guards, *bodies;    Eterm sbuff[30];    Eterm *buff = sbuff;    Eterm *ptpl;    int i;    int num_heads = 0;    Eterm key;    Eterm partly_bound;    int res;    Eterm least = 0;    Eterm most = 0;    mpi->some_limitation = 1;    mpi->got_partial = 0;    mpi->something_can_match = 0;    mpi->mp = NULL;    mpi->all_objects = 1;    mpi->save_term = NULL;    for (lst = pattern; is_list(lst); lst = CDR(list_val(lst)))	++num_heads;    if (lst != NIL) {/* proper list... */	return DB_ERROR_BADPARAM;    }    if (num_heads > 10) {	buff = erts_alloc(ERTS_ALC_T_DB_TMP, sizeof(Eterm) * num_heads * 3);    }    matches = buff;    guards = buff + num_heads;    bodies = buff + (num_heads * 2);    i = 0;    for(lst = pattern; is_list(lst); lst = CDR(list_val(lst))) {	Eterm body;	ttpl = CAR(list_val(lst));	if (!is_tuple(ttpl)) {	    if (buff != sbuff) { 		erts_free(ERTS_ALC_T_DB_TMP, buff);	    }	    return DB_ERROR_BADPARAM;	}	ptpl = tuple_val(ttpl);	if (ptpl[0] != make_arityval(3U)) {	    if (buff != sbuff) { 		erts_free(ERTS_ALC_T_DB_TMP, buff);	    }	    return DB_ERROR_BADPARAM;	}	matches[i] = tpl = ptpl[1];	guards[i] = ptpl[2];	bodies[i] = body = ptpl[3];	if (!is_list(body) || CDR(list_val(body)) != NIL ||	    CAR(list_val(body)) != am_DollarUnderscore) {	    mpi->all_objects = 0;	}	++i;	partly_bound = NIL;	res = key_given(tb, tpl, &mpi->save_term, &partly_bound);	if ( res >= 0 ) {   /* Can match something */	    key = 0;	    mpi->something_can_match = 1;	    if (res > 0) {		key = GETKEY(tb,tuple_val(tpl)); 	    } else if (partly_bound != NIL) {		mpi->got_partial = 1;		key = partly_bound;	    } else {		mpi->some_limitation = 0;	    }	    if (key != 0) {		if (least == 0 || 		    partly_bound_can_match_lesser(key,least)) {		    least = key;		}		if (most == 0 || 		    partly_bound_can_match_greater(key,most)) {		    most = key;		}	    }	}    }    mpi->least = least;    mpi->most = most;    /*     * It would be nice not to compile the match_spec if nothing could match,     * but then the select calls would not fail like they should on bad      * match specs that happen to specify non existent keys etc.     */    if ((mpi->mp = db_match_compile(matches, guards, bodies,				    num_heads, DCOMP_TABLE, NULL)) 	== NULL) {	if (buff != sbuff) { 	    erts_free(ERTS_ALC_T_DB_TMP, buff);	}	return DB_ERROR_BADPARAM;    }    if (buff != sbuff) { 	erts_free(ERTS_ALC_T_DB_TMP, buff);    }    return DB_ERROR_NONE;}static void do_dump_tree(int to, void *to_arg, TreeDbTerm *t){    if (t != NULL) {	do_dump_tree(to, to_arg, t->left);	erts_print(to, to_arg, "%T\n", make_tuple(t->dbterm.tpl));	do_dump_tree(to, to_arg, t->right);     }}static void free_term(DbTableTree *tb, TreeDbTerm* p){    db_free_term_data(&(p->dbterm));    erts_db_free(ERTS_ALC_T_DB_TERM,		 (DbTable *) tb,		 (void *) p,		 SIZ_DBTERM(p)*sizeof(Uint));}static void do_free_tree(DbTableTree *tb){    TreeDbTerm *root;    TreeDbTerm *p;    root = POP_NODE(tb);    while (root != NULL) {	if ((p = root->left) != NULL) {	    root->left = NULL;	    PUSH_NODE(tb, root);	    root = p;	    continue;	} else if ((p = root->right) != NULL) {	    root->right = NULL;	    PUSH_NODE(tb, root);	    root = p;	    continue;	} else {	    free_term(tb, root);	    root = POP_NODE(tb);	}    }}static int do_free_tree_cont(DbTableTree *tb, int num_left){    TreeDbTerm *root;    TreeDbTerm *p;    root = POP_NODE(tb);    while (root != NULL) {	if ((p = root->left) != NULL) {	    root->left = NULL;	    PUSH_NODE(tb, root);	    root = p;	    continue;	} else if ((p = root->right) != NULL) {	    root->right = NULL;	    PUSH_NODE(tb, root);	    root = p;	    continue;	} else {	    free_term(tb, root);	    if (--num_left > 0) {		root = POP_NODE(tb);	    } else {		return 0;	/* Done enough for now */	    }	}    }    return 1;}static TreeDbTerm* get_term(DbTableTree *tb,			    TreeDbTerm* old, 			    Eterm obj) {    TreeDbTerm* p = db_get_term((DbTableCommon *) tb,				(old != NULL) ? &(old->dbterm) : NULL, 				((char *) &(old->dbterm)) - ((char *) old),				obj);    return p;}/* * Deletion helpers */static int balance_left(TreeDbTerm **this) {    TreeDbTerm *p, *p1, *p2;    int b1, b2, h = 1;        p = *this;    switch (p->balance) {    case -1:	p->balance = 0;	break;    case 0:	p->balance = 1;	h = 0;	break;    case 1:	p1 = p->right;	b1 = p1->balance;	if (b1 >= 0) { /* Single RR rotation */	    p->right = p1->left;	    p1->left = p;	    if (b1 == 0) {		p->balance = 1;		p1->balance = -1;		h = 0;	    } else {		p->balance = p1->balance = 0;	    }	    (*this) = p1;	} else { /* Double RL rotation */	    p2 = p1->left;	    b2 = p2->balance;	    p1->left = p2->right;	    p2->right = p1;	    p->right = p2->left;	    p2->left = p;	    p->balance = (b2 == 1) ? -1 : 0;	    p1->balance = (b2 == -1) ? 1 : 0;	    p2->balance = 0;	    (*this) = p2;	}	break;    }    return h;}static int balance_right(TreeDbTerm **this) {    TreeDbTerm *p, *p1, *p2;    int b1, b2, h = 1;        p = *this;    switch (p->balance) {    case 1:	p->balance = 0;	break;    case 0:	p->balance = -1;	h = 0;	break;    case -1:	p1 = p->left;	b1 = p1->balance;	if (b1 <= 0) { /* Single LL rotation */	    p->left = p1->right;	    p1->right = p;	    if (b1 == 0) {		p->balance = -1;		p1->balance = 1;		h = 0;	    } else {		p->balance = p1->balance = 0;	    }	    (*this) = p1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -