📄 bt_cursor.c
字号:
DBT *data;{ BTREE_CURSOR *cp; DB *dbp; DBT dbt; DB_MPOOLFILE *mpf; db_recno_t recno; int exact, ret; dbp = dbc->dbp; mpf = dbp->mpf; cp = (BTREE_CURSOR *)dbc->internal; /* * Get the page with the current item on it. * Get a copy of the key. * Release the page, making sure we don't release it twice. */ if ((ret = mpf->get(mpf, &cp->pgno, 0, &cp->page)) != 0) return (ret); memset(&dbt, 0, sizeof(DBT)); if ((ret = __db_ret(dbp, cp->page, cp->indx, &dbt, &dbc->rkey->data, &dbc->rkey->ulen)) != 0) goto err; ret = mpf->put(mpf, cp->page, 0); cp->page = NULL; if (ret != 0) return (ret); if ((ret = __bam_search(dbc, PGNO_INVALID, &dbt, F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND, 1, &recno, &exact)) != 0) goto err; ret = __db_retcopy(dbp->dbenv, data, &recno, sizeof(recno), &dbc->rdata->data, &dbc->rdata->ulen); /* Release the stack. */err: __bam_stkrel(dbc, 0); return (ret);}/* * __bam_c_writelock -- * Upgrade the cursor to a write lock. */static int__bam_c_writelock(dbc) DBC *dbc;{ BTREE_CURSOR *cp; int ret; cp = (BTREE_CURSOR *)dbc->internal; if (cp->lock_mode == DB_LOCK_WRITE) return (0); /* * When writing to an off-page duplicate tree, we need to have the * appropriate page in the primary tree locked. The general DBC * code calls us first with the primary cursor so we can acquire the * appropriate lock. */ ACQUIRE_WRITE_LOCK(dbc, ret); return (ret);}/* * __bam_c_first -- * Return the first record. */static int__bam_c_first(dbc) DBC *dbc;{ BTREE_CURSOR *cp; db_pgno_t pgno; int ret; cp = (BTREE_CURSOR *)dbc->internal; ret = 0; /* Walk down the left-hand side of the tree. */ for (pgno = cp->root;;) { ACQUIRE_CUR_COUPLE(dbc, DB_LOCK_READ, pgno, ret); if (ret != 0) return (ret); /* If we find a leaf page, we're done. */ if (ISLEAF(cp->page)) break; pgno = GET_BINTERNAL(dbc->dbp, cp->page, 0)->pgno; } /* If we want a write lock instead of a read lock, get it now. */ if (F_ISSET(dbc, DBC_RMW)) { ACQUIRE_WRITE_LOCK(dbc, ret); if (ret != 0) return (ret); } cp->indx = 0; /* If on an empty page or a deleted record, move to the next one. */ if (NUM_ENT(cp->page) == 0 || IS_CUR_DELETED(dbc)) if ((ret = __bam_c_next(dbc, 0, 0)) != 0) return (ret); return (0);}/* * __bam_c_last -- * Return the last record. */static int__bam_c_last(dbc) DBC *dbc;{ BTREE_CURSOR *cp; db_pgno_t pgno; int ret; cp = (BTREE_CURSOR *)dbc->internal; ret = 0; /* Walk down the right-hand side of the tree. */ for (pgno = cp->root;;) { ACQUIRE_CUR_COUPLE(dbc, DB_LOCK_READ, pgno, ret); if (ret != 0) return (ret); /* If we find a leaf page, we're done. */ if (ISLEAF(cp->page)) break; pgno = GET_BINTERNAL(dbc->dbp, cp->page, NUM_ENT(cp->page) - O_INDX)->pgno; } /* If we want a write lock instead of a read lock, get it now. */ if (F_ISSET(dbc, DBC_RMW)) { ACQUIRE_WRITE_LOCK(dbc, ret); if (ret != 0) return (ret); } cp->indx = NUM_ENT(cp->page) == 0 ? 0 : NUM_ENT(cp->page) - (TYPE(cp->page) == P_LBTREE ? P_INDX : O_INDX); /* If on an empty page or a deleted record, move to the previous one. */ if (NUM_ENT(cp->page) == 0 || IS_CUR_DELETED(dbc)) if ((ret = __bam_c_prev(dbc)) != 0) return (ret); return (0);}/* * __bam_c_next -- * Move to the next record. */static int__bam_c_next(dbc, initial_move, deleted_okay) DBC *dbc; int initial_move, deleted_okay;{ BTREE_CURSOR *cp; db_indx_t adjust; db_lockmode_t lock_mode; db_pgno_t pgno; int ret; cp = (BTREE_CURSOR *)dbc->internal; ret = 0; /* * We're either moving through a page of duplicates or a btree leaf * page. * * !!! * This code handles empty pages and pages with only deleted entries. */ if (F_ISSET(dbc, DBC_OPD)) { adjust = O_INDX; lock_mode = DB_LOCK_NG; } else { adjust = dbc->dbtype == DB_BTREE ? P_INDX : O_INDX; lock_mode = F_ISSET(dbc, DBC_RMW) ? DB_LOCK_WRITE : DB_LOCK_READ; } if (cp->page == NULL) { ACQUIRE_CUR(dbc, lock_mode, cp->pgno, ret); if (ret != 0) return (ret); } if (initial_move) cp->indx += adjust; for (;;) { /* * If at the end of the page, move to a subsequent page. * * !!! * Check for >= NUM_ENT. If the original search landed us on * NUM_ENT, we may have incremented indx before the test. */ if (cp->indx >= NUM_ENT(cp->page)) { if ((pgno = NEXT_PGNO(cp->page)) == PGNO_INVALID) return (DB_NOTFOUND); ACQUIRE_CUR(dbc, lock_mode, pgno, ret); if (ret != 0) return (ret); cp->indx = 0; continue; } if (!deleted_okay && IS_CUR_DELETED(dbc)) { cp->indx += adjust; continue; } break; } return (0);}/* * __bam_c_prev -- * Move to the previous record. */static int__bam_c_prev(dbc) DBC *dbc;{ BTREE_CURSOR *cp; db_indx_t adjust; db_lockmode_t lock_mode; db_pgno_t pgno; int ret; cp = (BTREE_CURSOR *)dbc->internal; ret = 0; /* * We're either moving through a page of duplicates or a btree leaf * page. * * !!! * This code handles empty pages and pages with only deleted entries. */ if (F_ISSET(dbc, DBC_OPD)) { adjust = O_INDX; lock_mode = DB_LOCK_NG; } else { adjust = dbc->dbtype == DB_BTREE ? P_INDX : O_INDX; lock_mode = F_ISSET(dbc, DBC_RMW) ? DB_LOCK_WRITE : DB_LOCK_READ; } if (cp->page == NULL) { ACQUIRE_CUR(dbc, lock_mode, cp->pgno, ret); if (ret != 0) return (ret); } for (;;) { /* If at the beginning of the page, move to a previous one. */ if (cp->indx == 0) { if ((pgno = PREV_PGNO(cp->page)) == PGNO_INVALID) return (DB_NOTFOUND); ACQUIRE_CUR(dbc, lock_mode, pgno, ret); if (ret != 0) return (ret); if ((cp->indx = NUM_ENT(cp->page)) == 0) continue; } /* Ignore deleted records. */ cp->indx -= adjust; if (IS_CUR_DELETED(dbc)) continue; break; } return (0);}/* * __bam_c_search -- * Move to a specified record. */static int__bam_c_search(dbc, root_pgno, key, flags, exactp) DBC *dbc; db_pgno_t root_pgno; const DBT *key; u_int32_t flags; int *exactp;{ BTREE *t; BTREE_CURSOR *cp; DB *dbp; PAGE *h; db_indx_t indx, *inp; db_pgno_t bt_lpgno; db_recno_t recno; u_int32_t sflags; int cmp, ret; dbp = dbc->dbp; cp = (BTREE_CURSOR *)dbc->internal; t = dbp->bt_internal; ret = 0; /* * Find an entry in the database. Discard any lock we currently hold, * we're going to search the tree. */ DISCARD_CUR(dbc, ret); if (ret != 0) return (ret); switch (flags) { case DB_SET_RECNO: if ((ret = __ram_getno(dbc, key, &recno, 0)) != 0) return (ret); sflags = (F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND) | S_EXACT; if ((ret = __bam_rsearch(dbc, &recno, sflags, 1, exactp)) != 0) return (ret); break; case DB_SET: case DB_GET_BOTH: sflags = (F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND) | S_EXACT; goto search; case DB_GET_BOTH_RANGE: sflags = (F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND); goto search; case DB_SET_RANGE: sflags = (F_ISSET(dbc, DBC_RMW) ? S_WRITE : S_READ) | S_DUPFIRST; goto search; case DB_KEYFIRST: sflags = S_KEYFIRST; goto fast_search; case DB_KEYLAST: case DB_NODUPDATA: sflags = S_KEYLAST;fast_search: /* * If the application has a history of inserting into the first * or last pages of the database, we check those pages first to * avoid doing a full search. * * If the tree has record numbers, we need a complete stack so * that we can adjust the record counts, so fast_search isn't * possible. */ if (F_ISSET(cp, C_RECNUM)) goto search; /* * !!! * We do not mutex protect the t->bt_lpgno field, which means * that it can only be used in an advisory manner. If we find * page we can use, great. If we don't, we don't care, we do * it the slow way instead. Regardless, copy it into a local * variable, otherwise we might acquire a lock for a page and * then read a different page because it changed underfoot. */ bt_lpgno = t->bt_lpgno; /* * If the tree has no history of insertion, do it the slow way. */ if (bt_lpgno == PGNO_INVALID) goto search; /* Lock and retrieve the page on which we last inserted. */ h = NULL; ACQUIRE(dbc, DB_LOCK_WRITE, bt_lpgno, cp->lock, bt_lpgno, h, ret); if (ret != 0) goto fast_miss; inp = P_INP(dbp, h); /* * It's okay if the page type isn't right or it's empty, it * just means that the world changed. */ if (TYPE(h) != P_LBTREE || NUM_ENT(h) == 0) goto fast_miss; /* * What we do here is test to see if we're at the beginning or * end of the tree and if the new item sorts before/after the * first/last page entry. We don't try and catch inserts into * the middle of the tree (although we could, as long as there * were two keys on the page and we saved both the index and * the page number of the last insert). */ if (h->next_pgno == PGNO_INVALID) { indx = NUM_ENT(h) - P_INDX; if ((ret = __bam_cmp(dbp, key, h, indx, t->bt_compare, &cmp)) != 0) return (ret); if (cmp < 0) goto try_begin; if (cmp > 0) { indx += P_INDX; goto fast_hit; } /* * Found a duplicate. If doing DB_KEYLAST, we're at * the correct position, otherwise, move to the first * of the duplicates. If we're looking at off-page * duplicates, duplicate duplicates aren't permitted, * so we're done. */ if (flags == DB_KEYLAST) goto fast_hit; for (; indx > 0 && inp[indx - P_INDX] == inp[indx]; indx -= P_INDX) ; goto fast_hit; }try_begin: if (h->prev_pgno == PGNO_INVALID) { indx = 0; if ((ret = __bam_cmp(dbp, key, h, indx, t->bt_compare, &cmp)) != 0) return (ret); if (cmp > 0) goto fast_miss; if (cmp < 0) goto fast_hit; /* * Found a duplicate. If doing DB_KEYFIRST, we're at * the correct position, otherwise, move to the last * of the duplicates. If we're looking at off-page * duplicates, duplicate duplicates aren't permitted, * so we're done. */ if (flags == DB_KEYFIRST) goto fast_hit; for (; indx < (db_indx_t)(NUM_ENT(h) - P_INDX) && inp[indx] == inp[indx + P_INDX]; indx += P_INDX) ; goto fast_hit; } goto fast_miss;fast_hit: /* Set the exact match flag, we may have found a duplicate. */ *exactp = cmp == 0; /* * Insert the entry in the stack. (Our caller is likely to * call __bam_stkrel() after our return.) */ BT_STK_CLR(cp); BT_STK_ENTER(dbp->dbenv, cp, h, indx, cp->lock, cp->lock_mode, ret); if (ret != 0) return (ret); break;fast_miss: /* * This was not the right page, so we do not need to retain * the lock even in the presence of transactions. */ DISCARD(dbc, 1, cp->lock, h, ret); if (ret != 0) return (ret);search: if ((ret = __bam_search(dbc, root_pgno, key, sflags, 1, NULL, exactp)) != 0) return (ret); break; default: return (__db_unknown_flag(dbp->dbenv, "__bam_c_search", flags)); } /* Initialize the cursor from the stack. */ cp->page = cp->csp->page; cp->pgno = cp->csp->page->pgno; cp->indx = cp->csp->indx; cp->lock = cp->csp->lock; cp->lock_mode = cp->csp->lock_mode; /* * If we inser
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -