📄 bt_recno.c
字号:
break; } ret = DB_NOTFOUND; goto err; /* NOTREACHED */ case DB_GET_BOTH: case DB_GET_BOTH_RANGE: /* * If we're searching a set of off-page dups, we start * a new linear search from the first record. Otherwise, * we compare the single data item associated with the * requested record for a match. */ if (F_ISSET(dbc, DBC_OPD)) { cp->recno = 1; break; } /* FALLTHROUGH */ case DB_SET: case DB_SET_RANGE: if ((ret = __ram_getno(dbc, key, &cp->recno, 0)) != 0) goto err; break; default: ret = __db_unknown_flag(dbp->dbenv, "__ram_c_get", flags); goto err; } /* * For DB_PREV, DB_LAST, DB_SET and DB_SET_RANGE, we have already * called __ram_update() to make sure sufficient records have been * read from the backing source file. Do it now for DB_CURRENT (if * the current record was deleted we may need more records from the * backing file for a DB_CURRENT operation), DB_FIRST and DB_NEXT. * (We don't have to test for flags == DB_FIRST, because the switch * statement above re-set flags to DB_NEXT in that case.) */ if ((flags == DB_NEXT || flags == DB_CURRENT) && ((ret = __ram_update(dbc, cp->recno, 0)) != 0) && ret != DB_NOTFOUND) goto err; for (;; ++cp->recno) { /* Search the tree for the record. */ if ((ret = __bam_rsearch(dbc, &cp->recno, F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND, 1, &exact)) != 0) goto err; if (!exact) { ret = DB_NOTFOUND; goto err; } /* Copy the page into the cursor. */ STACK_TO_CURSOR(cp); /* * If re-numbering records, the on-page deleted flag means this * record was implicitly created. If not re-numbering records, * the on-page deleted flag means this record was implicitly * created, or, it was deleted at some time. Regardless, we * skip such records if doing cursor next/prev operations or * walking through off-page duplicates, and fail if they were * requested explicitly by the application. */ if (B_DISSET(GET_BKEYDATA(dbp, cp->page, cp->indx)->type)) switch (flags) { case DB_NEXT: case DB_PREV: (void)__bam_stkrel(dbc, STK_CLRDBC); goto retry; case DB_GET_BOTH: case DB_GET_BOTH_RANGE: /* * If we're an OPD tree, we don't care about * matching a record number on a DB_GET_BOTH * -- everything belongs to the same tree. A * normal recno should give up and return * DB_NOTFOUND if the matching recno is deleted. */ if (F_ISSET(dbc, DBC_OPD)) { (void)__bam_stkrel(dbc, STK_CLRDBC); continue; } ret = DB_NOTFOUND; goto err; default: ret = DB_KEYEMPTY; goto err; } if (flags == DB_GET_BOTH || flags == DB_GET_BOTHC || flags == DB_GET_BOTH_RANGE) { if ((ret = __bam_cmp(dbp, data, cp->page, cp->indx, __bam_defcmp, &cmp)) != 0) return (ret); if (cmp == 0) break; if (!F_ISSET(dbc, DBC_OPD)) { ret = DB_NOTFOUND; goto err; } (void)__bam_stkrel(dbc, STK_CLRDBC); } else break; } /* Return the key if the user didn't give us one. */ if (!F_ISSET(dbc, DBC_OPD)) { if (flags != DB_GET_BOTH && flags != DB_GET_BOTH_RANGE && flags != DB_SET && flags != DB_SET_RANGE) ret = __db_retcopy(dbp->dbenv, key, &cp->recno, sizeof(cp->recno), &dbc->rkey->data, &dbc->rkey->ulen); F_SET(key, DB_DBT_ISSET); } /* The cursor was reset, no further delete adjustment is necessary. */err: CD_CLR(cp); return (ret);}/* * __ram_c_put -- * Recno cursor->c_put function. * * PUBLIC: int __ram_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); */int__ram_c_put(dbc, key, data, flags, pgnop) DBC *dbc; DBT *key, *data; u_int32_t flags; db_pgno_t *pgnop;{ BTREE_CURSOR *cp; DB *dbp; DB_LSN lsn; int exact, nc, ret, t_ret; u_int32_t iiflags; void *arg; COMPQUIET(pgnop, NULL); dbp = dbc->dbp; cp = (BTREE_CURSOR *)dbc->internal; /* * DB_KEYFIRST and DB_KEYLAST mean different things if they're * used in an off-page duplicate tree. If we're an off-page * duplicate tree, they really mean "put at the beginning of the * tree" and "put at the end of the tree" respectively, so translate * them to something else. */ if (F_ISSET(dbc, DBC_OPD)) switch (flags) { case DB_KEYFIRST: cp->recno = 1; flags = DB_BEFORE; break; case DB_KEYLAST: if ((ret = __ram_add(dbc, &cp->recno, data, DB_APPEND, 0)) != 0) return (ret); if (CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0, CA_ICURRENT, cp->root, cp->recno, cp->order))) return (ret); return (0); } /* * Handle normal DB_KEYFIRST/DB_KEYLAST; for a recno, which has * no duplicates, these are identical and mean "put the given * datum at the given recno". * * Note that the code here used to be in __ram_put; now, we * go through the access-method-common __db_put function, which * handles DB_NOOVERWRITE, so we and __ram_add don't have to. */ if (flags == DB_KEYFIRST || flags == DB_KEYLAST) { ret = __ram_getno(dbc, key, &cp->recno, 1); if (ret == 0 || ret == DB_NOTFOUND) ret = __ram_add(dbc, &cp->recno, data, 0, 0); return (ret); } /* * If we're putting with a cursor that's marked C_DELETED, we need to * take special care; the cursor doesn't "really" reference the item * corresponding to its current recno, but instead is "between" that * record and the current one. Translate the actual insert into * DB_BEFORE, and let the __ram_ca work out the gory details of what * should wind up pointing where. */ if (CD_ISSET(cp)) iiflags = DB_BEFORE; else iiflags = flags;split: if ((ret = __bam_rsearch(dbc, &cp->recno, S_INSERT, 1, &exact)) != 0) goto err; /* * An inexact match is okay; it just means we're one record past the * end, which is reasonable if we're marked deleted. */ DB_ASSERT(exact || CD_ISSET(cp)); /* Copy the page into the cursor. */ STACK_TO_CURSOR(cp); ret = __bam_iitem(dbc, key, data, iiflags, 0); t_ret = __bam_stkrel(dbc, STK_CLRDBC); if (t_ret != 0 && (ret == 0 || ret == DB_NEEDSPLIT)) ret = t_ret; else if (ret == DB_NEEDSPLIT) { arg = &cp->recno; if ((ret = __bam_split(dbc, arg, NULL)) != 0) goto err; goto split; } if (ret != 0) goto err; switch (flags) { /* Adjust the cursors. */ case DB_AFTER: nc = __ram_ca(dbc, CA_IAFTER); /* * We only need to adjust this cursor forward if we truly added * the item after the current recno, rather than remapping it * to DB_BEFORE. */ if (iiflags == DB_AFTER) ++cp->recno; /* Only log if __ram_ca found any relevant cursors. */ if (nc > 0 && CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0, CA_IAFTER, cp->root, cp->recno, cp->order)) != 0) goto err; break; case DB_BEFORE: nc = __ram_ca(dbc, CA_IBEFORE); --cp->recno; /* Only log if __ram_ca found any relevant cursors. */ if (nc > 0 && CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0, CA_IBEFORE, cp->root, cp->recno, cp->order)) != 0) goto err; break; case DB_CURRENT: /* * We only need to do an adjustment if we actually * added an item, which we only would have done if the * cursor was marked deleted. * * Only log if __ram_ca found any relevant cursors. */ if (CD_ISSET(cp) && __ram_ca(dbc, CA_ICURRENT) > 0 && CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0, CA_ICURRENT, cp->root, cp->recno, cp->order)) != 0) goto err; break; } /* Return the key if we've created a new record. */ if (!F_ISSET(dbc, DBC_OPD) && (flags == DB_AFTER || flags == DB_BEFORE)) ret = __db_retcopy(dbp->dbenv, key, &cp->recno, sizeof(cp->recno), &dbc->rkey->data, &dbc->rkey->ulen); /* The cursor was reset, no further delete adjustment is necessary. */err: CD_CLR(cp); return (ret);}/* * __ram_ca -- * Adjust cursors. Returns the number of relevant cursors. * * PUBLIC: int __ram_ca __P((DBC *, ca_recno_arg)); */int__ram_ca(dbc_arg, op) DBC *dbc_arg; ca_recno_arg op;{ BTREE_CURSOR *cp, *cp_arg; DB *dbp, *ldbp; DB_ENV *dbenv; DBC *dbc; db_recno_t recno; int adjusted, found; u_int32_t order; dbp = dbc_arg->dbp; dbenv = dbp->dbenv; cp_arg = (BTREE_CURSOR *)dbc_arg->internal; recno = cp_arg->recno; found = 0; /* * It only makes sense to adjust cursors if we're a renumbering * recno; we should only be called if this is one. */ DB_ASSERT(F_ISSET(cp_arg, C_RENUMBER)); MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); /* * Adjust the cursors. See the comment in __bam_ca_delete(). */ /* * If we're doing a delete, we need to find the highest * order of any cursor currently pointing at this item, * so we can assign a higher order to the newly deleted * cursor. Unfortunately, this requires a second pass through * the cursor list. */ if (op == CA_DELETE) { order = 1; for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; ldbp = LIST_NEXT(ldbp, dblistlinks)) { MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); for (dbc = TAILQ_FIRST(&ldbp->active_queue); dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { cp = (BTREE_CURSOR *)dbc->internal; if (cp_arg->root == cp->root && recno == cp->recno && CD_ISSET(cp) && order <= cp->order) order = cp->order + 1; } MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); } } else order = INVALID_ORDER; /* Now go through and do the actual adjustments. */ for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; ldbp = LIST_NEXT(ldbp, dblistlinks)) { MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); for (dbc = TAILQ_FIRST(&ldbp->active_queue); dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { cp = (BTREE_CURSOR *)dbc->internal; if (cp_arg->root != cp->root) continue; ++found; adjusted = 0; switch (op) { case CA_DELETE: if (recno < cp->recno) { --cp->recno; /* * If the adjustment made them equal, * we have to merge the orders. */ if (recno == cp->recno && CD_ISSET(cp)) cp->order += order; } else if (recno == cp->recno && !CD_ISSET(cp)) { CD_SET(cp); cp->order = order; } break; case CA_IBEFORE: /* * IBEFORE is just like IAFTER, except that we * adjust cursors on the current record too. */ if (C_EQUAL(cp_arg, cp)) { ++cp->recno; adjusted = 1; } goto iafter; case CA_ICURRENT: /* * If the original cursor wasn't deleted, we * just did a replacement and so there's no * need to adjust anything--we shouldn't have * gotten this far. Otherwise, we behave * much like an IAFTER, except that all * cursors pointing to the current item get * marked undeleted and point to the new * item. */ DB_ASSERT(CD_ISSET(cp_arg)); if (C_EQUAL(cp_arg, cp)) { CD_CLR(cp); break; } /* FALLTHROUGH */ case CA_IAFTER:iafter: if (!adjusted && C_LESSTHAN(cp_arg, cp)) { ++cp->recno; adjusted = 1; } if (recno == cp->recno && adjusted) /* * If we've moved this cursor's recno, * split its order number--i.e., * decrement it by enough so that * the lowest cursor moved has order 1. * cp_arg->order is the split point, * so decrement by one less than that. */ cp->order -= (cp_arg->order - 1); break; } } MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); } MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); return (found);}/* * __ram_getno -- * Check the user's record number, and make sure we've seen it. * * PUBLIC: int __ram_getno __P((DBC *, const DBT *, db_recno_t *, int)); */int__ram_getno(dbc, key, rep, can_create) DBC *dbc; const DBT *key; db_recno_t *rep; int can_create;{ DB *dbp; db_recno_t recno; dbp = dbc->dbp; /* Check the user's record number. */ if ((recno = *(db_recno_t *)key->data) == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -