2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid[] = "@(#)bt_cursor.c 10.33 (Sleepycat) 9/24/97";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
27 static int __bam_c_close __P((DBC *));
28 static int __bam_c_del __P((DBC *, int));
29 static int __bam_c_first __P((DB *, CURSOR *));
30 static int __bam_c_get __P((DBC *, DBT *, DBT *, int));
31 static int __bam_c_last __P((DB *, CURSOR *));
32 static int __bam_c_next __P((DB *, CURSOR *, int));
33 static int __bam_c_physdel __P((DB *, CURSOR *, PAGE *));
34 static int __bam_c_prev __P((DB *, CURSOR *));
35 static int __bam_c_put __P((DBC *, DBT *, DBT *, int));
36 static int __bam_c_rget __P((DB *, CURSOR *, DBT *, DBT *, int));
37 static int __bam_c_search __P((DB *, CURSOR *, const DBT *, u_int, int, int *));
39 /* Discard the current page/lock held by a cursor. */
41 #define DISCARD(dbp, cp) { \
42 (void)memp_fput(dbp->mpf, (cp)->page, 0); \
44 (void)__BT_TLPUT((dbp), (cp)->lock); \
45 (cp)->lock = LOCK_INVALID; \
50 * Interface to the cursor functions.
52 * PUBLIC: int __bam_cursor __P((DB *, DB_TXN *, DBC **));
55 __bam_cursor(dbp, txn, dbcp)
63 DEBUG_LWRITE(dbp, txn, "bam_cursor", NULL, NULL, 0);
65 if ((dbc = (DBC *)calloc(1, sizeof(DBC))) == NULL)
67 if ((cp = (CURSOR *)calloc(1, sizeof(CURSOR))) == NULL) {
73 cp->pgno = cp->dpgno = PGNO_INVALID;
74 cp->lock = LOCK_INVALID;
79 dbc->c_close = __bam_c_close;
80 dbc->c_del = __bam_c_del;
81 dbc->c_get = __bam_c_get;
82 dbc->c_put = __bam_c_put;
85 * All cursors are queued from the master DB structure. Add the
86 * cursor to that queue.
89 TAILQ_INSERT_HEAD(&dbp->curs_queue, dbc, links);
90 DB_THREAD_UNLOCK(dbp);
98 * Close a single cursor.
107 DEBUG_LWRITE(dbc->dbp, dbc->txn, "bam_c_close", NULL, NULL, 0);
109 GETHANDLE(dbc->dbp, dbc->txn, &dbp, ret);
111 ret = __bam_c_iclose(dbp, dbc);
119 * Close a single cursor -- internal version.
121 * PUBLIC: int __bam_c_iclose __P((DB *, DBC *));
124 __bam_c_iclose(dbp, dbc)
133 /* If a cursor key was deleted, perform the actual deletion. */
134 ret = F_ISSET(cp, C_DELETED) ? __bam_c_physdel(dbp, cp, NULL) : 0;
136 /* Discard any lock if we're not inside a transaction. */
137 if (cp->lock != LOCK_INVALID)
138 (void)__BT_TLPUT(dbp, cp->lock);
141 * All cursors are queued from the master DB structure. Remove the
142 * cursor from that queue.
144 DB_THREAD_LOCK(dbc->dbp);
145 TAILQ_REMOVE(&dbc->dbp->curs_queue, dbc, links);
146 DB_THREAD_UNLOCK(dbc->dbp);
148 /* Discard the structures. */
149 FREE(dbc->internal, sizeof(CURSOR));
150 FREE(dbc, sizeof(DBC));
157 * Delete using a cursor.
160 __bam_c_del(dbc, flags)
172 DEBUG_LWRITE(dbc->dbp, dbc->txn, "bam_c_del", NULL, NULL, flags);
176 /* Check for invalid flags. */
177 if ((ret = __db_cdelchk(dbc->dbp, flags,
178 F_ISSET(dbc->dbp, DB_AM_RDONLY), cp->pgno != PGNO_INVALID)) != 0)
181 /* If already deleted, return failure. */
182 if (F_ISSET(cp, C_DELETED | C_REPLACE))
183 return (DB_KEYEMPTY);
185 GETHANDLE(dbc->dbp, dbc->txn, &dbp, ret);
188 * We don't physically delete the record until the cursor moves,
189 * so we have to have a long-lived write lock on the page instead
190 * of a long-lived read lock. Note, we have to have a read lock
191 * to even get here, so we simply discard it.
193 if (F_ISSET(dbp, DB_AM_LOCKING) && cp->mode != DB_LOCK_WRITE) {
194 if ((ret = __bam_lget(dbp,
195 0, cp->pgno, DB_LOCK_WRITE, &lock)) != 0)
197 (void)__BT_TLPUT(dbp, cp->lock);
199 cp->mode = DB_LOCK_WRITE;
203 * Acquire the underlying page (which may be different from the above
204 * page because it may be a duplicate page), and set the on-page and
205 * in-cursor delete flags. We don't need to lock it as we've already
206 * write-locked the page leading to it.
208 if (cp->dpgno == PGNO_INVALID) {
216 if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)
219 /* Log the change. */
220 if (DB_LOGGING(dbp) &&
221 (ret = __bam_cdel_log(dbp->dbenv->lg_info, dbp->txn, &LSN(h),
222 0, dbp->log_fileid, PGNO(h), &LSN(h), indx)) != 0) {
223 (void)memp_fput(dbp->mpf, h, 0);
227 /* Set the intent-to-delete flag on the page and in all cursors. */
228 if (cp->dpgno == PGNO_INVALID)
229 B_DSET(GET_BKEYDATA(h, indx + O_INDX)->type);
231 B_DSET(GET_BKEYDATA(h, indx)->type);
232 (void)__bam_ca_delete(dbp, pgno, indx, NULL);
234 ret = memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY);
242 * Retrieve a key/data pair from the tree.
244 * PUBLIC: int __bam_get __P((DB *, DB_TXN *, DBT *, DBT *, int));
247 __bam_get(argdbp, txn, key, data, flags)
257 DEBUG_LREAD(argdbp, txn, "bam_get", key, NULL, flags);
259 /* Check for invalid flags. */
260 if ((ret = __db_getchk(argdbp, key, data, flags)) != 0)
263 /* Build an internal cursor. */
264 memset(&cp, 0, sizeof(cp));
266 cp.pgno = cp.dpgno = PGNO_INVALID;
267 cp.lock = LOCK_INVALID;
268 cp.flags = C_INTERNAL;
270 /* Build an external cursor. */
271 memset(&dbc, 0, sizeof(dbc));
277 return(__bam_c_get(&dbc,
278 key, data, LF_ISSET(DB_SET_RECNO) ? DB_SET_RECNO : DB_SET));
283 * Get using a cursor (btree).
286 __bam_c_get(dbc, key, data, flags)
297 DEBUG_LREAD(dbc->dbp, dbc->txn, "bam_c_get",
298 flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags);
302 /* Check for invalid flags. */
303 if ((ret = __db_cgetchk(dbc->dbp,
304 key, data, flags, cp->pgno != PGNO_INVALID)) != 0)
307 GETHANDLE(dbc->dbp, dbc->txn, &dbp, ret);
311 * Break out the code to return a cursor's record number. It
312 * has nothing to do with the cursor get code except that it's
313 * been rammed into the interface.
315 if (LF_ISSET(DB_GET_RECNO)) {
316 ret = __bam_c_rget(dbp, cp, key, data, flags);
321 /* Initialize the cursor for a new retrieval. */
324 cp->lock = LOCK_INVALID;
328 /* It's not possible to return a deleted record. */
329 if (F_ISSET(cp, C_DELETED | C_REPLACE)) {
331 return (DB_KEYEMPTY);
334 /* Get the page with the current item on it. */
335 if ((ret = __bam_pget(dbp, &cp->page, &cp->pgno, 0)) != 0)
339 if (cp->pgno != PGNO_INVALID) {
340 if ((ret = __bam_c_next(dbp, cp, 1)) != 0)
346 if ((ret = __bam_c_first(dbp, cp)) != 0)
350 if (cp->pgno != PGNO_INVALID) {
351 if ((ret = __bam_c_prev(dbp, cp)) != 0)
357 if ((ret = __bam_c_last(dbp, cp)) != 0)
363 __bam_c_search(dbp, cp, key, S_FIND, 1, &exact)) != 0)
369 __bam_c_search(dbp, cp, key, S_FIND, 0, &exact)) != 0)
375 __bam_c_search(dbp, cp, key, S_FIND, 0, &exact)) != 0)
381 * Return the key if the user didn't give us one. If we've moved to
382 * a duplicate page, we may no longer have a pointer to the main page,
383 * so we have to go get it. We know that it's already read-locked,
384 * however, so we don't have to acquire a new lock.
386 if (flags != DB_SET) {
387 if (cp->dpgno != PGNO_INVALID) {
388 if ((ret = __bam_pget(dbp, &h, &cp->pgno, 0)) != 0)
393 h, cp->indx, key, &t->bt_rkey.data, &t->bt_rkey.ulen);
394 if (cp->dpgno != PGNO_INVALID)
395 (void)memp_fput(dbp->mpf, h, 0);
400 /* Return the data. */
401 if ((ret = __db_ret(dbp, cp->page,
402 cp->dpgno == PGNO_INVALID ? cp->indx + O_INDX : cp->dindx,
403 data, &t->bt_rdata.data, &t->bt_rdata.ulen)) != 0)
407 * If the previous cursor record has been deleted, delete it. The
408 * returned key isn't a deleted key, so clear the flag.
410 if (F_ISSET(©, C_DELETED) && __bam_c_physdel(dbp, ©, cp->page))
412 F_CLR(cp, C_DELETED | C_REPLACE);
414 /* Release the previous lock, if any. */
415 if (copy.lock != LOCK_INVALID)
416 (void)__BT_TLPUT(dbp, copy.lock);
418 /* Release the pinned page. */
419 ret = memp_fput(dbp->mpf, cp->page, 0);
421 /* Internal cursors don't hold locks. */
422 if (F_ISSET(cp, C_INTERNAL) && cp->lock != LOCK_INVALID)
423 (void)__BT_TLPUT(dbp, cp->lock);
428 err: if (cp->page != NULL)
429 (void)memp_fput(dbp->mpf, cp->page, 0);
430 if (cp->lock != LOCK_INVALID)
431 (void)__BT_TLPUT(dbp, cp->lock);
441 * Return the record number for a cursor.
444 __bam_c_rget(dbp, cp, key, data, flags)
455 /* Get the page with the current item on it. */
456 if ((ret = __bam_pget(dbp, &cp->page, &cp->pgno, 0)) != 0)
459 /* Get a copy of the key. */
460 memset(&dbt, 0, sizeof(DBT));
461 dbt.flags = DB_DBT_MALLOC | DB_DBT_INTERNAL;
462 if ((ret = __db_ret(dbp, cp->page, cp->indx, &dbt, NULL, NULL)) != 0)
466 if ((ret = __bam_search(dbp, &dbt, S_FIND, 1, &recno, &exact)) != 0)
470 ret = __db_retcopy(data, &recno, sizeof(recno),
471 &t->bt_rdata.data, &t->bt_rdata.ulen, dbp->db_malloc);
473 /* Release the stack. */
476 err: (void)memp_fput(dbp->mpf, cp->page, 0);
483 * Put using a cursor.
486 __bam_c_put(dbc, key, data, flags)
497 int exact, needkey, ret;
500 DEBUG_LWRITE(dbc->dbp, dbc->txn, "bam_c_put",
501 flags == DB_KEYFIRST || flags == DB_KEYLAST ? key : NULL,
506 if ((ret = __db_cputchk(dbc->dbp, key, data, flags,
507 F_ISSET(dbc->dbp, DB_AM_RDONLY), cp->pgno != PGNO_INVALID)) != 0)
510 GETHANDLE(dbc->dbp, dbc->txn, &dbp, ret);
513 /* Initialize the cursor for a new retrieval. */
516 cp->lock = LOCK_INVALID;
519 * To split, we need a valid key for the page. Since it's a cursor,
520 * we have to build one.
523 split: if (needkey) {
524 memset(&dbt, 0, sizeof(DBT));
525 ret = __db_ret(dbp, cp->page, indx,
526 &dbt, &t->bt_rkey.data, &t->bt_rkey.ulen);
534 (void)__bam_stkrel(dbp);
537 if ((ret = __bam_split(dbp, arg)) != 0)
541 /* If there's no key supplied, use the cursor. */
542 if (flags == DB_KEYFIRST || flags == DB_KEYLAST)
546 if (cp->dpgno == PGNO_INVALID) {
553 /* Acquire the current page. */
554 if ((ret = __bam_lget(dbp,
555 0, cp->pgno, DB_LOCK_WRITE, &cp->lock)) != 0)
557 if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
566 if ((ret = __bam_iitem(dbp, &cp->page,
567 &indx, key, data, flags, 0)) == DB_NEEDSPLIT)
573 __bam_c_search(dbp, cp, key, S_KEYFIRST, 0, &exact)) != 0)
576 indx = cp->dpgno == PGNO_INVALID ? cp->indx : cp->dindx;
577 if ((ret = __bam_iitem(dbp, &cp->page, &indx, key,
578 data, DB_BEFORE, exact ? 0 : BI_NEWKEY)) == DB_NEEDSPLIT)
586 __bam_c_search(dbp, cp, key, S_KEYLAST, 0, &exact)) != 0)
589 indx = cp->dpgno == PGNO_INVALID ? cp->indx : cp->dindx;
590 if ((ret = __bam_iitem(dbp, &cp->page, &indx, key,
591 data, DB_AFTER, exact ? 0 : BI_NEWKEY)) == DB_NEEDSPLIT)
599 * Update the cursor to point to the new entry. The new entry was
600 * stored on the current page, because we split pages until it was
603 if (cp->dpgno == PGNO_INVALID)
609 * If the previous cursor record has been deleted, delete it. The
610 * returned key isn't a deleted key, so clear the flag.
612 if (F_ISSET(©, C_DELETED) &&
613 (ret = __bam_c_physdel(dbp, ©, cp->page)) != 0)
615 F_CLR(cp, C_DELETED | C_REPLACE);
617 /* Release the previous lock, if any. */
618 if (copy.lock != LOCK_INVALID)
619 (void)__BT_TLPUT(dbp, copy.lock);
621 /* Discard the pinned page. */
622 ret = memp_fput(dbp->mpf, cp->page, 0);
624 err: if (cp->page != NULL)
625 (void)memp_fput(dbp->mpf, cp->page, 0);
626 if (cp->lock != LOCK_INVALID)
627 (void)__BT_TLPUT(dbp, cp->lock);
637 * Return the first record.
640 __bam_c_first(dbp, cp)
647 /* Walk down the left-hand side of the tree. */
648 for (pgno = PGNO_ROOT;;) {
650 __bam_lget(dbp, 0, pgno, DB_LOCK_READ, &cp->lock)) != 0)
652 if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
655 /* If we find a leaf page, we're done. */
656 if (ISLEAF(cp->page))
659 pgno = GET_BINTERNAL(cp->page, 0)->pgno;
663 cp->pgno = cp->page->pgno;
665 cp->dpgno = PGNO_INVALID;
667 /* If it's an empty page or a deleted record, go to the next one. */
668 if (NUM_ENT(cp->page) == 0 ||
669 B_DISSET(GET_BKEYDATA(cp->page, cp->indx + O_INDX)->type))
670 if ((ret = __bam_c_next(dbp, cp, 0)) != 0)
673 /* If it's a duplicate reference, go to the first entry. */
674 if ((ret = __bam_ovfl_chk(dbp, cp, O_INDX, 0)) != 0)
677 /* If it's a deleted record, go to the next one. */
678 if (cp->dpgno != PGNO_INVALID &&
679 B_DISSET(GET_BKEYDATA(cp->page, cp->dindx)->type))
680 if ((ret = __bam_c_next(dbp, cp, 0)) != 0)
687 * Return the last record.
690 __bam_c_last(dbp, cp)
697 /* Walk down the right-hand side of the tree. */
698 for (pgno = PGNO_ROOT;;) {
700 __bam_lget(dbp, 0, pgno, DB_LOCK_READ, &cp->lock)) != 0)
702 if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
705 /* If we find a leaf page, we're done. */
706 if (ISLEAF(cp->page))
710 GET_BINTERNAL(cp->page, NUM_ENT(cp->page) - O_INDX)->pgno;
714 cp->pgno = cp->page->pgno;
715 cp->indx = NUM_ENT(cp->page) == 0 ? 0 : NUM_ENT(cp->page) - P_INDX;
716 cp->dpgno = PGNO_INVALID;
718 /* If it's an empty page or a deleted record, go to the previous one. */
719 if (NUM_ENT(cp->page) == 0 ||
720 B_DISSET(GET_BKEYDATA(cp->page, cp->indx + O_INDX)->type))
721 if ((ret = __bam_c_prev(dbp, cp)) != 0)
724 /* If it's a duplicate reference, go to the last entry. */
725 if ((ret = __bam_ovfl_chk(dbp, cp, cp->indx + O_INDX, 1)) != 0)
728 /* If it's a deleted record, go to the previous one. */
729 if (cp->dpgno != PGNO_INVALID &&
730 B_DISSET(GET_BKEYDATA(cp->page, cp->dindx)->type))
731 if ((ret = __bam_c_prev(dbp, cp)) != 0)
738 * Move to the next record.
741 __bam_c_next(dbp, cp, initial_move)
746 db_indx_t adjust, indx;
751 * We're either moving through a page of duplicates or a btree leaf
754 if (cp->dpgno == PGNO_INVALID) {
755 adjust = dbp->type == DB_BTREE ? P_INDX : O_INDX;
763 if (cp->page == NULL) {
765 __bam_lget(dbp, 0, pgno, DB_LOCK_READ, &cp->lock)) != 0)
767 if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
772 * If at the end of the page, move to a subsequent page.
775 * Check for >= NUM_ENT. If we're here as the result of a search that
776 * landed us on NUM_ENT, we'll increment indx before we test.
779 * This code handles empty pages and pages with only deleted entries.
784 if (indx >= NUM_ENT(cp->page)) {
785 pgno = cp->page->next_pgno;
789 * If we're in a btree leaf page, we've reached the end
790 * of the tree. If we've reached the end of a page of
791 * duplicates, continue from the btree leaf page where
792 * we found this page of duplicates.
794 if (pgno == PGNO_INVALID) {
795 /* If in a btree leaf page, it's EOF. */
796 if (cp->dpgno == PGNO_INVALID)
797 return (DB_NOTFOUND);
799 /* Continue from the last btree leaf page. */
800 cp->dpgno = PGNO_INVALID;
804 indx = cp->indx + P_INDX;
808 if ((ret = __bam_lget(dbp,
809 0, pgno, DB_LOCK_READ, &cp->lock)) != 0)
811 if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
816 /* Ignore deleted records. */
817 if (dbp->type == DB_BTREE &&
818 ((cp->dpgno == PGNO_INVALID &&
819 B_DISSET(GET_BKEYDATA(cp->page, indx + O_INDX)->type)) ||
820 (cp->dpgno != PGNO_INVALID &&
821 B_DISSET(GET_BKEYDATA(cp->page, indx)->type)))) {
827 * If we're not in a duplicates page, check to see if we've
828 * found a page of duplicates, in which case we move to the
831 if (cp->dpgno == PGNO_INVALID) {
832 cp->pgno = cp->page->pgno;
836 __bam_ovfl_chk(dbp, cp, indx + O_INDX, 0)) != 0)
838 if (cp->dpgno != PGNO_INVALID) {
844 cp->dpgno = cp->page->pgno;
854 * Move to the previous record.
857 __bam_c_prev(dbp, cp)
861 db_indx_t indx, adjust;
866 * We're either moving through a page of duplicates or a btree leaf
869 if (cp->dpgno == PGNO_INVALID) {
870 adjust = dbp->type == DB_BTREE ? P_INDX : O_INDX;
878 if (cp->page == NULL) {
880 __bam_lget(dbp, 0, pgno, DB_LOCK_READ, &cp->lock)) != 0)
882 if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
887 * If at the beginning of the page, move to any previous one.
890 * This code handles empty pages and pages with only deleted entries.
894 pgno = cp->page->prev_pgno;
898 * If we're in a btree leaf page, we've reached the
899 * beginning of the tree. If we've reached the first
900 * of a page of duplicates, continue from the btree
901 * leaf page where we found this page of duplicates.
903 if (pgno == PGNO_INVALID) {
904 /* If in a btree leaf page, it's SOF. */
905 if (cp->dpgno == PGNO_INVALID)
906 return (DB_NOTFOUND);
908 /* Continue from the last btree leaf page. */
909 cp->dpgno = PGNO_INVALID;
918 if ((ret = __bam_lget(dbp,
919 0, pgno, DB_LOCK_READ, &cp->lock)) != 0)
921 if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
925 indx = NUM_ENT(cp->page);
930 /* Ignore deleted records. */
932 if (dbp->type == DB_BTREE &&
933 ((cp->dpgno == PGNO_INVALID &&
934 B_DISSET(GET_BKEYDATA(cp->page, indx + O_INDX)->type)) ||
935 (cp->dpgno != PGNO_INVALID &&
936 B_DISSET(GET_BKEYDATA(cp->page, indx)->type))))
940 * If we're not in a duplicates page, check to see if we've
941 * found a page of duplicates, in which case we move to the
944 if (cp->dpgno == PGNO_INVALID) {
945 cp->pgno = cp->page->pgno;
949 __bam_ovfl_chk(dbp, cp, indx + O_INDX, 1)) != 0)
951 if (cp->dpgno != PGNO_INVALID) {
952 indx = cp->dindx + O_INDX;
957 cp->dpgno = cp->page->pgno;
967 * Move to a specified record.
970 __bam_c_search(dbp, cp, key, flags, isrecno, exactp)
975 int isrecno, *exactp;
985 * Find any matching record; the search function pins the page. Make
986 * sure it's a valid key (__bam_search may return an index just past
987 * the end of a page) and return it.
990 if ((ret = __ram_getno(dbp, key, &recno, 0)) != 0)
992 ret = __bam_rsearch(dbp, &recno, flags, 1, exactp);
994 ret = __bam_search(dbp, key, flags, 1, NULL, exactp);
998 cp->page = t->bt_csp->page;
999 cp->pgno = cp->page->pgno;
1000 cp->indx = t->bt_csp->indx;
1001 cp->lock = t->bt_csp->lock;
1002 cp->dpgno = PGNO_INVALID;
1005 * If we have an exact match, make sure that we're not looking at a
1006 * chain of duplicates -- if so, move to an entry in that chain.
1009 if ((ret = __bam_ovfl_chk(dbp,
1010 cp, cp->indx + O_INDX, LF_ISSET(S_DUPLAST))) != 0)
1014 return (DB_NOTFOUND);
1016 /* If past the end of a page, find the next entry. */
1017 if (cp->indx == NUM_ENT(cp->page) &&
1018 (ret = __bam_c_next(dbp, cp, 0)) != 0)
1021 /* If it's a deleted record, go to the next or previous one. */
1022 if (cp->dpgno != PGNO_INVALID &&
1023 B_DISSET(GET_BKEYDATA(cp->page, cp->dindx)->type))
1024 if (flags == S_KEYLAST) {
1025 if ((ret = __bam_c_prev(dbp, cp)) != 0)
1028 if ((ret = __bam_c_next(dbp, cp, 0)) != 0)
1035 * Check for an overflow record, and if found, move to the correct
1038 * PUBLIC: int __bam_ovfl_chk __P((DB *, CURSOR *, u_int32_t, int));
1041 __bam_ovfl_chk(dbp, cp, indx, to_end)
1051 /* Check for an overflow entry. */
1052 bo = GET_BOVERFLOW(cp->page, indx);
1053 if (B_TYPE(bo->type) != B_DUPLICATE)
1057 * If we find one, go to the duplicates page, and optionally move
1058 * to the last record on that page.
1061 * We don't lock duplicates pages, we've already got the correct
1062 * lock on the main page.
1065 if ((ret = memp_fput(dbp->mpf, cp->page, 0)) != 0)
1069 if ((ret = __db_dend(dbp, pgno, &cp->page)) != 0)
1071 indx = NUM_ENT(cp->page) - O_INDX;
1073 if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
1078 /* Update the duplicate entry in the cursor. */
1079 cp->dpgno = cp->page->pgno;
1088 * Display the current btree cursor list.
1097 DB_THREAD_LOCK(dbp);
1098 for (dbc = TAILQ_FIRST(&dbp->curs_queue);
1099 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1100 cp = (CURSOR *)dbc->internal;
1102 "%#0x: page: %lu index: %lu dpage %lu dindex: %lu",
1103 (u_int)cp, (u_long)cp->pgno, (u_long)cp->indx,
1104 (u_long)cp->dpgno, (u_long)cp->dindx);
1105 if (F_ISSET(cp, C_DELETED))
1106 fprintf(stderr, "(deleted)");
1107 fprintf(stderr, "\n");
1109 DB_THREAD_UNLOCK(dbp);
1115 * __bam_ca_delete --
1116 * Check if any of the cursors refer to the item we are about to delete.
1117 * We'll return the number of cursors that refer to the item in question.
1118 * If a cursor does refer to the item, then we set its deleted bit.
1120 * PUBLIC: int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, CURSOR *));
1123 __bam_ca_delete(dbp, pgno, indx, curs)
1134 * Adjust the cursors. We don't have to review the cursors for any
1135 * process other than the current one, because we have the page write
1136 * locked at this point, and any other process had better be using a
1137 * different locker ID, meaning that only cursors in our process can
1140 * It's possible for multiple cursors within the thread to have write
1141 * locks on the same page, but, cursors within a thread must be single
1142 * threaded, so all we're locking here is the cursor linked list.
1144 * indx refers to the first of what might be a duplicate set. The
1145 * cursor passed in is the one initiating the delete, so we don't
1148 DB_THREAD_LOCK(dbp);
1149 for (count = 0, dbc = TAILQ_FIRST(&dbp->curs_queue);
1150 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1151 cp = (CURSOR *)dbc->internal;
1153 cp->pgno == pgno && cp->indx == indx) ||
1154 (cp->dpgno == pgno && cp->dindx == indx)) {
1156 F_SET(cp, C_DELETED);
1159 DB_THREAD_UNLOCK(dbp);
1165 * Adjust the cursors during a delete or insert.
1167 * PUBLIC: void __bam_ca_di __P((DB *, db_pgno_t, u_int32_t, int));
1170 __bam_ca_di(dbp, pgno, indx, value)
1179 /* Recno is responsible for its own adjustments. */
1180 if (dbp->type == DB_RECNO)
1184 * Adjust the cursors. See the comment in __bam_ca_delete().
1186 DB_THREAD_LOCK(dbp);
1187 for (dbc = TAILQ_FIRST(&dbp->curs_queue);
1188 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1189 cp = (CURSOR *)dbc->internal;
1190 if (cp->pgno == pgno && cp->indx >= indx)
1192 if (cp->dpgno == pgno && cp->dindx >= indx)
1195 DB_THREAD_UNLOCK(dbp);
1200 * Adjust the cursors when moving data items to a duplicates page.
1202 * PUBLIC: void __bam_ca_dup __P((DB *,
1203 * PUBLIC: db_pgno_t, u_int32_t, u_int32_t, db_pgno_t, u_int32_t));
1206 __bam_ca_dup(dbp, fpgno, first, fi, tpgno, ti)
1208 db_pgno_t fpgno, tpgno;
1209 u_int32_t first, fi, ti;
1215 * Adjust the cursors. See the comment in __bam_ca_delete().
1217 * No need to test duplicates, this only gets called when moving
1218 * leaf page data items onto a duplicates page.
1220 DB_THREAD_LOCK(dbp);
1221 for (dbc = TAILQ_FIRST(&dbp->curs_queue);
1222 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1223 cp = (CURSOR *)dbc->internal;
1225 * Ignore matching entries that have already been moved,
1226 * we move from the same location on the leaf page more
1229 if (cp->dpgno == PGNO_INVALID &&
1230 cp->pgno == fpgno && cp->indx == fi) {
1236 DB_THREAD_UNLOCK(dbp);
1241 * Adjust the cursors when moving data items to another page.
1243 * PUBLIC: void __bam_ca_move __P((DB *, BTREE *, db_pgno_t, db_pgno_t));
1246 __bam_ca_move(dbp, t, fpgno, tpgno)
1249 db_pgno_t fpgno, tpgno;
1254 /* Recno is responsible for its own adjustments. */
1255 if (dbp->type == DB_RECNO)
1259 * Adjust the cursors. See the comment in __bam_ca_delete().
1261 * No need to test duplicates, this only gets called when copying
1262 * over the root page with a leaf or internal page.
1264 DB_THREAD_LOCK(dbp);
1265 for (dbc = TAILQ_FIRST(&dbp->curs_queue);
1266 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1267 cp = (CURSOR *)dbc->internal;
1268 if (cp->pgno == fpgno)
1271 DB_THREAD_UNLOCK(dbp);
1275 * __bam_ca_replace --
1276 * Check if any of the cursors refer to the item we are about to replace.
1277 * If so, their flags should be changed from deleted to replaced.
1279 * PUBLIC: void __bam_ca_replace
1280 * PUBLIC: __P((DB *, db_pgno_t, u_int32_t, ca_replace_arg));
1283 __bam_ca_replace(dbp, pgno, indx, pass)
1287 ca_replace_arg pass;
1293 * Adjust the cursors. See the comment in __bam_ca_delete().
1295 * Find any cursors that have logically deleted a record we're about
1298 * Pass == REPLACE_SETUP:
1299 * Set C_REPLACE_SETUP so we can find the cursors again.
1301 * Pass == REPLACE_SUCCESS:
1302 * Clear C_DELETED and C_REPLACE_SETUP, set C_REPLACE, the
1303 * overwrite was successful.
1305 * Pass == REPLACE_FAILED:
1306 * Clear C_REPLACE_SETUP, the overwrite failed.
1308 * For REPLACE_SUCCESS and REPLACE_FAILED, we reset the indx value
1309 * for the cursor as it may have been changed by other cursor update
1310 * routines as the item was deleted/inserted.
1312 DB_THREAD_LOCK(dbp);
1314 case REPLACE_SETUP: /* Setup. */
1315 for (dbc = TAILQ_FIRST(&dbp->curs_queue);
1316 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1317 cp = (CURSOR *)dbc->internal;
1318 if ((cp->pgno == pgno && cp->indx == indx) ||
1319 (cp->dpgno == pgno && cp->dindx == indx))
1320 F_SET(cp, C_REPLACE_SETUP);
1323 case REPLACE_SUCCESS: /* Overwrite succeeded. */
1324 for (dbc = TAILQ_FIRST(&dbp->curs_queue);
1325 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1326 cp = (CURSOR *)dbc->internal;
1327 if (F_ISSET(cp, C_REPLACE_SETUP)) {
1328 if (cp->dpgno == pgno)
1330 if (cp->pgno == pgno)
1332 F_SET(cp, C_REPLACE);
1333 F_CLR(cp, C_DELETED | C_REPLACE_SETUP);
1337 case REPLACE_FAILED: /* Overwrite failed. */
1338 for (dbc = TAILQ_FIRST(&dbp->curs_queue);
1339 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1340 cp = (CURSOR *)dbc->internal;
1341 if (F_ISSET(cp, C_REPLACE_SETUP)) {
1342 if (cp->dpgno == pgno)
1344 if (cp->pgno == pgno)
1346 F_CLR(cp, C_REPLACE_SETUP);
1351 DB_THREAD_UNLOCK(dbp);
1356 * Adjust the cursors when splitting a page.
1358 * PUBLIC: void __bam_ca_split __P((DB *,
1359 * PUBLIC: db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int));
1362 __bam_ca_split(dbp, ppgno, lpgno, rpgno, split_indx, cleft)
1364 db_pgno_t ppgno, lpgno, rpgno;
1365 u_int32_t split_indx;
1371 /* Recno is responsible for its own adjustments. */
1372 if (dbp->type == DB_RECNO)
1376 * Adjust the cursors. See the comment in __bam_ca_delete().
1378 * If splitting the page that a cursor was on, the cursor has to be
1379 * adjusted to point to the same record as before the split. Most
1380 * of the time we don't adjust pointers to the left page, because
1381 * we're going to copy its contents back over the original page. If
1382 * the cursor is on the right page, it is decremented by the number of
1383 * records split to the left page.
1385 DB_THREAD_LOCK(dbp);
1386 for (dbc = TAILQ_FIRST(&dbp->curs_queue);
1387 dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
1388 cp = (CURSOR *)dbc->internal;
1389 if (cp->pgno == ppgno)
1390 if (cp->indx < split_indx) {
1395 cp->indx -= split_indx;
1397 if (cp->dpgno == ppgno)
1398 if (cp->dindx < split_indx) {
1403 cp->dindx -= split_indx;
1406 DB_THREAD_UNLOCK(dbp);
1410 * __bam_c_physdel --
1411 * Actually do the cursor deletion.
1414 __bam_c_physdel(dbp, cp, h)
1424 db_pgno_t pgno, next_pgno, prev_pgno;
1430 /* Figure out what we're deleting. */
1431 if (cp->dpgno == PGNO_INVALID) {
1440 * If the item is referenced by another cursor, leave it up to that
1441 * cursor to do the delete.
1443 if (__bam_ca_delete(dbp, pgno, indx, cp) != 0)
1447 * If we don't already have the page locked, get it and delete the
1450 if ((h == NULL || h->pgno != pgno)) {
1451 if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_WRITE, &lock)) != 0)
1453 if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)
1460 * If we're deleting a duplicate entry, call the common code to do
1463 if (TYPE(h) == P_DUPLICATE) {
1465 prev_pgno = PREV_PGNO(h);
1466 next_pgno = NEXT_PGNO(h);
1467 if ((ret = __db_drem(dbp, &h, indx, __bam_free)) != 0)
1471 * There are 4 cases:
1473 * 1. We removed an item on a page, but there are more items
1475 * 2. We removed the last item on a page, removing the last
1477 * 3. We removed the last item on a page, but there is a
1478 * following page of duplicates.
1479 * 4. We removed the last item on a page, but there is a
1480 * previous page of duplicates.
1482 * In case 1, h != NULL, h->pgno == pgno
1483 * In case 2, h == NULL,
1484 * prev_pgno == PGNO_INVALID, next_pgno == PGNO_INVALID
1485 * In case 3, h != NULL, next_pgno != PGNO_INVALID
1486 * In case 4, h == NULL, prev_pgno != PGNO_INVALID
1488 * In case 1, there's nothing else to do.
1489 * In case 2, remove the entry from the parent page.
1490 * In case 3 or 4, if the deleted page was the first in a chain
1491 * of duplicate pages, update the parent page's entry.
1494 * If there were previous pages of duplicates or we didn't
1495 * empty the current page of duplicates, we don't need to
1496 * touch the parent page.
1498 if (prev_pgno != PGNO_INVALID || (h != NULL && pgno == h->pgno))
1502 * Release any page we're holding and the lock on the deleted
1507 (void)memp_fput(dbp->mpf, h, 0);
1508 (void)__BT_TLPUT(dbp, lock);
1512 /* Acquire the parent page. */
1514 __bam_lget(dbp, 0, cp->pgno, DB_LOCK_WRITE, &lock)) != 0)
1516 if ((ret = __bam_pget(dbp, &h, &cp->pgno, 0)) != 0) {
1517 (void)__BT_TLPUT(dbp, lock);
1523 * If we deleted the last duplicate, we can fall out and do a
1524 * normal btree delete in the context of the parent page. If
1525 * not, we have to update the parent's page.
1528 if (next_pgno != PGNO_INVALID) {
1530 * Copy, delete, update and re-insert the parent page's
1533 bo = *GET_BOVERFLOW(h, indx);
1534 (void)__db_ditem(dbp, h, indx, BOVERFLOW_SIZE);
1535 bo.pgno = next_pgno;
1536 memset(&dbt, 0, sizeof(dbt));
1538 dbt.size = BOVERFLOW_SIZE;
1539 (void)__db_pitem(dbp,
1540 h, indx, BOVERFLOW_SIZE, &dbt, NULL);
1542 /* Discard the parent page. */
1543 (void)memp_fput(dbp->mpf, h, 0);
1544 (void)__BT_TLPUT(dbp, lock);
1551 /* Otherwise, do a normal btree delete. */
1552 if ((ret = __bam_ditem(dbp, h, indx)) != 0)
1554 if ((ret = __bam_ditem(dbp, h, indx)) != 0)
1558 * If the page is empty, delete it. To delete a leaf page we need a
1559 * copy of a key from the page. We use the first one that was there,
1560 * since it's the last key that the page held. We malloc the page
1561 * information instead of using the return key/data memory because
1562 * we've already set them -- the reason that we've already set them
1563 * is because we're (potentially) about to do a reverse split, which
1564 * would make our saved page information useless.
1567 * The following operations to delete a page might deadlock. I think
1568 * that's OK. The problem is if we're deleting an item because we're
1569 * closing cursors because we've already deadlocked and want to call
1570 * txn_abort(). If we fail due to deadlock, we'll leave an locked
1571 * empty page in the tree, which won't be empty long because we're
1572 * going to undo the delete.
1574 if (NUM_ENT(h) == 0 && h->pgno != PGNO_ROOT) {
1575 memset(&dbt, 0, sizeof(DBT));
1576 dbt.flags = DB_DBT_MALLOC | DB_DBT_INTERNAL;
1577 if ((ret = __db_ret(dbp, h, 0, &dbt, NULL, NULL)) != 0)
1581 (void)memp_fput(dbp->mpf, h, 0);
1582 (void)__BT_TLPUT(dbp, lock);
1586 ret = __bam_dpage(dbp, &dbt);
1592 (void)memp_fput(dbp->mpf, h, 0);
1593 (void)__BT_TLPUT(dbp, lock);
1597 ++t->lstat.bt_deleted;