xref: /csrg-svn/lib/libc/db/btree/bt_delete.c (revision 46130)
1*46130Smao /*-
2*46130Smao  * Copyright (c) 1990 The Regents of the University of California.
3*46130Smao  * All rights reserved.
4*46130Smao  *
5*46130Smao  * This code is derived from software contributed to Berkeley by
6*46130Smao  * Mike Olson.
7*46130Smao  *
8*46130Smao  * %sccs.include.redist.c%
9*46130Smao  */
10*46130Smao 
11*46130Smao #if defined(LIBC_SCCS) && !defined(lint)
12*46130Smao static char sccsid[] = "@(#)bt_delete.c	5.1 (Berkeley) 01/23/91";
13*46130Smao #endif /* LIBC_SCCS and not lint */
14*46130Smao 
15*46130Smao #include <sys/types.h>
16*46130Smao #include <sys/errno.h>
17*46130Smao #include <db.h>
18*46130Smao #include "btree.h"
19*46130Smao 
20*46130Smao /*
21*46130Smao  *  _BT_CRSRDEL -- Delete the item pointed to by the cursor.
22*46130Smao  *
23*46130Smao  *	This routine deletes the item most recently returned by a scan
24*46130Smao  *	through the tree.  Since it only makes sense to delete the current
25*46130Smao  *	record once, we make sure that we don't try to delete twice without
26*46130Smao  *	advancing the scan.
27*46130Smao  *
28*46130Smao  *	Parameters:
29*46130Smao  *		t -- tree in which to do deletion
30*46130Smao  *
31*46130Smao  *	Returns:
32*46130Smao  *		RET_SUCCESS, RET_ERROR.
33*46130Smao  *
34*46130Smao  *	Side Effects:
35*46130Smao  *		The call to _bt_delone marks the cursor, so we can tell that
36*46130Smao  *		the current record has been deleted.
37*46130Smao  */
38*46130Smao 
39*46130Smao int
40*46130Smao _bt_crsrdel(t)
41*46130Smao 	BTREE_P t;
42*46130Smao {
43*46130Smao 	CURSOR *c;
44*46130Smao 
45*46130Smao 	c = &(t->bt_cursor);
46*46130Smao 
47*46130Smao 	/* a cursor must exist, and can't have deleted the current key yet */
48*46130Smao 	if (!(t->bt_flags & BTF_SEQINIT) || (c->c_flags & CRSR_BEFORE)) {
49*46130Smao 		errno = EINVAL;
50*46130Smao 		return (RET_ERROR);
51*46130Smao 	}
52*46130Smao 
53*46130Smao 	if (_bt_getpage(t, c->c_pgno) == RET_ERROR)
54*46130Smao 		return (RET_ERROR);
55*46130Smao 
56*46130Smao 	if (c->c_index >= NEXTINDEX(t->bt_curpage)) {
57*46130Smao 		errno = EINVAL;
58*46130Smao 		return (RET_ERROR);
59*46130Smao 	}
60*46130Smao 
61*46130Smao 	return (_bt_delone(t, c->c_index));
62*46130Smao }
63*46130Smao 
64*46130Smao /*
65*46130Smao  *  _BT_DELONE -- Delete a single entry from a btree.
66*46130Smao  *
67*46130Smao  *	This routine physically removes a btree entry from a leaf page.
68*46130Smao  *	IDATUM items are *never* removed from internal nodes, regardless
69*46130Smao  *	of whether the entries that originally caused them to be added
70*46130Smao  *	are removed from the tree or not.  In addition, pages made empty
71*46130Smao  *	by element deletion are not actually reclaimed.  They are,
72*46130Smao  *	however, made available for reuse.
73*46130Smao  *
74*46130Smao  *	To delete an item from a page, we pack the remaining items at
75*46130Smao  *	the end of the page, overwriting the deleted item's entry.  We
76*46130Smao  *	move the line pointers backward on the page, overwriting the
77*46130Smao  *	original item's line pointer.  This guarantees that the space in
78*46130Smao  *	the middle of the page is free -- a property that our insertion
79*46130Smao  *	strategy relies on.
80*46130Smao  *
81*46130Smao  *	This routine doesn't reclaim pages all of whose entries have
82*46130Smao  *	been deleted.  These pages are available for reuse, however.
83*46130Smao  *	If an item is deleted that was too big to fit on a page, then
84*46130Smao  *	the blocks that it occupies are put on a free list for reuse.
85*46130Smao  *
86*46130Smao  *	Parameters:
87*46130Smao  *		t -- btree from which to delete item
88*46130Smao  *		index -- index of entry on current page to delete
89*46130Smao  *
90*46130Smao  *	Returns:
91*46130Smao  *		RET_SUCCESS, RET_ERROR.
92*46130Smao  *
93*46130Smao  *	Side Effects:
94*46130Smao  *		Physically changes page layout, adjusts internal page
95*46130Smao  *		state to reflect the deletion of the item, and updates
96*46130Smao  *		the list of free pages for this tree.
97*46130Smao  */
98*46130Smao 
99*46130Smao int
100*46130Smao _bt_delone(t, index)
101*46130Smao 	BTREE_P t;
102*46130Smao 	index_t index;
103*46130Smao {
104*46130Smao 	char *src, *dest;
105*46130Smao 	int nbytes, nmoved;
106*46130Smao 	index_t off;
107*46130Smao 	index_t top;
108*46130Smao 	index_t i;
109*46130Smao 	pgno_t chain;
110*46130Smao 	BTHEADER *h;
111*46130Smao 	CURSOR *c;
112*46130Smao 	DATUM *d;
113*46130Smao 
114*46130Smao 	/* deletion may confuse an active scan.  fix it.  */
115*46130Smao 	c = &(t->bt_cursor);
116*46130Smao 	if (t->bt_flags & BTF_SEQINIT && t->bt_curpage->h_pgno == c->c_pgno)
117*46130Smao 		if (_bt_fixscan(t, index, (DATUM *) NULL, DELETE) == RET_ERROR)
118*46130Smao 			return (RET_ERROR);
119*46130Smao 
120*46130Smao 	h = t->bt_curpage;
121*46130Smao 	off = h->h_linp[index];
122*46130Smao 	d = (DATUM *) GETDATUM(h, index);
123*46130Smao 
124*46130Smao 	/* if this is a big item, reclaim the space it occupies */
125*46130Smao 	if (d->d_flags & D_BIGKEY) {
126*46130Smao 		bcopy(&(d->d_bytes[0]),
127*46130Smao 		      (char *) &chain,
128*46130Smao 		      sizeof(chain));
129*46130Smao 		if (_bt_delindir(t, chain) == RET_ERROR)
130*46130Smao 			return (RET_ERROR);
131*46130Smao 		h = t->bt_curpage;
132*46130Smao 		d = (DATUM *) GETDATUM(h, index);
133*46130Smao 	}
134*46130Smao 	if (d->d_flags & D_BIGDATA) {
135*46130Smao 		bcopy(&(d->d_bytes[d->d_ksize]),
136*46130Smao 		      (char *) &chain,
137*46130Smao 		      sizeof(chain));
138*46130Smao 		if (_bt_delindir(t, chain) == RET_ERROR)
139*46130Smao 			return (RET_ERROR);
140*46130Smao 		h = t->bt_curpage;
141*46130Smao 		d = (DATUM *) GETDATUM(h, index);
142*46130Smao 	}
143*46130Smao 
144*46130Smao 	/* move the data down on the page */
145*46130Smao 	nbytes = d->d_ksize + d->d_dsize
146*46130Smao 		 + (sizeof(DATUM) - sizeof(char));
147*46130Smao 	nbytes = LONGALIGN(nbytes);
148*46130Smao 	src = ((char *) h) + h->h_upper;
149*46130Smao 	dest = src + nbytes;
150*46130Smao 	nmoved = (int) (((char *) d) - src);
151*46130Smao 	(void) bcopy(src, dest, nmoved);
152*46130Smao 
153*46130Smao 	/* next move the line pointers up */
154*46130Smao 	src = (char *) &(h->h_linp[index + 1]);
155*46130Smao 	dest = (char *) &(h->h_linp[index]);
156*46130Smao 	nmoved = (int) (((char *) &(h->h_linp[NEXTINDEX(h)])) - src);
157*46130Smao 	(void) bcopy(src, dest, nmoved);
158*46130Smao 
159*46130Smao 	/* remember that we freed up some space */
160*46130Smao 	h->h_upper += nbytes;
161*46130Smao 	h->h_lower -= sizeof(index_t);
162*46130Smao 
163*46130Smao 	/* adjust offsets in line pointers affected by moving the data */
164*46130Smao 	top = NEXTINDEX(h);
165*46130Smao 	for (i = 0; i < top; i++) {
166*46130Smao 		if (h->h_linp[i] < off)
167*46130Smao 			h->h_linp[i] += nbytes;
168*46130Smao 	}
169*46130Smao 
170*46130Smao 	/* it's gone */
171*46130Smao 	h->h_flags |= F_DIRTY;
172*46130Smao 
173*46130Smao 	return (RET_SUCCESS);
174*46130Smao }
175