]>
git.saurik.com Git - apple/libc.git/blob - db/btree/bt_delete.c
f8ace922c94e69f9e8d9b05c72293efa2fdd061c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1990, 1993
27 * The Regents of the University of California. All rights reserved.
29 * This code is derived from software contributed to Berkeley by
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 #include <sys/types.h>
71 static int bt_bdelete
__P((BTREE
*, const DBT
*));
74 * __BT_DELETE -- Delete the item(s) referenced by a key.
77 * dbp: pointer to access method
79 * flags: R_CURSOR if deleting what the cursor references
82 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
85 __bt_delete(dbp
, key
, flags
)
95 /* Toss any page pinned across calls. */
96 if (t
->bt_pinned
!= NULL
) {
97 mpool_put(t
->bt_mp
, t
->bt_pinned
, 0);
101 if (ISSET(t
, B_RDONLY
)) {
108 status
= bt_bdelete(t
, key
);
112 * If flags is R_CURSOR, delete the cursor; must already have
113 * started a scan and not have already deleted the record. For
114 * the delete cursor bit to have been set requires that the
115 * scan be initialized, so no reason to check.
117 if (!ISSET(t
, B_SEQINIT
))
119 status
= ISSET(t
, B_DELCRSR
) ?
120 RET_SPECIAL
: __bt_crsrdel(t
, &t
->bt_bcursor
);
123 einval
: errno
= EINVAL
;
126 if (status
== RET_SUCCESS
)
132 * BT_BDELETE -- Delete all key/data pairs matching the specified key.
139 * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
150 int deleted
, dirty1
, dirty2
, exact
;
152 /* Find any matching record; __bt_search pins the page. */
153 if ((e
= __bt_search(t
, key
, &exact
)) == NULL
)
156 mpool_put(t
->bt_mp
, e
->page
, 0);
157 return (RET_SPECIAL
);
161 * Delete forward, then delete backward, from the found key. The
162 * ordering is so that the deletions don't mess up the page refs.
163 * The first loop deletes the key from the original page, the second
164 * unpins the original page. In the first loop, dirty1 is set if
165 * the original page is modified, and dirty2 is set if any subsequent
166 * pages are modified. In the second loop, dirty1 starts off set if
167 * the original page has been modified, and is set if any subsequent
168 * pages are modified.
170 * If find the key referenced by the cursor, don't delete it, just
171 * flag it for future deletion. The cursor page number is P_INVALID
172 * unless the sequential scan is initialized, so no reason to check.
173 * A special case is when the already deleted cursor record was the
174 * only record found. If so, then the delete opertion fails as no
175 * records were deleted.
177 * Cycle in place in the current page until the current record doesn't
178 * match the key or the page is empty. If the latter, walk forward,
179 * skipping empty pages and repeating until a record doesn't match
180 * the key or the end of the tree is reached.
182 cpgno
= t
->bt_bcursor
.pgno
;
183 cindex
= t
->bt_bcursor
.index
;
186 for (h
= e
->page
, deleted
= 0;;) {
189 if (h
->pgno
== cpgno
&& e
->index
== cindex
) {
190 if (!ISSET(t
, B_DELCRSR
)) {
196 if (__bt_dleaf(t
, h
, e
->index
)) {
197 if (h
->pgno
!= save
.page
->pgno
)
198 mpool_put(t
->bt_mp
, h
, dirty2
);
199 mpool_put(t
->bt_mp
, save
.page
, dirty1
);
202 if (h
->pgno
== save
.page
->pgno
)
203 dirty1
= MPOOL_DIRTY
;
205 dirty2
= MPOOL_DIRTY
;
208 } while (e
->index
< NEXTINDEX(h
) && __bt_cmp(t
, key
, e
) == 0);
211 * Quit if didn't find a match, no next page, or first key on
212 * the next page doesn't match. Don't unpin the original page
213 * unless an error occurs.
215 if (e
->index
< NEXTINDEX(h
))
218 if ((pg
= h
->nextpg
) == P_INVALID
)
220 if (h
->pgno
!= save
.page
->pgno
)
221 mpool_put(t
->bt_mp
, h
, dirty2
);
222 if ((h
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
) {
223 mpool_put(t
->bt_mp
, save
.page
, dirty1
);
226 if (NEXTINDEX(h
) != 0) {
233 if (__bt_cmp(t
, key
, e
) != 0)
238 * Reach here with the original page and the last page referenced
239 * pinned (they may be the same). Release it if not the original.
241 done1
: if (h
->pgno
!= save
.page
->pgno
)
242 mpool_put(t
->bt_mp
, h
, dirty2
);
245 * Walk backwards from the record previous to the record returned by
246 * __bt_search, skipping empty pages, until a record doesn't match
247 * the key or reach the beginning of the tree.
253 for (h
= e
->page
; e
->index
; --e
->index
) {
254 if (__bt_cmp(t
, key
, e
) != 0)
256 if (h
->pgno
== cpgno
&& e
->index
== cindex
) {
257 if (!ISSET(t
, B_DELCRSR
)) {
262 if (__bt_dleaf(t
, h
, e
->index
) == RET_ERROR
) {
263 mpool_put(t
->bt_mp
, h
, dirty1
);
266 if (h
->pgno
== save
.page
->pgno
)
267 dirty1
= MPOOL_DIRTY
;
272 if ((pg
= h
->prevpg
) == P_INVALID
)
274 mpool_put(t
->bt_mp
, h
, dirty1
);
276 if ((e
->page
= mpool_get(t
->bt_mp
, pg
, 0)) == NULL
)
278 e
->index
= NEXTINDEX(e
->page
);
282 * Reach here with the last page that was looked at pinned. Release
285 done2
: mpool_put(t
->bt_mp
, h
, dirty1
);
286 return (deleted
? RET_SUCCESS
: RET_SPECIAL
);
290 * __BT_DLEAF -- Delete a single record from a leaf page.
294 * index: index on current page to delete
297 * RET_SUCCESS, RET_ERROR.
300 __bt_dleaf(t
, h
, index
)
306 register indx_t cnt
, *ip
, offset
;
307 register size_t nbytes
;
312 * Delete a record from a btree leaf page. Internal records are never
313 * deleted from internal pages, regardless of the records that caused
314 * them to be added being deleted. Pages made empty by deletion are
315 * not reclaimed. They are, however, made available for reuse.
317 * Pack the remaining entries at the end of the page, shift the indices
318 * down, overwriting the deleted record and its index. If the record
319 * uses overflow pages, make them available for reuse.
321 to
= bl
= GETBLEAF(h
, index
);
322 if (bl
->flags
& P_BIGKEY
&& __ovfl_delete(t
, bl
->bytes
) == RET_ERROR
)
324 if (bl
->flags
& P_BIGDATA
&&
325 __ovfl_delete(t
, bl
->bytes
+ bl
->ksize
) == RET_ERROR
)
330 * Compress the key/data pairs. Compress and adjust the [BR]LEAF
331 * offsets. Reset the headers.
333 from
= (char *)h
+ h
->upper
;
334 memmove(from
+ nbytes
, from
, (char *)to
- from
);
337 offset
= h
->linp
[index
];
338 for (cnt
= index
, ip
= &h
->linp
[0]; cnt
--; ++ip
)
341 for (cnt
= NEXTINDEX(h
) - index
; --cnt
; ++ip
)
342 ip
[0] = ip
[1] < offset
? ip
[1] + nbytes
: ip
[1];
343 h
->lower
-= sizeof(indx_t
);
344 return (RET_SUCCESS
);