xref: /netbsd-src/lib/libc/db/btree/bt_delete.c (revision aae80e6be7bf8e6ad43f8b63d296d2d3923c4ee5)
1*aae80e6bSchristos /*	$NetBSD: bt_delete.c,v 1.19 2016/09/24 21:31:25 christos Exp $	*/
2a954b078Scgd 
39f0aa214Scgd /*-
4a6d14e36Scgd  * Copyright (c) 1990, 1993, 1994
59f0aa214Scgd  *	The Regents of the University of California.  All rights reserved.
69f0aa214Scgd  *
79f0aa214Scgd  * This code is derived from software contributed to Berkeley by
89f0aa214Scgd  * Mike Olson.
99f0aa214Scgd  *
109f0aa214Scgd  * Redistribution and use in source and binary forms, with or without
119f0aa214Scgd  * modification, are permitted provided that the following conditions
129f0aa214Scgd  * are met:
139f0aa214Scgd  * 1. Redistributions of source code must retain the above copyright
149f0aa214Scgd  *    notice, this list of conditions and the following disclaimer.
159f0aa214Scgd  * 2. Redistributions in binary form must reproduce the above copyright
169f0aa214Scgd  *    notice, this list of conditions and the following disclaimer in the
179f0aa214Scgd  *    documentation and/or other materials provided with the distribution.
18eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
199f0aa214Scgd  *    may be used to endorse or promote products derived from this software
209f0aa214Scgd  *    without specific prior written permission.
219f0aa214Scgd  *
229f0aa214Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239f0aa214Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249f0aa214Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259f0aa214Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269f0aa214Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279f0aa214Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289f0aa214Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299f0aa214Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309f0aa214Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319f0aa214Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329f0aa214Scgd  * SUCH DAMAGE.
339f0aa214Scgd  */
349f0aa214Scgd 
35d3595ddfSjoerg #if HAVE_NBTOOL_CONFIG_H
36d3595ddfSjoerg #include "nbtool_config.h"
37d3595ddfSjoerg #endif
38d3595ddfSjoerg 
3900ae392dSchristos #include <sys/cdefs.h>
40*aae80e6bSchristos __RCSID("$NetBSD: bt_delete.c,v 1.19 2016/09/24 21:31:25 christos Exp $");
419f0aa214Scgd 
4243fa6fe3Sjtc #include "namespace.h"
439f0aa214Scgd #include <sys/types.h>
449f0aa214Scgd 
45cb9daf8fSchristos #include <assert.h>
469f0aa214Scgd #include <errno.h>
479f0aa214Scgd #include <stdio.h>
489f0aa214Scgd #include <string.h>
499f0aa214Scgd 
509f0aa214Scgd #include <db.h>
519f0aa214Scgd #include "btree.h"
529f0aa214Scgd 
53cb9daf8fSchristos static int __bt_bdelete(BTREE *, const DBT *);
54cb9daf8fSchristos static int __bt_curdel(BTREE *, const DBT *, PAGE *, u_int);
55cb9daf8fSchristos static int __bt_pdelete(BTREE *, PAGE *);
56cb9daf8fSchristos static int __bt_stkacq(BTREE *, PAGE **, CURSOR *);
579f0aa214Scgd 
589f0aa214Scgd /*
5924420c01Scgd  * __bt_delete
6024420c01Scgd  *	Delete the item(s) referenced by a key.
619f0aa214Scgd  *
6224420c01Scgd  * Return RET_SPECIAL if the key is not found.
639f0aa214Scgd  */
649f0aa214Scgd int
__bt_delete(const DB * dbp,const DBT * key,u_int flags)65cb9daf8fSchristos __bt_delete(const DB *dbp, const DBT *key, u_int flags)
669f0aa214Scgd {
679f0aa214Scgd 	BTREE *t;
6824420c01Scgd 	CURSOR *c;
6924420c01Scgd 	PAGE *h;
709f0aa214Scgd 	int status;
719f0aa214Scgd 
729f0aa214Scgd 	t = dbp->internal;
7345e27c80Scgd 
7445e27c80Scgd 	/* Toss any page pinned across calls. */
7545e27c80Scgd 	if (t->bt_pinned != NULL) {
7645e27c80Scgd 		mpool_put(t->bt_mp, t->bt_pinned, 0);
7745e27c80Scgd 		t->bt_pinned = NULL;
7845e27c80Scgd 	}
7945e27c80Scgd 
8024420c01Scgd 	/* Check for change to a read-only tree. */
8124420c01Scgd 	if (F_ISSET(t, B_RDONLY)) {
829f0aa214Scgd 		errno = EPERM;
839f0aa214Scgd 		return (RET_ERROR);
849f0aa214Scgd 	}
8545e27c80Scgd 
869f0aa214Scgd 	switch (flags) {
879f0aa214Scgd 	case 0:
8824420c01Scgd 		status = __bt_bdelete(t, key);
899f0aa214Scgd 		break;
909f0aa214Scgd 	case R_CURSOR:
919f0aa214Scgd 		/*
9224420c01Scgd 		 * If flags is R_CURSOR, delete the cursor.  Must already
9324420c01Scgd 		 * have started a scan and not have already deleted it.
949f0aa214Scgd 		 */
9524420c01Scgd 		c = &t->bt_cursor;
9624420c01Scgd 		if (F_ISSET(c, CURS_INIT)) {
9724420c01Scgd 			if (F_ISSET(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
9824420c01Scgd 				return (RET_SPECIAL);
99*aae80e6bSchristos 			if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
10024420c01Scgd 				return (RET_ERROR);
10124420c01Scgd 
10224420c01Scgd 			/*
10324420c01Scgd 			 * If the page is about to be emptied, we'll need to
10424420c01Scgd 			 * delete it, which means we have to acquire a stack.
10524420c01Scgd 			 */
10624420c01Scgd 			if (NEXTINDEX(h) == 1)
10724420c01Scgd 				if (__bt_stkacq(t, &h, &t->bt_cursor))
10824420c01Scgd 					return (RET_ERROR);
10924420c01Scgd 
11061238e71Schristos 			status = __bt_dleaf(t, NULL, h, (u_int)c->pg.index);
11124420c01Scgd 
11224420c01Scgd 			if (NEXTINDEX(h) == 0 && status == RET_SUCCESS) {
11324420c01Scgd 				if (__bt_pdelete(t, h))
11424420c01Scgd 					return (RET_ERROR);
11524420c01Scgd 			} else
11661238e71Schristos 				mpool_put(t->bt_mp, h,
11761238e71Schristos 				    (u_int)(status == RET_SUCCESS ?
11861238e71Schristos 				    MPOOL_DIRTY : 0));
1199f0aa214Scgd 			break;
12024420c01Scgd 		}
12124420c01Scgd 		/* FALLTHROUGH */
1229f0aa214Scgd 	default:
12324420c01Scgd 		errno = EINVAL;
1249f0aa214Scgd 		return (RET_ERROR);
1259f0aa214Scgd 	}
1269f0aa214Scgd 	if (status == RET_SUCCESS)
12724420c01Scgd 		F_SET(t, B_MODIFIED);
1289f0aa214Scgd 	return (status);
1299f0aa214Scgd }
1309f0aa214Scgd 
1319f0aa214Scgd /*
13224420c01Scgd  * __bt_stkacq --
13324420c01Scgd  *	Acquire a stack so we can delete a cursor entry.
1349f0aa214Scgd  *
1359f0aa214Scgd  * Parameters:
13624420c01Scgd  *	  t:	tree
13724420c01Scgd  *	 hp:	pointer to current, pinned PAGE pointer
13824420c01Scgd  *	  c:	pointer to the cursor
13924420c01Scgd  *
14024420c01Scgd  * Returns:
14124420c01Scgd  *	0 on success, 1 on failure
14224420c01Scgd  */
14324420c01Scgd static int
__bt_stkacq(BTREE * t,PAGE ** hp,CURSOR * c)144cb9daf8fSchristos __bt_stkacq(BTREE *t, PAGE **hp, CURSOR *c)
14524420c01Scgd {
14624420c01Scgd 	BINTERNAL *bi;
14724420c01Scgd 	EPG *e;
14824420c01Scgd 	EPGNO *parent;
14924420c01Scgd 	PAGE *h;
15061238e71Schristos 	indx_t idx = 0;	/* Pacify gcc */
15124420c01Scgd 	pgno_t pgno;
15224420c01Scgd 	recno_t nextpg, prevpg;
15324420c01Scgd 	int exact, level;
15424420c01Scgd 
15524420c01Scgd 	/*
15624420c01Scgd 	 * Find the first occurrence of the key in the tree.  Toss the
15724420c01Scgd 	 * currently locked page so we don't hit an already-locked page.
15824420c01Scgd 	 */
15924420c01Scgd 	h = *hp;
16024420c01Scgd 	mpool_put(t->bt_mp, h, 0);
16124420c01Scgd 	if ((e = __bt_search(t, &c->key, &exact)) == NULL)
16224420c01Scgd 		return (1);
16324420c01Scgd 	h = e->page;
16424420c01Scgd 
16524420c01Scgd 	/* See if we got it in one shot. */
16624420c01Scgd 	if (h->pgno == c->pg.pgno)
16724420c01Scgd 		goto ret;
16824420c01Scgd 
16924420c01Scgd 	/*
17024420c01Scgd 	 * Move right, looking for the page.  At each move we have to move
17124420c01Scgd 	 * up the stack until we don't have to move to the next page.  If
17224420c01Scgd 	 * we have to change pages at an internal level, we have to fix the
17324420c01Scgd 	 * stack back up.
17424420c01Scgd 	 */
17524420c01Scgd 	while (h->pgno != c->pg.pgno) {
17624420c01Scgd 		if ((nextpg = h->nextpg) == P_INVALID)
17724420c01Scgd 			break;
17824420c01Scgd 		mpool_put(t->bt_mp, h, 0);
17924420c01Scgd 
18024420c01Scgd 		/* Move up the stack. */
18124420c01Scgd 		for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
18224420c01Scgd 			/* Get the parent page. */
183*aae80e6bSchristos 			if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
18424420c01Scgd 				return (1);
18524420c01Scgd 
18624420c01Scgd 			/* Move to the next index. */
18724420c01Scgd 			if (parent->index != NEXTINDEX(h) - 1) {
18861238e71Schristos 				idx = parent->index + 1;
18961238e71Schristos 				BT_PUSH(t, h->pgno, idx);
19024420c01Scgd 				break;
19124420c01Scgd 			}
19224420c01Scgd 			mpool_put(t->bt_mp, h, 0);
19324420c01Scgd 		}
19424420c01Scgd 
19524420c01Scgd 		/* Restore the stack. */
19624420c01Scgd 		while (level--) {
19724420c01Scgd 			/* Push the next level down onto the stack. */
19861238e71Schristos 			bi = GETBINTERNAL(h, idx);
19924420c01Scgd 			pgno = bi->pgno;
20024420c01Scgd 			BT_PUSH(t, pgno, 0);
20124420c01Scgd 
20224420c01Scgd 			/* Lose the currently pinned page. */
20324420c01Scgd 			mpool_put(t->bt_mp, h, 0);
20424420c01Scgd 
20524420c01Scgd 			/* Get the next level down. */
206*aae80e6bSchristos 			if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
20724420c01Scgd 				return (1);
20861238e71Schristos 			idx = 0;
20924420c01Scgd 		}
21024420c01Scgd 		mpool_put(t->bt_mp, h, 0);
211*aae80e6bSchristos 		if ((h = mpool_get(t->bt_mp, nextpg, 0)) == NULL)
21224420c01Scgd 			return (1);
21324420c01Scgd 	}
21424420c01Scgd 
21524420c01Scgd 	if (h->pgno == c->pg.pgno)
21624420c01Scgd 		goto ret;
21724420c01Scgd 
21824420c01Scgd 	/* Reacquire the original stack. */
21924420c01Scgd 	mpool_put(t->bt_mp, h, 0);
22024420c01Scgd 	if ((e = __bt_search(t, &c->key, &exact)) == NULL)
22124420c01Scgd 		return (1);
22224420c01Scgd 	h = e->page;
22324420c01Scgd 
22424420c01Scgd 	/*
22524420c01Scgd 	 * Move left, looking for the page.  At each move we have to move
22624420c01Scgd 	 * up the stack until we don't have to change pages to move to the
22724420c01Scgd 	 * next page.  If we have to change pages at an internal level, we
22824420c01Scgd 	 * have to fix the stack back up.
22924420c01Scgd 	 */
23024420c01Scgd 	while (h->pgno != c->pg.pgno) {
23124420c01Scgd 		if ((prevpg = h->prevpg) == P_INVALID)
23224420c01Scgd 			break;
23324420c01Scgd 		mpool_put(t->bt_mp, h, 0);
23424420c01Scgd 
23524420c01Scgd 		/* Move up the stack. */
23624420c01Scgd 		for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
23724420c01Scgd 			/* Get the parent page. */
238*aae80e6bSchristos 			if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
23924420c01Scgd 				return (1);
24024420c01Scgd 
24124420c01Scgd 			/* Move to the next index. */
24224420c01Scgd 			if (parent->index != 0) {
24361238e71Schristos 				idx = parent->index - 1;
24461238e71Schristos 				BT_PUSH(t, h->pgno, idx);
24524420c01Scgd 				break;
24624420c01Scgd 			}
24724420c01Scgd 			mpool_put(t->bt_mp, h, 0);
24824420c01Scgd 		}
24924420c01Scgd 
25024420c01Scgd 		/* Restore the stack. */
25124420c01Scgd 		while (level--) {
25224420c01Scgd 			/* Push the next level down onto the stack. */
25361238e71Schristos 			bi = GETBINTERNAL(h, idx);
25424420c01Scgd 			pgno = bi->pgno;
25524420c01Scgd 
25624420c01Scgd 			/* Lose the currently pinned page. */
25724420c01Scgd 			mpool_put(t->bt_mp, h, 0);
25824420c01Scgd 
25924420c01Scgd 			/* Get the next level down. */
260*aae80e6bSchristos 			if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
26124420c01Scgd 				return (1);
26224420c01Scgd 
26361238e71Schristos 			idx = NEXTINDEX(h) - 1;
26461238e71Schristos 			BT_PUSH(t, pgno, idx);
26524420c01Scgd 		}
26624420c01Scgd 		mpool_put(t->bt_mp, h, 0);
267*aae80e6bSchristos 		if ((h = mpool_get(t->bt_mp, prevpg, 0)) == NULL)
26824420c01Scgd 			return (1);
26924420c01Scgd 	}
27024420c01Scgd 
27124420c01Scgd 
27224420c01Scgd ret:	mpool_put(t->bt_mp, h, 0);
273*aae80e6bSchristos 	return ((*hp = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL);
27424420c01Scgd }
27524420c01Scgd 
27624420c01Scgd /*
27724420c01Scgd  * __bt_bdelete --
27824420c01Scgd  *	Delete all key/data pairs matching the specified key.
27924420c01Scgd  *
28024420c01Scgd  * Parameters:
28124420c01Scgd  *	  t:	tree
2829f0aa214Scgd  *	key:	key to delete
2839f0aa214Scgd  *
2849f0aa214Scgd  * Returns:
2859f0aa214Scgd  *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
2869f0aa214Scgd  */
2879f0aa214Scgd static int
__bt_bdelete(BTREE * t,const DBT * key)288cb9daf8fSchristos __bt_bdelete(BTREE *t, const DBT *key)
2899f0aa214Scgd {
29024420c01Scgd 	EPG *e;
2919f0aa214Scgd 	PAGE *h;
29224420c01Scgd 	int deleted, exact, redo;
29324420c01Scgd 
29424420c01Scgd 	deleted = 0;
2959f0aa214Scgd 
2969f0aa214Scgd 	/* Find any matching record; __bt_search pins the page. */
29724420c01Scgd loop:	if ((e = __bt_search(t, key, &exact)) == NULL)
29824420c01Scgd 		return (deleted ? RET_SUCCESS : RET_ERROR);
2999f0aa214Scgd 	if (!exact) {
3009f0aa214Scgd 		mpool_put(t->bt_mp, e->page, 0);
3019f0aa214Scgd 		return (deleted ? RET_SUCCESS : RET_SPECIAL);
3029f0aa214Scgd 	}
3039f0aa214Scgd 
3049f0aa214Scgd 	/*
30524420c01Scgd 	 * Delete forward, then delete backward, from the found key.  If
30624420c01Scgd 	 * there are duplicates and we reach either side of the page, do
30724420c01Scgd 	 * the key search again, so that we get them all.
30824420c01Scgd 	 */
30924420c01Scgd 	redo = 0;
31024420c01Scgd 	h = e->page;
31124420c01Scgd 	do {
31261238e71Schristos 		if (__bt_dleaf(t, key, h, (u_int)e->index)) {
31324420c01Scgd 			mpool_put(t->bt_mp, h, 0);
31424420c01Scgd 			return (RET_ERROR);
31524420c01Scgd 		}
31624420c01Scgd 		if (F_ISSET(t, B_NODUPS)) {
31724420c01Scgd 			if (NEXTINDEX(h) == 0) {
31824420c01Scgd 				if (__bt_pdelete(t, h))
31924420c01Scgd 					return (RET_ERROR);
32024420c01Scgd 			} else
32124420c01Scgd 				mpool_put(t->bt_mp, h, MPOOL_DIRTY);
32224420c01Scgd 			return (RET_SUCCESS);
32324420c01Scgd 		}
32424420c01Scgd 		deleted = 1;
32524420c01Scgd 	} while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
32624420c01Scgd 
32724420c01Scgd 	/* Check for right-hand edge of the page. */
32824420c01Scgd 	if (e->index == NEXTINDEX(h))
32924420c01Scgd 		redo = 1;
33024420c01Scgd 
33124420c01Scgd 	/* Delete from the key to the beginning of the page. */
33224420c01Scgd 	while (e->index-- > 0) {
33324420c01Scgd 		if (__bt_cmp(t, key, e) != 0)
33424420c01Scgd 			break;
33561238e71Schristos 		if (__bt_dleaf(t, key, h, (u_int)e->index) == RET_ERROR) {
33624420c01Scgd 			mpool_put(t->bt_mp, h, 0);
33724420c01Scgd 			return (RET_ERROR);
33824420c01Scgd 		}
33924420c01Scgd 		if (e->index == 0)
34024420c01Scgd 			redo = 1;
34124420c01Scgd 	}
34224420c01Scgd 
34324420c01Scgd 	/* Check for an empty page. */
34424420c01Scgd 	if (NEXTINDEX(h) == 0) {
34524420c01Scgd 		if (__bt_pdelete(t, h))
34624420c01Scgd 			return (RET_ERROR);
34724420c01Scgd 		goto loop;
34824420c01Scgd 	}
34924420c01Scgd 
35024420c01Scgd 	/* Put the page. */
35124420c01Scgd 	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
35224420c01Scgd 
35324420c01Scgd 	if (redo)
35424420c01Scgd 		goto loop;
35524420c01Scgd 	return (RET_SUCCESS);
35624420c01Scgd }
35724420c01Scgd 
35824420c01Scgd /*
35924420c01Scgd  * __bt_pdelete --
36024420c01Scgd  *	Delete a single page from the tree.
3619f0aa214Scgd  *
3629f0aa214Scgd  * Parameters:
3639f0aa214Scgd  *	t:	tree
36424420c01Scgd  *	h:	leaf page
36524420c01Scgd  *
36624420c01Scgd  * Returns:
36724420c01Scgd  *	RET_SUCCESS, RET_ERROR.
36824420c01Scgd  *
36924420c01Scgd  * Side-effects:
37024420c01Scgd  *	mpool_put's the page
37124420c01Scgd  */
37224420c01Scgd static int
__bt_pdelete(BTREE * t,PAGE * h)373cb9daf8fSchristos __bt_pdelete(BTREE *t, PAGE *h)
37424420c01Scgd {
37524420c01Scgd 	BINTERNAL *bi;
37624420c01Scgd 	PAGE *pg;
37724420c01Scgd 	EPGNO *parent;
37861238e71Schristos 	indx_t cnt, idx, *ip, offset;
37940b37a3bSjoerg 	uint32_t nksize;
38024420c01Scgd 	char *from;
38124420c01Scgd 
38224420c01Scgd 	/*
38324420c01Scgd 	 * Walk the parent page stack -- a LIFO stack of the pages that were
38424420c01Scgd 	 * traversed when we searched for the page where the delete occurred.
38524420c01Scgd 	 * Each stack entry is a page number and a page index offset.  The
38624420c01Scgd 	 * offset is for the page traversed on the search.  We've just deleted
38724420c01Scgd 	 * a page, so we have to delete the key from the parent page.
38824420c01Scgd 	 *
38924420c01Scgd 	 * If the delete from the parent page makes it empty, this process may
39024420c01Scgd 	 * continue all the way up the tree.  We stop if we reach the root page
39124420c01Scgd 	 * (which is never deleted, it's just not worth the effort) or if the
39224420c01Scgd 	 * delete does not empty the page.
39324420c01Scgd 	 */
39424420c01Scgd 	while ((parent = BT_POP(t)) != NULL) {
39524420c01Scgd 		/* Get the parent page. */
396*aae80e6bSchristos 		if ((pg = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
39724420c01Scgd 			return (RET_ERROR);
39824420c01Scgd 
39961238e71Schristos 		idx = parent->index;
40061238e71Schristos 		bi = GETBINTERNAL(pg, idx);
40124420c01Scgd 
40224420c01Scgd 		/* Free any overflow pages. */
40324420c01Scgd 		if (bi->flags & P_BIGKEY &&
40424420c01Scgd 		    __ovfl_delete(t, bi->bytes) == RET_ERROR) {
40524420c01Scgd 			mpool_put(t->bt_mp, pg, 0);
40624420c01Scgd 			return (RET_ERROR);
40724420c01Scgd 		}
40824420c01Scgd 
40924420c01Scgd 		/*
41024420c01Scgd 		 * Free the parent if it has only the one key and it's not the
41124420c01Scgd 		 * root page. If it's the rootpage, turn it back into an empty
41224420c01Scgd 		 * leaf page.
41324420c01Scgd 		 */
414d4639c81Schristos 		if (NEXTINDEX(pg) == 1) {
41524420c01Scgd 			if (pg->pgno == P_ROOT) {
41624420c01Scgd 				pg->lower = BTDATAOFF;
41724420c01Scgd 				pg->upper = t->bt_psize;
41824420c01Scgd 				pg->flags = P_BLEAF;
41924420c01Scgd 			} else {
42024420c01Scgd 				if (__bt_relink(t, pg) || __bt_free(t, pg))
42124420c01Scgd 					return (RET_ERROR);
42224420c01Scgd 				continue;
42324420c01Scgd 			}
424d4639c81Schristos 		} else {
42524420c01Scgd 			/* Pack remaining key items at the end of the page. */
42624420c01Scgd 			nksize = NBINTERNAL(bi->ksize);
42761238e71Schristos 			from = (char *)(void *)pg + pg->upper;
42861238e71Schristos 			memmove(from + nksize, from,
42961238e71Schristos 			(size_t)((char *)(void *)bi - from));
43024420c01Scgd 			pg->upper += nksize;
43124420c01Scgd 
43224420c01Scgd 			/* Adjust indices' offsets, shift the indices down. */
43361238e71Schristos 			offset = pg->linp[idx];
43461238e71Schristos 			for (cnt = idx, ip = &pg->linp[0]; cnt--; ++ip)
43524420c01Scgd 				if (ip[0] < offset)
43624420c01Scgd 					ip[0] += nksize;
43761238e71Schristos 			for (cnt = NEXTINDEX(pg) - idx; --cnt; ++ip)
43824420c01Scgd 				ip[0] = ip[1] < offset ? ip[1] + nksize : ip[1];
43924420c01Scgd 			pg->lower -= sizeof(indx_t);
44024420c01Scgd 		}
44124420c01Scgd 
44224420c01Scgd 		mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
44324420c01Scgd 		break;
44424420c01Scgd 	}
44524420c01Scgd 
44624420c01Scgd 	/* Free the leaf page, as long as it wasn't the root. */
44724420c01Scgd 	if (h->pgno == P_ROOT) {
44824420c01Scgd 		mpool_put(t->bt_mp, h, MPOOL_DIRTY);
44924420c01Scgd 		return (RET_SUCCESS);
45024420c01Scgd 	}
45124420c01Scgd 	return (__bt_relink(t, h) || __bt_free(t, h));
45224420c01Scgd }
45324420c01Scgd 
45424420c01Scgd /*
45524420c01Scgd  * __bt_dleaf --
45624420c01Scgd  *	Delete a single record from a leaf page.
45724420c01Scgd  *
45824420c01Scgd  * Parameters:
45924420c01Scgd  *	t:	tree
46024420c01Scgd  *    key:	referenced key
46124420c01Scgd  *	h:	page
46261238e71Schristos  *	idx:	index on page to delete
4639f0aa214Scgd  *
4649f0aa214Scgd  * Returns:
4659f0aa214Scgd  *	RET_SUCCESS, RET_ERROR.
4669f0aa214Scgd  */
4679f0aa214Scgd int
__bt_dleaf(BTREE * t,const DBT * key,PAGE * h,u_int idx)468cb9daf8fSchristos __bt_dleaf(BTREE *t, const DBT *key, PAGE *h, u_int idx)
4699f0aa214Scgd {
47024420c01Scgd 	BLEAF *bl;
47124420c01Scgd 	indx_t cnt, *ip, offset;
47240b37a3bSjoerg 	uint32_t nbytes;
4739f0aa214Scgd 	void *to;
47424420c01Scgd 	char *from;
4759f0aa214Scgd 
47624420c01Scgd 	/* If this record is referenced by the cursor, delete the cursor. */
47724420c01Scgd 	if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
47824420c01Scgd 	    !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
47961238e71Schristos 	    t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index == idx &&
48061238e71Schristos 	    __bt_curdel(t, key, h, idx))
48124420c01Scgd 		return (RET_ERROR);
48224420c01Scgd 
48324420c01Scgd 	/* If the entry uses overflow pages, make them available for reuse. */
48461238e71Schristos 	to = bl = GETBLEAF(h, idx);
4859f0aa214Scgd 	if (bl->flags & P_BIGKEY && __ovfl_delete(t, bl->bytes) == RET_ERROR)
4869f0aa214Scgd 		return (RET_ERROR);
4879f0aa214Scgd 	if (bl->flags & P_BIGDATA &&
4889f0aa214Scgd 	    __ovfl_delete(t, bl->bytes + bl->ksize) == RET_ERROR)
4899f0aa214Scgd 		return (RET_ERROR);
4909f0aa214Scgd 
49124420c01Scgd 	/* Pack the remaining key/data items at the end of the page. */
49224420c01Scgd 	nbytes = NBLEAF(bl);
49361238e71Schristos 	from = (char *)(void *)h + h->upper;
49461238e71Schristos 	memmove(from + nbytes, from, (size_t)((char *)(void *)to - from));
4959f0aa214Scgd 	h->upper += nbytes;
4969f0aa214Scgd 
49724420c01Scgd 	/* Adjust the indices' offsets, shift the indices down. */
49861238e71Schristos 	offset = h->linp[idx];
49961238e71Schristos 	for (cnt = idx, ip = &h->linp[0]; cnt--; ++ip)
5009f0aa214Scgd 		if (ip[0] < offset)
5019f0aa214Scgd 			ip[0] += nbytes;
50261238e71Schristos 	for (cnt = NEXTINDEX(h) - idx; --cnt; ++ip)
5039f0aa214Scgd 		ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
5049f0aa214Scgd 	h->lower -= sizeof(indx_t);
50524420c01Scgd 
50624420c01Scgd 	/* If the cursor is on this page, adjust it as necessary. */
50724420c01Scgd 	if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
50824420c01Scgd 	    !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
50961238e71Schristos 	    t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index > idx)
51024420c01Scgd 		--t->bt_cursor.pg.index;
51124420c01Scgd 
5129f0aa214Scgd 	return (RET_SUCCESS);
5139f0aa214Scgd }
51424420c01Scgd 
51524420c01Scgd /*
51624420c01Scgd  * __bt_curdel --
51724420c01Scgd  *	Delete the cursor.
51824420c01Scgd  *
51924420c01Scgd  * Parameters:
52024420c01Scgd  *	t:	tree
52124420c01Scgd  *    key:	referenced key (or NULL)
52224420c01Scgd  *	h:	page
52361238e71Schristos  *  idx:	index on page to delete
52424420c01Scgd  *
52524420c01Scgd  * Returns:
52624420c01Scgd  *	RET_SUCCESS, RET_ERROR.
52724420c01Scgd  */
52824420c01Scgd static int
__bt_curdel(BTREE * t,const DBT * key,PAGE * h,u_int idx)529cb9daf8fSchristos __bt_curdel(BTREE *t, const DBT *key, PAGE *h, u_int idx)
53024420c01Scgd {
53124420c01Scgd 	CURSOR *c;
53224420c01Scgd 	EPG e;
53324420c01Scgd 	PAGE *pg;
53424420c01Scgd 	int curcopy, status;
53524420c01Scgd 
53624420c01Scgd 	/*
53724420c01Scgd 	 * If there are duplicates, move forward or backward to one.
53824420c01Scgd 	 * Otherwise, copy the key into the cursor area.
53924420c01Scgd 	 */
54024420c01Scgd 	c = &t->bt_cursor;
54124420c01Scgd 	F_CLR(c, CURS_AFTER | CURS_BEFORE | CURS_ACQUIRE);
54224420c01Scgd 
54324420c01Scgd 	curcopy = 0;
54424420c01Scgd 	if (!F_ISSET(t, B_NODUPS)) {
54524420c01Scgd 		/*
54624420c01Scgd 		 * We're going to have to do comparisons.  If we weren't
54724420c01Scgd 		 * provided a copy of the key, i.e. the user is deleting
54824420c01Scgd 		 * the current cursor position, get one.
54924420c01Scgd 		 */
55024420c01Scgd 		if (key == NULL) {
55124420c01Scgd 			e.page = h;
55261238e71Schristos 			e.index = idx;
55324420c01Scgd 			if ((status = __bt_ret(t, &e,
55424420c01Scgd 			    &c->key, &c->key, NULL, NULL, 1)) != RET_SUCCESS)
55524420c01Scgd 				return (status);
55624420c01Scgd 			curcopy = 1;
55724420c01Scgd 			key = &c->key;
55824420c01Scgd 		}
55924420c01Scgd 		/* Check previous key, if not at the beginning of the page. */
56061238e71Schristos 		if (idx > 0) {
56124420c01Scgd 			e.page = h;
56261238e71Schristos 			e.index = idx - 1;
56324420c01Scgd 			if (__bt_cmp(t, key, &e) == 0) {
56424420c01Scgd 				F_SET(c, CURS_BEFORE);
56524420c01Scgd 				goto dup2;
56624420c01Scgd 			}
56724420c01Scgd 		}
56824420c01Scgd 		/* Check next key, if not at the end of the page. */
56979becf98Slukem 		if (idx < (unsigned)(NEXTINDEX(h) - 1)) {
57024420c01Scgd 			e.page = h;
57161238e71Schristos 			e.index = idx + 1;
57224420c01Scgd 			if (__bt_cmp(t, key, &e) == 0) {
57324420c01Scgd 				F_SET(c, CURS_AFTER);
57424420c01Scgd 				goto dup2;
57524420c01Scgd 			}
57624420c01Scgd 		}
57724420c01Scgd 		/* Check previous key if at the beginning of the page. */
57861238e71Schristos 		if (idx == 0 && h->prevpg != P_INVALID) {
579*aae80e6bSchristos 			if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
58024420c01Scgd 				return (RET_ERROR);
58124420c01Scgd 			e.page = pg;
58224420c01Scgd 			e.index = NEXTINDEX(pg) - 1;
58324420c01Scgd 			if (__bt_cmp(t, key, &e) == 0) {
58424420c01Scgd 				F_SET(c, CURS_BEFORE);
58524420c01Scgd 				goto dup1;
58624420c01Scgd 			}
58724420c01Scgd 			mpool_put(t->bt_mp, pg, 0);
58824420c01Scgd 		}
58924420c01Scgd 		/* Check next key if at the end of the page. */
59079becf98Slukem 		if (idx == (unsigned)(NEXTINDEX(h) - 1) && h->nextpg != P_INVALID) {
591*aae80e6bSchristos 			if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
59224420c01Scgd 				return (RET_ERROR);
59324420c01Scgd 			e.page = pg;
59424420c01Scgd 			e.index = 0;
59524420c01Scgd 			if (__bt_cmp(t, key, &e) == 0) {
59624420c01Scgd 				F_SET(c, CURS_AFTER);
59724420c01Scgd dup1:				mpool_put(t->bt_mp, pg, 0);
59824420c01Scgd dup2:				c->pg.pgno = e.page->pgno;
59924420c01Scgd 				c->pg.index = e.index;
60024420c01Scgd 				return (RET_SUCCESS);
60124420c01Scgd 			}
60224420c01Scgd 			mpool_put(t->bt_mp, pg, 0);
60324420c01Scgd 		}
60424420c01Scgd 	}
60524420c01Scgd 	e.page = h;
60661238e71Schristos 	e.index = idx;
60724420c01Scgd 	if (curcopy || (status =
60824420c01Scgd 	    __bt_ret(t, &e, &c->key, &c->key, NULL, NULL, 1)) == RET_SUCCESS) {
60924420c01Scgd 		F_SET(c, CURS_ACQUIRE);
61024420c01Scgd 		return (RET_SUCCESS);
61124420c01Scgd 	}
61224420c01Scgd 	return (status);
61324420c01Scgd }
61424420c01Scgd 
61524420c01Scgd /*
61624420c01Scgd  * __bt_relink --
61724420c01Scgd  *	Link around a deleted page.
61824420c01Scgd  *
61924420c01Scgd  * Parameters:
62024420c01Scgd  *	t:	tree
62124420c01Scgd  *	h:	page to be deleted
62224420c01Scgd  */
62386147b1cSchristos int
__bt_relink(BTREE * t,PAGE * h)624cb9daf8fSchristos __bt_relink(BTREE *t, PAGE *h)
62524420c01Scgd {
62624420c01Scgd 	PAGE *pg;
62724420c01Scgd 
62824420c01Scgd 	if (h->nextpg != P_INVALID) {
629*aae80e6bSchristos 		if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
63024420c01Scgd 			return (RET_ERROR);
63124420c01Scgd 		pg->prevpg = h->prevpg;
63224420c01Scgd 		mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
63324420c01Scgd 	}
63424420c01Scgd 	if (h->prevpg != P_INVALID) {
635*aae80e6bSchristos 		if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
63624420c01Scgd 			return (RET_ERROR);
63724420c01Scgd 		pg->nextpg = h->nextpg;
63824420c01Scgd 		mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
63924420c01Scgd 	}
64024420c01Scgd 	return (0);
64124420c01Scgd }
642