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

📄 erl_db_tree.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 5 页
字号:
	counterpos = tb->common.keypos + 1;    res = db_do_update_counter(p, (DbTableCommon *) tb, 			       (void *) bp, (*bp)->dbterm.tpl,			       counterpos, 			       (int (*)(DbTableCommon *,					void *,					Uint,					Eterm,					int))			       &realloc_counter, incr, warp, ret);    if (*bp != b) /* May be reallocated in which case 		     the saved stack is messed up, clear stck if so. */	tb->stack_pos = tb->slot_pos = 0;    return res;}static int db_put_tree(Process *proc, DbTable *tbl, Eterm obj, Eterm *ret){    DbTableTree *tb = &tbl->tree;    /* Non recursive insertion in AVL tree, building our own stack */    TreeDbTerm **tstack[STACK_NEED];    int tpos = 0;    int dstack[STACK_NEED+1];    int dpos = 0;    int state = 0;    TreeDbTerm **this = &tb->root;    Sint c;    Eterm key;    int dir;    TreeDbTerm *p1, *p2, *p;    key = GETKEY(tb, tuple_val(obj));    tb->stack_pos = tb->slot_pos = 0;    dstack[dpos++] = DIR_END;    for (;;)	if (!*this) { /* Found our place */	    state = 1;	    if (tb->common.nitems < TREE_MAX_ELEMENTS)		tb->common.nitems++;	    else		return DB_ERROR_SYSRES;	    *this = get_term(tb, NULL, obj);	    (*this)->balance = 0;	    (*this)->left = (*this)->right = NULL;	    break;	} else if ((c = cmp(key,GETKEY(tb,(*this)->dbterm.tpl))) < 0) { 	    /* go left */	    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 and this is a set, replace. */	    *this = get_term(tb, *this, obj);	    break;	}    while (state && ( dir = dstack[--dpos] ) != DIR_END) {	this = tstack[--tpos];	p = *this;	if (dir == DIR_LEFT) {	    switch (p->balance) {	    case 1:		p->balance = 0;		state = 0;		break;	    case 0:		p->balance = -1;		break;	    case -1: /* The icky case */		p1 = p->left;		if (p1->balance == -1) { /* Single LL rotation */		    p->left = p1->right;		    p1->right = p;		    p->balance = 0;		    (*this) = p1;		} else { /* Double RR rotation */		    p2 = p1->right;		    p1->right = p2->left;		    p2->left = p1;		    p->left = p2->right;		    p2->right = p;		    p->balance = (p2->balance == -1) ? +1 : 0;		    p1->balance = (p2->balance == 1) ? -1 : 0;		    (*this) = p2;		}		(*this)->balance = 0;		state = 0;		break;	    }	} else { /* dir == DIR_RIGHT */	    switch (p->balance) {	    case -1:		p->balance = 0;		state = 0;		break;	    case 0:		p->balance = 1;		break;	    case 1:		p1 = p->right;		if (p1->balance == 1) { /* Single RR rotation */		    p->right = p1->left;		    p1->left = p;		    p->balance = 0;		    (*this) = p1;		} else { /* Double RL rotation */		    p2 = p1->left;		    p1->left = p2->right;		    p2->right = p1;		    p->right = p2->left;		    p2->left = p;		    p->balance = (p2->balance == 1) ? -1 : 0;		    p1->balance = (p2->balance == -1) ? 1 : 0;		    (*this) = p2;		}		(*this)->balance = 0; 		state = 0;		break;	    }	}    }    *ret = am_true;        return DB_ERROR_NONE;}static int db_get_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret){    DbTableTree *tb = &tbl->tree;    Eterm copy;    Eterm *hp;    TreeDbTerm *this;    /*     * This is always a set, so we know exactly how large     * the data is when we have found it.     * The list created around it is purely for interface conformance.     */        this = find_node(tb,key);    if (this == NULL) {	*ret = NIL;    } else {	hp = HAlloc(p, this->dbterm.size + 2);	copy = copy_shallow(this->dbterm.v, 			    this->dbterm.size, 			    &hp, 			    &MSO(p));	*ret = CONS(hp, copy, NIL);    }    return DB_ERROR_NONE;}static int db_member_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret){    DbTableTree *tb = &tbl->tree;    TreeDbTerm *this;    /*     * This is always a set, so we know exactly how large     * the data is when we have found it.     * The list created around it is purely for interface conformance.     */        this = find_node(tb,key);    if (this == NULL) {	*ret = am_false;    } else {	*ret = am_true;    }    return DB_ERROR_NONE;}static int db_get_element_tree(Process *p, DbTable *tbl,			       Eterm key, int ndex, Eterm *ret){    DbTableTree *tb = &tbl->tree;    /*     * Look the node up:     */    Eterm *hp;    TreeDbTerm *this;    /*     * This is always a set, so we know exactly how large     * the data is when we have found it.     * No list is created around elements in set's so there are no list     * around the element here either.     */        this = find_node(tb,key);    if (this == NULL) {	return DB_ERROR_BADKEY;    } else {	Eterm element;	Uint sz;	if (ndex > arityval(this->dbterm.tpl[0])) {	    return DB_ERROR_BADPARAM;	}	element = this->dbterm.tpl[ndex];	sz = size_object(element);	hp = HAlloc(p, sz);	*ret = copy_struct(element, 			   sz, 			   &hp, 			   &MSO(p));    }    return DB_ERROR_NONE;}static int db_erase_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret){    DbTableTree *tb = &tbl->tree;    TreeDbTerm *res;    *ret = am_true;    if ((res = linkout_tree(tb, key)) != NULL) {	free_term(tb, res);    }    return DB_ERROR_NONE;}static int db_erase_object_tree(Process *p, DbTable *tbl,				Eterm object, Eterm *ret){    DbTableTree *tb = &tbl->tree;    TreeDbTerm *res;    *ret = am_true;    if ((res = linkout_object_tree(tb, object)) != NULL) {	free_term(tb, res);    }    return DB_ERROR_NONE;}static int db_slot_tree(Process *p, DbTable *tbl, 			Eterm slot_term, Eterm *ret){    DbTableTree *tb = &tbl->tree;    Sint slot;    TreeDbTerm *st;    Eterm *hp;    Eterm copy;    /*     * The notion of a "slot" is not natural in a tree, but we try to     * simulate it by giving the n'th node in the tree instead.     * Traversing a tree in this way is not very convenient, but by     * using the saved stack we at least sometimes will get acceptable      * performance.     */    if (is_not_small(slot_term) ||	((slot = signed_val(slot_term)) < 0) ||	(slot > tb->common.nitems))	return DB_ERROR_BADPARAM;    if (slot == tb->common.nitems) {	*ret = am_EOT;	return DB_ERROR_NONE;    }    /*      * We use the slot position and search from there, slot positions      * are counted from 1 and up.     */    ++slot;    st = slot_search(p, tb, slot);     if (st == NULL) {	*ret = am_false;	return DB_ERROR_UNSPEC;    }    hp = HAlloc(p, st->dbterm.size + 2);    copy = copy_shallow(st->dbterm.v, 			st->dbterm.size, 			&hp, 			&MSO(p));    *ret = CONS(hp, copy, NIL);    return DB_ERROR_NONE;}static BIF_RETTYPE ets_select_reverse(Process *p, Eterm a1, Eterm a2, Eterm a3){    Eterm list;    Eterm result;    Eterm* hp;    Eterm* hend;    int max_iter = CONTEXT_REDS * 10;    if (is_nil(a1)) {	hp = HAlloc(p, 3);	BIF_RET(TUPLE2(hp,a2,a3));    } else if (is_not_list(a1)) {    error:	BIF_ERROR(p, BADARG);    }        list = a1;    result = a2;    hp = hend = NULL;    while (is_list(list)) {	Eterm* pair = list_val(list);	if (--max_iter == 0) {	    BUMP_ALL_REDS(p);	    HRelease(p, hend, hp);	    BIF_TRAP3(&ets_select_reverse_exp, p, list, result, a3);	}	if (hp == hend) {	    hp = HAlloc(p, 64);	    hend = hp + 64;	}	result = CONS(hp, CAR(pair), result);	hp += 2;	list = CDR(pair);    }    if (is_not_nil(list))  {	goto error;    }    HRelease(p, hend, hp);    BUMP_REDS(p,CONTEXT_REDS - max_iter / 10);    hp = HAlloc(p,3);    BIF_RET(TUPLE2(hp, result, a3));}static BIF_RETTYPE bif_trap1(Export *bif,			     Process *p, 			     Eterm p1) {    BIF_TRAP1(bif, p, p1);}    static BIF_RETTYPE bif_trap3(Export *bif,			     Process *p, 			     Eterm p1, 			     Eterm p2,			     Eterm p3) {    BIF_TRAP3(bif, p, p1, p2, p3);}    /*** This is called either when the select bif traps or when ets:select/1 ** is called. It does mostly the same as db_select_tree and may in either case** trap to itself again (via the ets:select/1 bif).** Note that this is common for db_select_tree and db_select_chunk_tree.*/static int db_select_continue_tree(Process *p, 				   DbTable *tbl,				   Eterm continuation,				   Eterm *ret){    DbTableTree *tb = &tbl->tree;    struct select_context sc;    unsigned sz;    Eterm *hp;     Eterm lastkey;    Eterm end_condition;     Binary *mp;    Eterm key;    Eterm *tptr;    Sint chunk_size;    Sint reverse;#define RET_TO_BIF(Term, State) do { *ret = (Term); return State; } while(0);    /* Decode continuation. We know it's a tuple but not the arity or        anything else */    tptr = tuple_val(continuation);    if (arityval(*tptr) != 8)	RET_TO_BIF(NIL,DB_ERROR_BADPARAM);        if (!is_small(tptr[4]) || !is_binary(tptr[5]) || 	!(is_list(tptr[6]) || tptr[6] == NIL) || !is_small(tptr[7]) ||	!is_small(tptr[8]))	RET_TO_BIF(NIL,DB_ERROR_BADPARAM);        lastkey = tptr[2];    end_condition = tptr[3];    if (!(thing_subtag(*binary_val(tptr[5])) == REFC_BINARY_SUBTAG))	RET_TO_BIF(NIL,DB_ERROR_BADPARAM);    mp = ((ProcBin *) binary_val(tptr[5]))->val;    if (!(mp->flags & BIN_FLAG_MATCH_PROG))	RET_TO_BIF(NIL,DB_ERROR_BADPARAM);    chunk_size = signed_val(tptr[4]);    sc.p = p;    sc.accum = tptr[6];    sc.mp = mp;    sc.end_condition = NIL;    sc.lastobj = NULL;    sc.max = 1000;    sc.keypos = tb->common.keypos;    sc.all_objects = mp->flags & BIN_FLAG_ALL_OBJECTS;    sc.chunk_size = chunk_size;    reverse = unsigned_val(tptr[7]);    sc.got = signed_val(tptr[8]);    if (chunk_size) {	if (reverse) {	    traverse_backwards(tb, lastkey, &doit_select_chunk, &sc); 	} else {	    traverse_forward(tb, lastkey, &doit_select_chunk, &sc); 	}    } else {	if (reverse) {	    traverse_forward(tb, lastkey, &doit_select, &sc);	} else {	    traverse_backwards(tb, lastkey, &doit_select, &sc);	}    }    BUMP_REDS(p, 1000 - sc.max);    if (sc.max > 0) {	if (chunk_size) {	    Eterm *hp; 	    unsigned sz;	    if (sc.got < chunk_size || sc.lastobj == NULL) { 		/* end of table, sc.lastobj may be NULL as we may have been		   at the very last object in the table when trapping. */		if (!sc.got) {		    RET_TO_BIF(am_EOT, DB_ERROR_NONE);		} else {		    RET_TO_BIF(bif_trap3(&ets_select_reverse_exp, p,					 sc.accum, NIL, am_EOT), 			       DB_ERROR_NONE);		}	    }	    key = GETKEY(tb, sc.lastobj);	    sz = size_object(key);	    hp = HAlloc(p, 9 + sz);	    key = copy_struct(key, sz, &hp, &MSO(p));	    continuation = TUPLE8		(hp,		 tptr[1],		 key,		 tptr[3], 		 tptr[4],		 tptr[5],		 NIL,		 tptr[7],		 make_small(0));	    RET_TO_BIF(bif_trap3(&ets_select_reverse_exp, p,				 sc.accum, NIL, continuation), 		       DB_ERROR_NONE);	} else {	    RET_TO_BIF(sc.accum, DB_ERROR_NONE);	}    }	    key = GETKEY(tb, sc.lastobj);    if (chunk_size) {	if (end_condition != NIL && 	    ((!reverse && cmp_partly_bound(end_condition,key) < 0) ||	     (reverse && cmp_partly_bound(end_condition,key) > 0))) { 	    /* done anyway */	    if (!sc.got) {		RET_TO_BIF(am_EOT, DB_ERROR_NONE);	    } else {		RET_TO_BIF(bif_trap3(&ets_select_reverse_exp, p, 				     sc.accum, NIL, am_EOT), 			   DB_ERROR_NONE);	    }	}    } else {	if (end_condition != NIL && 	    ((!reverse && cmp_partly_bound(end_condition,key) > 0) ||	     (reverse && cmp_partly_bound(end_condition,key) < 0))) { 	    /* done anyway */	    RET_TO_BIF(sc.accum,DB_ERROR_NONE);	}    }    /* Not done yet, let's trap. */    sz = size_object(key);    hp = HAlloc(p, 9 + sz);    key = copy_struct(key, sz, &hp, &MSO(p));    continuation = TUPLE8	(hp,	 tptr[1],	 key,	 tptr[3], 	 tptr[4],	 tptr[5],	 sc.accum,	 tptr[7],	 make_small(sc.got));    RET_TO_BIF(bif_trap1(bif_export[BIF_ets_select_1], p, continuation), 	       DB_ERROR_NONE);#undef RET_TO_BIF}static int db_select_tree(Process *p, DbTable *tbl, 			  Eterm pattern, int reverse, Eterm *ret){    DbTableTree *tb = &tbl->tree;    struct select_context sc;    struct mp_info mpi;    Eterm lastkey = NIL;    Eterm key;    Eterm continuation;    unsigned sz;    Eterm *hp;     TreeDbTerm *this;    int errcode;    Eterm mpb;#define RET_TO_BIF(Term,RetVal) do { 	       	\	if (mpi.mp != NULL) {			\	    erts_match_set_free(mpi.mp);       	\	}					\	*ret = (Term); 				\	return RetVal; 			        \    } while(0)    mpi.mp = NULL;    sc.accum = NIL;    sc.lastobj = NULL;    sc.p = p;    sc.max = 1000;     sc.end_condition = NIL;    sc.keypos = tb->common.keypos;    sc.got = 0;    sc.chunk_size = 0;    if ((errcode = analyze_pattern(tb, pattern, &mpi)) != DB_ERROR_NONE) {	RET_TO_BIF(NIL,errcode);    }    if (!mpi.something_can_match) {	RET_TO_BIF(NIL,DB_ERROR_NONE);  	/* can't possibly match anything */

⌨️ 快捷键说明

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