📄 erl_db_tree.c
字号:
} sc.mp = mpi.mp; sc.all_objects = mpi.all_objects; if (!mpi.got_partial && mpi.some_limitation && cmp(mpi.least,mpi.most) == 0) { doit_select(tb,mpi.save_term,&sc,0 /* direction doesn't matter */); RET_TO_BIF(sc.accum,DB_ERROR_NONE); } if (reverse) { if (mpi.some_limitation) { if ((this = find_prev_from_pb_key(tb, mpi.least)) != NULL) { lastkey = GETKEY(tb, this->dbterm.tpl); } sc.end_condition = mpi.most; } traverse_forward(tb, lastkey, &doit_select, &sc); } else { 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, &sc); }#ifdef HARDDEBUG erts_fprintf(stderr,"Least: %T\n", mpi.least); erts_fprintf(stderr,"Most: %T\n", mpi.most);#endif BUMP_REDS(p, 1000 - sc.max); if (sc.max > 0) { RET_TO_BIF(sc.accum,DB_ERROR_NONE); } key = GETKEY(tb, sc.lastobj); sz = size_object(key); hp = HAlloc(p, 9 + sz + PROC_BIN_SIZE); key = copy_struct(key, sz, &hp, &MSO(p)); if (mpi.all_objects) (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS; mpb=db_make_mp_binary(p,mpi.mp,&hp); continuation = TUPLE8 (hp, tb->common.id, key, sc.end_condition, /* From the match program, needn't be copied */ make_small(0), /* Chunk size of zero means not chunked to the continuation BIF */ mpb, sc.accum, make_small(reverse), make_small(sc.got)); /* Don't free mpi.mp, so don't use macro */ *ret = bif_trap1(bif_export[BIF_ets_select_1], p, continuation); return DB_ERROR_NONE;#undef RET_TO_BIF} /*** This is called either when the select_count bif traps.*/static int db_select_count_continue_tree(Process *p, DbTable *tbl, Eterm continuation, Eterm *ret){ DbTableTree *tb = &tbl->tree; struct select_count_context sc; unsigned sz; Eterm *hp; Eterm lastkey; Eterm end_condition; Binary *mp; Eterm key; Eterm *tptr; Eterm egot;#define RET_TO_BIF(Term, State) do { *ret = (Term); return State; } while(0); /* Decode continuation. We know it's a tuple and everything else as this is only called by ourselves */ /* continuation: {Table, Lastkey, EndCondition, MatchProgBin, HowManyGot}*/ tptr = tuple_val(continuation); if (arityval(*tptr) != 5) erl_exit(1,"Internal error in ets:select_count/1"); lastkey = tptr[2]; end_condition = tptr[3]; if (!(thing_subtag(*binary_val(tptr[4])) == REFC_BINARY_SUBTAG)) RET_TO_BIF(NIL,DB_ERROR_BADPARAM); mp = ((ProcBin *) binary_val(tptr[4]))->val; if (!(mp->flags & BIN_FLAG_MATCH_PROG)) RET_TO_BIF(NIL,DB_ERROR_BADPARAM); sc.p = p; sc.mp = mp; sc.end_condition = NIL; sc.lastobj = NULL; sc.max = 1000; sc.keypos = tb->common.keypos; if (is_big(tptr[5])) { sc.got = big_to_uint32(tptr[5]); } else { sc.got = unsigned_val(tptr[5]); } traverse_backwards(tb, lastkey, &doit_select_count, &sc); BUMP_REDS(p, 1000 - sc.max); if (sc.max > 0) { RET_TO_BIF(erts_make_integer(sc.got,p), DB_ERROR_NONE); } key = GETKEY(tb, sc.lastobj); if (end_condition != NIL && (cmp_partly_bound(end_condition,key) > 0)) { /* done anyway */ RET_TO_BIF(make_small(sc.got),DB_ERROR_NONE); } /* Not done yet, let's trap. */ sz = size_object(key); if (IS_USMALL(0, sc.got)) { hp = HAlloc(p, sz + 6); egot = make_small(sc.got); } else { hp = HAlloc(p, BIG_UINT_HEAP_SIZE + sz + 6); egot = uint_to_big(sc.got, hp); hp += BIG_UINT_HEAP_SIZE; } key = copy_struct(key, sz, &hp, &MSO(p)); continuation = TUPLE5 (hp, tptr[1], key, tptr[3], tptr[4], egot); RET_TO_BIF(bif_trap1(&ets_select_count_continue_exp, p, continuation), DB_ERROR_NONE);#undef RET_TO_BIF}static int db_select_count_tree(Process *p, DbTable *tbl, Eterm pattern, Eterm *ret){ DbTableTree *tb = &tbl->tree; struct select_count_context sc; struct mp_info mpi; Eterm lastkey = NIL; Eterm key; Eterm continuation; unsigned sz; Eterm *hp; TreeDbTerm *this; int errcode; Eterm egot; 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.lastobj = NULL; sc.p = p; sc.max = 1000; sc.end_condition = NIL; sc.keypos = tb->common.keypos; sc.got = 0; if ((errcode = analyze_pattern(tb, pattern, &mpi)) != DB_ERROR_NONE) { RET_TO_BIF(NIL,errcode); } if (!mpi.something_can_match) { RET_TO_BIF(make_small(0),DB_ERROR_NONE); /* can't possibly match anything */ } sc.mp = mpi.mp; sc.all_objects = mpi.all_objects; if (!mpi.got_partial && mpi.some_limitation && cmp(mpi.least,mpi.most) == 0) { doit_select_count(tb,mpi.save_term,&sc,0 /* dummy */); RET_TO_BIF(erts_make_integer(sc.got,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_count, &sc); BUMP_REDS(p, 1000 - sc.max); if (sc.max > 0) { RET_TO_BIF(erts_make_integer(sc.got,p),DB_ERROR_NONE); } key = GETKEY(tb, sc.lastobj); sz = size_object(key); if (IS_USMALL(0, sc.got)) { hp = HAlloc(p, sz + PROC_BIN_SIZE + 6); egot = make_small(sc.got); } else { hp = HAlloc(p, BIG_UINT_HEAP_SIZE + sz + PROC_BIN_SIZE + 6); egot = uint_to_big(sc.got, hp); hp += BIG_UINT_HEAP_SIZE; } key = copy_struct(key, sz, &hp, &MSO(p)); if (mpi.all_objects) (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS; 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, egot); /* Don't free mpi.mp, so don't use macro */ *ret = bif_trap1(&ets_select_count_continue_exp, p, continuation); return DB_ERROR_NONE;#undef RET_TO_BIF}static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm pattern, Sint chunk_size, 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 = chunk_size; if ((errcode = analyze_pattern(tb, pattern, &mpi)) != DB_ERROR_NONE) { RET_TO_BIF(NIL,errcode); } if (!mpi.something_can_match) { RET_TO_BIF(am_EOT,DB_ERROR_NONE); /* can't possibly match anything */ } sc.mp = mpi.mp; sc.all_objects = mpi.all_objects; if (!mpi.got_partial && mpi.some_limitation && cmp(mpi.least,mpi.most) == 0) { doit_select(tb,mpi.save_term,&sc, 0 /* direction doesn't matter */); if (sc.accum != NIL) { hp=HAlloc(p, 3); RET_TO_BIF(TUPLE2(hp,sc.accum,am_EOT),DB_ERROR_NONE); } else { RET_TO_BIF(am_EOT,DB_ERROR_NONE); } } if (reverse) { 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_chunk, &sc); } else { if (mpi.some_limitation) { if ((this = find_prev_from_pb_key(tb, mpi.least)) != NULL) { lastkey = GETKEY(tb, this->dbterm.tpl); } sc.end_condition = mpi.most; } traverse_forward(tb, lastkey, &doit_select_chunk, &sc); } BUMP_REDS(p, 1000 - sc.max); if (sc.max > 0) { Eterm *hp; unsigned sz; if (sc.got < chunk_size || sc.lastobj == NULL) { /* We haven't got all and we haven't trapped which should mean we are at the end of the table, sc.lastobj may be NULL if the table was empty */ 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 + PROC_BIN_SIZE); key = copy_struct(key, sz, &hp, &MSO(p)); if (mpi.all_objects) (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS; mpb = db_make_mp_binary(p,mpi.mp,&hp); continuation = TUPLE8 (hp, tb->common.id, key, sc.end_condition, /* From the match program, needn't be copied */ make_small(chunk_size), mpb, NIL, make_small(reverse), make_small(0)); /* Don't let RET_TO_BIF macro free mpi.mp*/ *ret = bif_trap3(&ets_select_reverse_exp, p, sc.accum, NIL, continuation); return DB_ERROR_NONE; } key = GETKEY(tb, sc.lastobj); sz = size_object(key); hp = HAlloc(p, 9 + sz + PROC_BIN_SIZE); key = copy_struct(key, sz, &hp, &MSO(p)); if (mpi.all_objects) (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS; mpb = db_make_mp_binary(p,mpi.mp,&hp); continuation = TUPLE8 (hp, tb->common.id, key, sc.end_condition, /* From the match program, needn't be copied */ make_small(chunk_size), mpb, sc.accum, make_small(reverse), make_small(sc.got)); /* Don't let RET_TO_BIF macro free mpi.mp*/ *ret = bif_trap1(bif_export[BIF_ets_select_1], p, continuation); return DB_ERROR_NONE;#undef RET_TO_BIF}/*** This is called when select_delete traps*/static int db_select_delete_continue_tree(Process *p, DbTable *tbl, Eterm continuation, Eterm *ret){ DbTableTree *tb = &tbl->tree; struct select_delete_context sc; unsigned sz; Eterm *hp; Eterm lastkey; Eterm end_condition; Binary *mp; Eterm key; Eterm *tptr; Eterm eaccsum;#define RET_TO_BIF(Term, State) do { \ if (sc.erase_lastterm) { \ free_term(tb, sc.lastterm); \ } \ *ret = (Term); \ return State; \ } while(0); /* Decode continuation. We know it's correct, this can only be called by trapping */ tptr = tuple_val(continuation); lastkey = tptr[2]; end_condition = tptr[3]; sc.erase_lastterm = 0; /* Before first RET_TO_BIF */ sc.lastterm = NULL; mp = ((ProcBin *) binary_val(tptr[4]))->val; sc.p = p; sc.tb = tb; if (is_big(tptr[5])) { sc.accum = big_to_uint32(tptr[5]); } else { sc.accum = unsigned_val(tptr[5]); } sc.mp = mp; sc.end_condition = NIL; sc.max = 1000; sc.keypos = tb->common.keypos; 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); if (end_condition != NIL && cmp_partly_bound(end_condition,key) > 0) { /* done anyway */ RET_TO_BIF(erts_make_integer(sc.accum,p),DB_ERROR_NONE); } /* Not done yet, let's trap. */ sz = size_object(key); if (IS_USMALL(0, sc.accum)) { hp = HAlloc(p, sz + 6); eaccsum = make_small(sc.accum); } else { hp = HAlloc(p, BIG_UINT_HEAP_SIZE + sz + 6); eaccsum = uint_to_big(sc.accum, hp); hp += BIG_UINT_HEAP_SIZE; } key = copy_struct(key, sz, &hp, &MSO(p)); continuation = TUPLE5 (hp, tptr[1], key, tptr[3], tptr[4], eaccsum); RET_TO_BIF(bif_trap1(&ets_select_delete_continue_exp, p, continuation), DB_ERROR_NONE);#undef RET_TO_BIF}static int db_select_delete_tree(Process *p, DbTable *tbl, Eterm pattern, Eterm *ret){ DbTableTree *tb = &tbl->tree; struct select_delete_context sc; struct mp_info mpi; Eterm lastkey = NIL; Eterm key; Eterm continuation; unsigned sz; Eterm *hp; TreeDbTerm *this; int errcode; Eterm mpb; Eterm eaccsum;#define RET_TO_BIF(Term,RetVal) do { \ if (mpi.mp != NULL) { \ erts_match_set_free(mpi.mp); \ } \ if (sc.erase_lastterm) { \ free_term(tb, sc.lastterm); \ } \ *ret = (Term); \ return RetVal; \ } while(0) mpi.mp = NULL; sc.accum = 0; sc.erase_lastterm = 0; sc.lastterm = NULL; sc.p = p; sc.max = 1000; sc.end_condition = NIL; sc.keypos = tb->common.keypos; sc.tb = tb; if ((errcode = analyze_pattern(tb, pattern, &mpi)) != DB_ERROR_NONE) { RET_TO_BIF(0,errcode); } if (!mpi.something_can_match) { RET_TO_BIF(make_small(0),DB_ERROR_NONE); /* can't possibly match anything */ } sc.mp = mpi.mp; if (!mpi.got_partial && mpi.some_limitation && cmp(mpi.least,mpi.most) == 0) { doit_select_delete(tb,mpi.save_term,&sc, 0 /* direction doesn't matter */);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -