xref: /csrg-svn/lib/libc/db/btree/bt_delete.c (revision 46561)
146130Smao /*-
246130Smao  * Copyright (c) 1990 The Regents of the University of California.
346130Smao  * All rights reserved.
446130Smao  *
546130Smao  * This code is derived from software contributed to Berkeley by
646130Smao  * Mike Olson.
746130Smao  *
846130Smao  * %sccs.include.redist.c%
946130Smao  */
1046130Smao 
1146130Smao #if defined(LIBC_SCCS) && !defined(lint)
12*46561Sbostic static char sccsid[] = "@(#)bt_delete.c	5.2 (Berkeley) 02/22/91";
1346130Smao #endif /* LIBC_SCCS and not lint */
1446130Smao 
1546130Smao #include <sys/types.h>
1646130Smao #include <db.h>
17*46561Sbostic #include <errno.h>
18*46561Sbostic #include <string.h>
1946130Smao #include "btree.h"
2046130Smao 
2146130Smao /*
2246130Smao  *  _BT_CRSRDEL -- Delete the item pointed to by the cursor.
2346130Smao  *
2446130Smao  *	This routine deletes the item most recently returned by a scan
2546130Smao  *	through the tree.  Since it only makes sense to delete the current
2646130Smao  *	record once, we make sure that we don't try to delete twice without
2746130Smao  *	advancing the scan.
2846130Smao  *
2946130Smao  *	Parameters:
3046130Smao  *		t -- tree in which to do deletion
3146130Smao  *
3246130Smao  *	Returns:
3346130Smao  *		RET_SUCCESS, RET_ERROR.
3446130Smao  *
3546130Smao  *	Side Effects:
3646130Smao  *		The call to _bt_delone marks the cursor, so we can tell that
3746130Smao  *		the current record has been deleted.
3846130Smao  */
3946130Smao 
4046130Smao int
4146130Smao _bt_crsrdel(t)
4246130Smao 	BTREE_P t;
4346130Smao {
4446130Smao 	CURSOR *c;
4546130Smao 
4646130Smao 	c = &(t->bt_cursor);
4746130Smao 
4846130Smao 	/* a cursor must exist, and can't have deleted the current key yet */
4946130Smao 	if (!(t->bt_flags & BTF_SEQINIT) || (c->c_flags & CRSR_BEFORE)) {
5046130Smao 		errno = EINVAL;
5146130Smao 		return (RET_ERROR);
5246130Smao 	}
5346130Smao 
5446130Smao 	if (_bt_getpage(t, c->c_pgno) == RET_ERROR)
5546130Smao 		return (RET_ERROR);
5646130Smao 
5746130Smao 	if (c->c_index >= NEXTINDEX(t->bt_curpage)) {
5846130Smao 		errno = EINVAL;
5946130Smao 		return (RET_ERROR);
6046130Smao 	}
6146130Smao 
6246130Smao 	return (_bt_delone(t, c->c_index));
6346130Smao }
6446130Smao 
6546130Smao /*
6646130Smao  *  _BT_DELONE -- Delete a single entry from a btree.
6746130Smao  *
6846130Smao  *	This routine physically removes a btree entry from a leaf page.
6946130Smao  *	IDATUM items are *never* removed from internal nodes, regardless
7046130Smao  *	of whether the entries that originally caused them to be added
7146130Smao  *	are removed from the tree or not.  In addition, pages made empty
7246130Smao  *	by element deletion are not actually reclaimed.  They are,
7346130Smao  *	however, made available for reuse.
7446130Smao  *
7546130Smao  *	To delete an item from a page, we pack the remaining items at
7646130Smao  *	the end of the page, overwriting the deleted item's entry.  We
7746130Smao  *	move the line pointers backward on the page, overwriting the
7846130Smao  *	original item's line pointer.  This guarantees that the space in
7946130Smao  *	the middle of the page is free -- a property that our insertion
8046130Smao  *	strategy relies on.
8146130Smao  *
8246130Smao  *	This routine doesn't reclaim pages all of whose entries have
8346130Smao  *	been deleted.  These pages are available for reuse, however.
8446130Smao  *	If an item is deleted that was too big to fit on a page, then
8546130Smao  *	the blocks that it occupies are put on a free list for reuse.
8646130Smao  *
8746130Smao  *	Parameters:
8846130Smao  *		t -- btree from which to delete item
8946130Smao  *		index -- index of entry on current page to delete
9046130Smao  *
9146130Smao  *	Returns:
9246130Smao  *		RET_SUCCESS, RET_ERROR.
9346130Smao  *
9446130Smao  *	Side Effects:
9546130Smao  *		Physically changes page layout, adjusts internal page
9646130Smao  *		state to reflect the deletion of the item, and updates
9746130Smao  *		the list of free pages for this tree.
9846130Smao  */
9946130Smao 
10046130Smao int
10146130Smao _bt_delone(t, index)
10246130Smao 	BTREE_P t;
10346130Smao 	index_t index;
10446130Smao {
10546130Smao 	char *src, *dest;
10646130Smao 	int nbytes, nmoved;
10746130Smao 	index_t off;
10846130Smao 	index_t top;
10946130Smao 	index_t i;
11046130Smao 	pgno_t chain;
11146130Smao 	BTHEADER *h;
11246130Smao 	CURSOR *c;
11346130Smao 	DATUM *d;
11446130Smao 
11546130Smao 	/* deletion may confuse an active scan.  fix it.  */
11646130Smao 	c = &(t->bt_cursor);
11746130Smao 	if (t->bt_flags & BTF_SEQINIT && t->bt_curpage->h_pgno == c->c_pgno)
11846130Smao 		if (_bt_fixscan(t, index, (DATUM *) NULL, DELETE) == RET_ERROR)
11946130Smao 			return (RET_ERROR);
12046130Smao 
12146130Smao 	h = t->bt_curpage;
12246130Smao 	off = h->h_linp[index];
12346130Smao 	d = (DATUM *) GETDATUM(h, index);
12446130Smao 
12546130Smao 	/* if this is a big item, reclaim the space it occupies */
12646130Smao 	if (d->d_flags & D_BIGKEY) {
12746130Smao 		bcopy(&(d->d_bytes[0]),
12846130Smao 		      (char *) &chain,
12946130Smao 		      sizeof(chain));
13046130Smao 		if (_bt_delindir(t, chain) == RET_ERROR)
13146130Smao 			return (RET_ERROR);
13246130Smao 		h = t->bt_curpage;
13346130Smao 		d = (DATUM *) GETDATUM(h, index);
13446130Smao 	}
13546130Smao 	if (d->d_flags & D_BIGDATA) {
13646130Smao 		bcopy(&(d->d_bytes[d->d_ksize]),
13746130Smao 		      (char *) &chain,
13846130Smao 		      sizeof(chain));
13946130Smao 		if (_bt_delindir(t, chain) == RET_ERROR)
14046130Smao 			return (RET_ERROR);
14146130Smao 		h = t->bt_curpage;
14246130Smao 		d = (DATUM *) GETDATUM(h, index);
14346130Smao 	}
14446130Smao 
14546130Smao 	/* move the data down on the page */
14646130Smao 	nbytes = d->d_ksize + d->d_dsize
14746130Smao 		 + (sizeof(DATUM) - sizeof(char));
14846130Smao 	nbytes = LONGALIGN(nbytes);
14946130Smao 	src = ((char *) h) + h->h_upper;
15046130Smao 	dest = src + nbytes;
15146130Smao 	nmoved = (int) (((char *) d) - src);
15246130Smao 	(void) bcopy(src, dest, nmoved);
15346130Smao 
15446130Smao 	/* next move the line pointers up */
15546130Smao 	src = (char *) &(h->h_linp[index + 1]);
15646130Smao 	dest = (char *) &(h->h_linp[index]);
15746130Smao 	nmoved = (int) (((char *) &(h->h_linp[NEXTINDEX(h)])) - src);
15846130Smao 	(void) bcopy(src, dest, nmoved);
15946130Smao 
16046130Smao 	/* remember that we freed up some space */
16146130Smao 	h->h_upper += nbytes;
16246130Smao 	h->h_lower -= sizeof(index_t);
16346130Smao 
16446130Smao 	/* adjust offsets in line pointers affected by moving the data */
16546130Smao 	top = NEXTINDEX(h);
16646130Smao 	for (i = 0; i < top; i++) {
16746130Smao 		if (h->h_linp[i] < off)
16846130Smao 			h->h_linp[i] += nbytes;
16946130Smao 	}
17046130Smao 
17146130Smao 	/* it's gone */
17246130Smao 	h->h_flags |= F_DIRTY;
17346130Smao 
17446130Smao 	return (RET_SUCCESS);
17546130Smao }
176