1*0Sstevel@tonic-gate /*-
2*0Sstevel@tonic-gate * See the file LICENSE for redistribution information.
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * Copyright (c) 1996, 1997, 1998
5*0Sstevel@tonic-gate * Sleepycat Software. All rights reserved.
6*0Sstevel@tonic-gate */
7*0Sstevel@tonic-gate /*
8*0Sstevel@tonic-gate * Copyright (c) 1990, 1993, 1994
9*0Sstevel@tonic-gate * Margo Seltzer. All rights reserved.
10*0Sstevel@tonic-gate */
11*0Sstevel@tonic-gate /*
12*0Sstevel@tonic-gate * Copyright (c) 1990, 1993, 1994
13*0Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
14*0Sstevel@tonic-gate *
15*0Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by
16*0Sstevel@tonic-gate * Margo Seltzer.
17*0Sstevel@tonic-gate *
18*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
19*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions
20*0Sstevel@tonic-gate * are met:
21*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
22*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
23*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
24*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
25*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
26*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software
27*0Sstevel@tonic-gate * must display the following acknowledgement:
28*0Sstevel@tonic-gate * This product includes software developed by the University of
29*0Sstevel@tonic-gate * California, Berkeley and its contributors.
30*0Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors
31*0Sstevel@tonic-gate * may be used to endorse or promote products derived from this software
32*0Sstevel@tonic-gate * without specific prior written permission.
33*0Sstevel@tonic-gate *
34*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44*0Sstevel@tonic-gate * SUCH DAMAGE.
45*0Sstevel@tonic-gate */
46*0Sstevel@tonic-gate
47*0Sstevel@tonic-gate #include "config.h"
48*0Sstevel@tonic-gate
49*0Sstevel@tonic-gate #ifndef lint
50*0Sstevel@tonic-gate static const char sccsid[] = "@(#)hash_page.c 10.55 (Sleepycat) 1/3/99";
51*0Sstevel@tonic-gate #endif /* not lint */
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate /*
54*0Sstevel@tonic-gate * PACKAGE: hashing
55*0Sstevel@tonic-gate *
56*0Sstevel@tonic-gate * DESCRIPTION:
57*0Sstevel@tonic-gate * Page manipulation for hashing package.
58*0Sstevel@tonic-gate *
59*0Sstevel@tonic-gate * ROUTINES:
60*0Sstevel@tonic-gate *
61*0Sstevel@tonic-gate * External
62*0Sstevel@tonic-gate * __get_page
63*0Sstevel@tonic-gate * __add_ovflpage
64*0Sstevel@tonic-gate * __overflow_page
65*0Sstevel@tonic-gate * Internal
66*0Sstevel@tonic-gate * open_temp
67*0Sstevel@tonic-gate */
68*0Sstevel@tonic-gate
69*0Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES
70*0Sstevel@tonic-gate #include <sys/types.h>
71*0Sstevel@tonic-gate
72*0Sstevel@tonic-gate #include <errno.h>
73*0Sstevel@tonic-gate #include <string.h>
74*0Sstevel@tonic-gate #endif
75*0Sstevel@tonic-gate
76*0Sstevel@tonic-gate #include "db_int.h"
77*0Sstevel@tonic-gate #include "db_page.h"
78*0Sstevel@tonic-gate #include "hash.h"
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gate static int __ham_lock_bucket __P((DBC *, db_lockmode_t));
81*0Sstevel@tonic-gate
82*0Sstevel@tonic-gate #ifdef DEBUG_SLOW
83*0Sstevel@tonic-gate static void __account_page(DB *, db_pgno_t, int);
84*0Sstevel@tonic-gate #endif
85*0Sstevel@tonic-gate
86*0Sstevel@tonic-gate /*
87*0Sstevel@tonic-gate * PUBLIC: int __ham_item __P((DBC *, db_lockmode_t));
88*0Sstevel@tonic-gate */
89*0Sstevel@tonic-gate int
__ham_item(dbc,mode)90*0Sstevel@tonic-gate __ham_item(dbc, mode)
91*0Sstevel@tonic-gate DBC *dbc;
92*0Sstevel@tonic-gate db_lockmode_t mode;
93*0Sstevel@tonic-gate {
94*0Sstevel@tonic-gate DB *dbp;
95*0Sstevel@tonic-gate HASH_CURSOR *hcp;
96*0Sstevel@tonic-gate db_pgno_t next_pgno;
97*0Sstevel@tonic-gate int ret;
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate dbp = dbc->dbp;
100*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
101*0Sstevel@tonic-gate
102*0Sstevel@tonic-gate if (F_ISSET(hcp, H_DELETED))
103*0Sstevel@tonic-gate return (EINVAL);
104*0Sstevel@tonic-gate F_CLR(hcp, H_OK | H_NOMORE);
105*0Sstevel@tonic-gate
106*0Sstevel@tonic-gate /* Check if we need to get a page for this cursor. */
107*0Sstevel@tonic-gate if ((ret = __ham_get_cpage(dbc, mode)) != 0)
108*0Sstevel@tonic-gate return (ret);
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate /* Check if we are looking for space in which to insert an item. */
111*0Sstevel@tonic-gate if (hcp->seek_size && hcp->seek_found_page == PGNO_INVALID
112*0Sstevel@tonic-gate && hcp->seek_size < P_FREESPACE(hcp->pagep))
113*0Sstevel@tonic-gate hcp->seek_found_page = hcp->pgno;
114*0Sstevel@tonic-gate
115*0Sstevel@tonic-gate /* Check if we need to go on to the next page. */
116*0Sstevel@tonic-gate if (F_ISSET(hcp, H_ISDUP) && hcp->dpgno == PGNO_INVALID)
117*0Sstevel@tonic-gate /*
118*0Sstevel@tonic-gate * ISDUP is set, and offset is at the beginning of the datum.
119*0Sstevel@tonic-gate * We need to grab the length of the datum, then set the datum
120*0Sstevel@tonic-gate * pointer to be the beginning of the datum.
121*0Sstevel@tonic-gate */
122*0Sstevel@tonic-gate memcpy(&hcp->dup_len,
123*0Sstevel@tonic-gate HKEYDATA_DATA(H_PAIRDATA(hcp->pagep, hcp->bndx)) +
124*0Sstevel@tonic-gate hcp->dup_off, sizeof(db_indx_t));
125*0Sstevel@tonic-gate else if (F_ISSET(hcp, H_ISDUP)) {
126*0Sstevel@tonic-gate /* Make sure we're not about to run off the page. */
127*0Sstevel@tonic-gate if (hcp->dpagep == NULL && (ret = __ham_get_page(dbp,
128*0Sstevel@tonic-gate hcp->dpgno, &hcp->dpagep)) != 0)
129*0Sstevel@tonic-gate return (ret);
130*0Sstevel@tonic-gate
131*0Sstevel@tonic-gate if (hcp->dndx >= NUM_ENT(hcp->dpagep)) {
132*0Sstevel@tonic-gate if (NEXT_PGNO(hcp->dpagep) == PGNO_INVALID) {
133*0Sstevel@tonic-gate if (F_ISSET(hcp, H_DUPONLY)) {
134*0Sstevel@tonic-gate F_CLR(hcp, H_OK);
135*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
136*0Sstevel@tonic-gate return (0);
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate if ((ret = __ham_put_page(dbp,
139*0Sstevel@tonic-gate hcp->dpagep, 0)) != 0)
140*0Sstevel@tonic-gate return (ret);
141*0Sstevel@tonic-gate F_CLR(hcp, H_ISDUP);
142*0Sstevel@tonic-gate hcp->dpagep = NULL;
143*0Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID;
144*0Sstevel@tonic-gate hcp->dndx = NDX_INVALID;
145*0Sstevel@tonic-gate hcp->bndx++;
146*0Sstevel@tonic-gate } else if ((ret = __ham_next_cpage(dbc,
147*0Sstevel@tonic-gate NEXT_PGNO(hcp->dpagep), 0, H_ISDUP)) != 0)
148*0Sstevel@tonic-gate return (ret);
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate }
151*0Sstevel@tonic-gate
152*0Sstevel@tonic-gate if (hcp->bndx >= (db_indx_t)H_NUMPAIRS(hcp->pagep)) {
153*0Sstevel@tonic-gate /* Fetch next page. */
154*0Sstevel@tonic-gate if (NEXT_PGNO(hcp->pagep) == PGNO_INVALID) {
155*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
156*0Sstevel@tonic-gate if (hcp->dpagep != NULL &&
157*0Sstevel@tonic-gate (ret = __ham_put_page(dbp, hcp->dpagep, 0)) != 0)
158*0Sstevel@tonic-gate return (ret);
159*0Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID;
160*0Sstevel@tonic-gate return (DB_NOTFOUND);
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate next_pgno = NEXT_PGNO(hcp->pagep);
163*0Sstevel@tonic-gate hcp->bndx = 0;
164*0Sstevel@tonic-gate if ((ret = __ham_next_cpage(dbc, next_pgno, 0, 0)) != 0)
165*0Sstevel@tonic-gate return (ret);
166*0Sstevel@tonic-gate }
167*0Sstevel@tonic-gate
168*0Sstevel@tonic-gate F_SET(hcp, H_OK);
169*0Sstevel@tonic-gate return (0);
170*0Sstevel@tonic-gate }
171*0Sstevel@tonic-gate
172*0Sstevel@tonic-gate /*
173*0Sstevel@tonic-gate * PUBLIC: int __ham_item_reset __P((DBC *));
174*0Sstevel@tonic-gate */
175*0Sstevel@tonic-gate int
__ham_item_reset(dbc)176*0Sstevel@tonic-gate __ham_item_reset(dbc)
177*0Sstevel@tonic-gate DBC *dbc;
178*0Sstevel@tonic-gate {
179*0Sstevel@tonic-gate HASH_CURSOR *hcp;
180*0Sstevel@tonic-gate DB *dbp;
181*0Sstevel@tonic-gate int ret;
182*0Sstevel@tonic-gate
183*0Sstevel@tonic-gate ret = 0;
184*0Sstevel@tonic-gate dbp = dbc->dbp;
185*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
186*0Sstevel@tonic-gate if (hcp->pagep != NULL)
187*0Sstevel@tonic-gate ret = __ham_put_page(dbp, hcp->pagep, 0);
188*0Sstevel@tonic-gate if (ret == 0 && hcp->dpagep != NULL)
189*0Sstevel@tonic-gate ret = __ham_put_page(dbp, hcp->dpagep, 0);
190*0Sstevel@tonic-gate
191*0Sstevel@tonic-gate __ham_item_init(hcp);
192*0Sstevel@tonic-gate return (ret);
193*0Sstevel@tonic-gate }
194*0Sstevel@tonic-gate
195*0Sstevel@tonic-gate /*
196*0Sstevel@tonic-gate * PUBLIC: void __ham_item_init __P((HASH_CURSOR *));
197*0Sstevel@tonic-gate */
198*0Sstevel@tonic-gate void
__ham_item_init(hcp)199*0Sstevel@tonic-gate __ham_item_init(hcp)
200*0Sstevel@tonic-gate HASH_CURSOR *hcp;
201*0Sstevel@tonic-gate {
202*0Sstevel@tonic-gate /*
203*0Sstevel@tonic-gate * If this cursor still holds any locks, we must
204*0Sstevel@tonic-gate * release them if we are not running with transactions.
205*0Sstevel@tonic-gate */
206*0Sstevel@tonic-gate if (hcp->lock && hcp->dbc->txn == NULL)
207*0Sstevel@tonic-gate (void)lock_put(hcp->dbc->dbp->dbenv->lk_info, hcp->lock);
208*0Sstevel@tonic-gate
209*0Sstevel@tonic-gate /*
210*0Sstevel@tonic-gate * The following fields must *not* be initialized here
211*0Sstevel@tonic-gate * because they may have meaning across inits.
212*0Sstevel@tonic-gate * hlock, hdr, split_buf, stats
213*0Sstevel@tonic-gate */
214*0Sstevel@tonic-gate hcp->bucket = BUCKET_INVALID;
215*0Sstevel@tonic-gate hcp->lbucket = BUCKET_INVALID;
216*0Sstevel@tonic-gate hcp->lock = 0;
217*0Sstevel@tonic-gate hcp->pagep = NULL;
218*0Sstevel@tonic-gate hcp->pgno = PGNO_INVALID;
219*0Sstevel@tonic-gate hcp->bndx = NDX_INVALID;
220*0Sstevel@tonic-gate hcp->dpagep = NULL;
221*0Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID;
222*0Sstevel@tonic-gate hcp->dndx = NDX_INVALID;
223*0Sstevel@tonic-gate hcp->dup_off = 0;
224*0Sstevel@tonic-gate hcp->dup_len = 0;
225*0Sstevel@tonic-gate hcp->dup_tlen = 0;
226*0Sstevel@tonic-gate hcp->seek_size = 0;
227*0Sstevel@tonic-gate hcp->seek_found_page = PGNO_INVALID;
228*0Sstevel@tonic-gate hcp->flags = 0;
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate
231*0Sstevel@tonic-gate /*
232*0Sstevel@tonic-gate * PUBLIC: int __ham_item_done __P((DBC *, int));
233*0Sstevel@tonic-gate */
234*0Sstevel@tonic-gate int
__ham_item_done(dbc,dirty)235*0Sstevel@tonic-gate __ham_item_done(dbc, dirty)
236*0Sstevel@tonic-gate DBC *dbc;
237*0Sstevel@tonic-gate int dirty;
238*0Sstevel@tonic-gate {
239*0Sstevel@tonic-gate DB *dbp;
240*0Sstevel@tonic-gate HASH_CURSOR *hcp;
241*0Sstevel@tonic-gate int ret, t_ret;
242*0Sstevel@tonic-gate
243*0Sstevel@tonic-gate dbp = dbc->dbp;
244*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
245*0Sstevel@tonic-gate t_ret = ret = 0;
246*0Sstevel@tonic-gate
247*0Sstevel@tonic-gate if (hcp->pagep)
248*0Sstevel@tonic-gate ret = __ham_put_page(dbp, hcp->pagep,
249*0Sstevel@tonic-gate dirty && hcp->dpagep == NULL);
250*0Sstevel@tonic-gate hcp->pagep = NULL;
251*0Sstevel@tonic-gate
252*0Sstevel@tonic-gate if (hcp->dpagep)
253*0Sstevel@tonic-gate t_ret = __ham_put_page(dbp, hcp->dpagep, dirty);
254*0Sstevel@tonic-gate hcp->dpagep = NULL;
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate if (ret == 0 && t_ret != 0)
257*0Sstevel@tonic-gate ret = t_ret;
258*0Sstevel@tonic-gate
259*0Sstevel@tonic-gate /*
260*0Sstevel@tonic-gate * We don't throw out the page number since we might want to
261*0Sstevel@tonic-gate * continue getting on this page.
262*0Sstevel@tonic-gate */
263*0Sstevel@tonic-gate return (ret != 0 ? ret : t_ret);
264*0Sstevel@tonic-gate }
265*0Sstevel@tonic-gate
266*0Sstevel@tonic-gate /*
267*0Sstevel@tonic-gate * Returns the last item in a bucket.
268*0Sstevel@tonic-gate *
269*0Sstevel@tonic-gate * PUBLIC: int __ham_item_last __P((DBC *, db_lockmode_t));
270*0Sstevel@tonic-gate */
271*0Sstevel@tonic-gate int
__ham_item_last(dbc,mode)272*0Sstevel@tonic-gate __ham_item_last(dbc, mode)
273*0Sstevel@tonic-gate DBC *dbc;
274*0Sstevel@tonic-gate db_lockmode_t mode;
275*0Sstevel@tonic-gate {
276*0Sstevel@tonic-gate HASH_CURSOR *hcp;
277*0Sstevel@tonic-gate int ret;
278*0Sstevel@tonic-gate
279*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
280*0Sstevel@tonic-gate if ((ret = __ham_item_reset(dbc)) != 0)
281*0Sstevel@tonic-gate return (ret);
282*0Sstevel@tonic-gate
283*0Sstevel@tonic-gate hcp->bucket = hcp->hdr->max_bucket;
284*0Sstevel@tonic-gate F_SET(hcp, H_OK);
285*0Sstevel@tonic-gate return (__ham_item_prev(dbc, mode));
286*0Sstevel@tonic-gate }
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gate /*
289*0Sstevel@tonic-gate * PUBLIC: int __ham_item_first __P((DBC *, db_lockmode_t));
290*0Sstevel@tonic-gate */
291*0Sstevel@tonic-gate int
__ham_item_first(dbc,mode)292*0Sstevel@tonic-gate __ham_item_first(dbc, mode)
293*0Sstevel@tonic-gate DBC *dbc;
294*0Sstevel@tonic-gate db_lockmode_t mode;
295*0Sstevel@tonic-gate {
296*0Sstevel@tonic-gate HASH_CURSOR *hcp;
297*0Sstevel@tonic-gate int ret;
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
300*0Sstevel@tonic-gate if ((ret = __ham_item_reset(dbc)) != 0)
301*0Sstevel@tonic-gate return (ret);
302*0Sstevel@tonic-gate F_SET(hcp, H_OK);
303*0Sstevel@tonic-gate hcp->bucket = 0;
304*0Sstevel@tonic-gate return (__ham_item_next(dbc, mode));
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate /*
308*0Sstevel@tonic-gate * __ham_item_prev --
309*0Sstevel@tonic-gate * Returns a pointer to key/data pair on a page. In the case of
310*0Sstevel@tonic-gate * bigkeys, just returns the page number and index of the bigkey
311*0Sstevel@tonic-gate * pointer pair.
312*0Sstevel@tonic-gate *
313*0Sstevel@tonic-gate * PUBLIC: int __ham_item_prev __P((DBC *, db_lockmode_t));
314*0Sstevel@tonic-gate */
315*0Sstevel@tonic-gate int
__ham_item_prev(dbc,mode)316*0Sstevel@tonic-gate __ham_item_prev(dbc, mode)
317*0Sstevel@tonic-gate DBC *dbc;
318*0Sstevel@tonic-gate db_lockmode_t mode;
319*0Sstevel@tonic-gate {
320*0Sstevel@tonic-gate DB *dbp;
321*0Sstevel@tonic-gate HASH_CURSOR *hcp;
322*0Sstevel@tonic-gate db_pgno_t next_pgno;
323*0Sstevel@tonic-gate int ret;
324*0Sstevel@tonic-gate
325*0Sstevel@tonic-gate dbp = dbc->dbp;
326*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
327*0Sstevel@tonic-gate /*
328*0Sstevel@tonic-gate * There are N cases for backing up in a hash file.
329*0Sstevel@tonic-gate * Case 1: In the middle of a page, no duplicates, just dec the index.
330*0Sstevel@tonic-gate * Case 2: In the middle of a duplicate set, back up one.
331*0Sstevel@tonic-gate * Case 3: At the beginning of a duplicate set, get out of set and
332*0Sstevel@tonic-gate * back up to next key.
333*0Sstevel@tonic-gate * Case 4: At the beginning of a page; go to previous page.
334*0Sstevel@tonic-gate * Case 5: At the beginning of a bucket; go to prev bucket.
335*0Sstevel@tonic-gate */
336*0Sstevel@tonic-gate F_CLR(hcp, H_OK | H_NOMORE | H_DELETED);
337*0Sstevel@tonic-gate
338*0Sstevel@tonic-gate /*
339*0Sstevel@tonic-gate * First handle the duplicates. Either you'll get the key here
340*0Sstevel@tonic-gate * or you'll exit the duplicate set and drop into the code below
341*0Sstevel@tonic-gate * to handle backing up through keys.
342*0Sstevel@tonic-gate */
343*0Sstevel@tonic-gate if (F_ISSET(hcp, H_ISDUP)) {
344*0Sstevel@tonic-gate if (hcp->dpgno == PGNO_INVALID) {
345*0Sstevel@tonic-gate /* Duplicates are on-page. */
346*0Sstevel@tonic-gate if (hcp->dup_off != 0)
347*0Sstevel@tonic-gate if ((ret = __ham_get_cpage(dbc, mode)) != 0)
348*0Sstevel@tonic-gate return (ret);
349*0Sstevel@tonic-gate else {
350*0Sstevel@tonic-gate HASH_CURSOR *h;
351*0Sstevel@tonic-gate h = hcp;
352*0Sstevel@tonic-gate memcpy(&h->dup_len, HKEYDATA_DATA(
353*0Sstevel@tonic-gate H_PAIRDATA(h->pagep, h->bndx))
354*0Sstevel@tonic-gate + h->dup_off - sizeof(db_indx_t),
355*0Sstevel@tonic-gate sizeof(db_indx_t));
356*0Sstevel@tonic-gate hcp->dup_off -=
357*0Sstevel@tonic-gate DUP_SIZE(hcp->dup_len);
358*0Sstevel@tonic-gate hcp->dndx--;
359*0Sstevel@tonic-gate return (__ham_item(dbc, mode));
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate } else if (hcp->dndx > 0) { /* Duplicates are off-page. */
362*0Sstevel@tonic-gate hcp->dndx--;
363*0Sstevel@tonic-gate return (__ham_item(dbc, mode));
364*0Sstevel@tonic-gate } else if ((ret = __ham_get_cpage(dbc, mode)) != 0)
365*0Sstevel@tonic-gate return (ret);
366*0Sstevel@tonic-gate else if (PREV_PGNO(hcp->dpagep) == PGNO_INVALID) {
367*0Sstevel@tonic-gate if (F_ISSET(hcp, H_DUPONLY)) {
368*0Sstevel@tonic-gate F_CLR(hcp, H_OK);
369*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
370*0Sstevel@tonic-gate return (0);
371*0Sstevel@tonic-gate } else {
372*0Sstevel@tonic-gate F_CLR(hcp, H_ISDUP); /* End of dups */
373*0Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID;
374*0Sstevel@tonic-gate if (hcp->dpagep != NULL)
375*0Sstevel@tonic-gate (void)__ham_put_page(dbp,
376*0Sstevel@tonic-gate hcp->dpagep, 0);
377*0Sstevel@tonic-gate hcp->dpagep = NULL;
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate } else if ((ret = __ham_next_cpage(dbc,
380*0Sstevel@tonic-gate PREV_PGNO(hcp->dpagep), 0, H_ISDUP)) != 0)
381*0Sstevel@tonic-gate return (ret);
382*0Sstevel@tonic-gate else {
383*0Sstevel@tonic-gate hcp->dndx = NUM_ENT(hcp->pagep) - 1;
384*0Sstevel@tonic-gate return (__ham_item(dbc, mode));
385*0Sstevel@tonic-gate }
386*0Sstevel@tonic-gate }
387*0Sstevel@tonic-gate
388*0Sstevel@tonic-gate /*
389*0Sstevel@tonic-gate * If we get here, we are not in a duplicate set, and just need
390*0Sstevel@tonic-gate * to back up the cursor. There are still three cases:
391*0Sstevel@tonic-gate * midpage, beginning of page, beginning of bucket.
392*0Sstevel@tonic-gate */
393*0Sstevel@tonic-gate
394*0Sstevel@tonic-gate if (F_ISSET(hcp, H_DUPONLY)) {
395*0Sstevel@tonic-gate F_CLR(hcp, H_OK);
396*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
397*0Sstevel@tonic-gate return (0);
398*0Sstevel@tonic-gate }
399*0Sstevel@tonic-gate
400*0Sstevel@tonic-gate if (hcp->bndx == 0) { /* Beginning of page. */
401*0Sstevel@tonic-gate if ((ret = __ham_get_cpage(dbc, mode)) != 0)
402*0Sstevel@tonic-gate return (ret);
403*0Sstevel@tonic-gate hcp->pgno = PREV_PGNO(hcp->pagep);
404*0Sstevel@tonic-gate if (hcp->pgno == PGNO_INVALID) {
405*0Sstevel@tonic-gate /* Beginning of bucket. */
406*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
407*0Sstevel@tonic-gate return (DB_NOTFOUND);
408*0Sstevel@tonic-gate } else if ((ret =
409*0Sstevel@tonic-gate __ham_next_cpage(dbc, hcp->pgno, 0, 0)) != 0)
410*0Sstevel@tonic-gate return (ret);
411*0Sstevel@tonic-gate else
412*0Sstevel@tonic-gate hcp->bndx = H_NUMPAIRS(hcp->pagep);
413*0Sstevel@tonic-gate }
414*0Sstevel@tonic-gate
415*0Sstevel@tonic-gate /*
416*0Sstevel@tonic-gate * Either we've got the cursor set up to be decremented, or we
417*0Sstevel@tonic-gate * have to find the end of a bucket.
418*0Sstevel@tonic-gate */
419*0Sstevel@tonic-gate if (hcp->bndx == NDX_INVALID) {
420*0Sstevel@tonic-gate if (hcp->pagep == NULL)
421*0Sstevel@tonic-gate next_pgno = BUCKET_TO_PAGE(hcp, hcp->bucket);
422*0Sstevel@tonic-gate else
423*0Sstevel@tonic-gate goto got_page;
424*0Sstevel@tonic-gate
425*0Sstevel@tonic-gate do {
426*0Sstevel@tonic-gate if ((ret = __ham_next_cpage(dbc, next_pgno, 0, 0)) != 0)
427*0Sstevel@tonic-gate return (ret);
428*0Sstevel@tonic-gate got_page: next_pgno = NEXT_PGNO(hcp->pagep);
429*0Sstevel@tonic-gate hcp->bndx = H_NUMPAIRS(hcp->pagep);
430*0Sstevel@tonic-gate } while (next_pgno != PGNO_INVALID);
431*0Sstevel@tonic-gate
432*0Sstevel@tonic-gate if (hcp->bndx == 0) {
433*0Sstevel@tonic-gate /* Bucket was empty. */
434*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
435*0Sstevel@tonic-gate return (DB_NOTFOUND);
436*0Sstevel@tonic-gate }
437*0Sstevel@tonic-gate }
438*0Sstevel@tonic-gate
439*0Sstevel@tonic-gate hcp->bndx--;
440*0Sstevel@tonic-gate
441*0Sstevel@tonic-gate return (__ham_item(dbc, mode));
442*0Sstevel@tonic-gate }
443*0Sstevel@tonic-gate
444*0Sstevel@tonic-gate /*
445*0Sstevel@tonic-gate * Sets the cursor to the next key/data pair on a page.
446*0Sstevel@tonic-gate *
447*0Sstevel@tonic-gate * PUBLIC: int __ham_item_next __P((DBC *, db_lockmode_t));
448*0Sstevel@tonic-gate */
449*0Sstevel@tonic-gate int
__ham_item_next(dbc,mode)450*0Sstevel@tonic-gate __ham_item_next(dbc, mode)
451*0Sstevel@tonic-gate DBC *dbc;
452*0Sstevel@tonic-gate db_lockmode_t mode;
453*0Sstevel@tonic-gate {
454*0Sstevel@tonic-gate HASH_CURSOR *hcp;
455*0Sstevel@tonic-gate
456*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
457*0Sstevel@tonic-gate /*
458*0Sstevel@tonic-gate * Deleted on-page duplicates are a weird case. If we delete the last
459*0Sstevel@tonic-gate * one, then our cursor is at the very end of a duplicate set and
460*0Sstevel@tonic-gate * we actually need to go on to the next key.
461*0Sstevel@tonic-gate */
462*0Sstevel@tonic-gate if (F_ISSET(hcp, H_DELETED)) {
463*0Sstevel@tonic-gate if (hcp->bndx != NDX_INVALID &&
464*0Sstevel@tonic-gate F_ISSET(hcp, H_ISDUP) &&
465*0Sstevel@tonic-gate hcp->dpgno == PGNO_INVALID &&
466*0Sstevel@tonic-gate hcp->dup_tlen == hcp->dup_off) {
467*0Sstevel@tonic-gate if (F_ISSET(hcp, H_DUPONLY)) {
468*0Sstevel@tonic-gate F_CLR(hcp, H_OK);
469*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
470*0Sstevel@tonic-gate return (0);
471*0Sstevel@tonic-gate } else {
472*0Sstevel@tonic-gate F_CLR(hcp, H_ISDUP);
473*0Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID;
474*0Sstevel@tonic-gate hcp->bndx++;
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate } else if (!F_ISSET(hcp, H_ISDUP) &&
477*0Sstevel@tonic-gate F_ISSET(hcp, H_DUPONLY)) {
478*0Sstevel@tonic-gate F_CLR(hcp, H_OK);
479*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
480*0Sstevel@tonic-gate return (0);
481*0Sstevel@tonic-gate }
482*0Sstevel@tonic-gate F_CLR(hcp, H_DELETED);
483*0Sstevel@tonic-gate } else if (hcp->bndx == NDX_INVALID) {
484*0Sstevel@tonic-gate hcp->bndx = 0;
485*0Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID;
486*0Sstevel@tonic-gate F_CLR(hcp, H_ISDUP);
487*0Sstevel@tonic-gate } else if (F_ISSET(hcp, H_ISDUP) && hcp->dpgno != PGNO_INVALID)
488*0Sstevel@tonic-gate hcp->dndx++;
489*0Sstevel@tonic-gate else if (F_ISSET(hcp, H_ISDUP)) {
490*0Sstevel@tonic-gate if (hcp->dup_off + DUP_SIZE(hcp->dup_len) >=
491*0Sstevel@tonic-gate hcp->dup_tlen && F_ISSET(hcp, H_DUPONLY)) {
492*0Sstevel@tonic-gate F_CLR(hcp, H_OK);
493*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
494*0Sstevel@tonic-gate return (0);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate hcp->dndx++;
497*0Sstevel@tonic-gate hcp->dup_off += DUP_SIZE(hcp->dup_len);
498*0Sstevel@tonic-gate if (hcp->dup_off >= hcp->dup_tlen) {
499*0Sstevel@tonic-gate F_CLR(hcp, H_ISDUP);
500*0Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID;
501*0Sstevel@tonic-gate hcp->bndx++;
502*0Sstevel@tonic-gate }
503*0Sstevel@tonic-gate } else if (F_ISSET(hcp, H_DUPONLY)) {
504*0Sstevel@tonic-gate F_CLR(hcp, H_OK);
505*0Sstevel@tonic-gate F_SET(hcp, H_NOMORE);
506*0Sstevel@tonic-gate return (0);
507*0Sstevel@tonic-gate } else
508*0Sstevel@tonic-gate hcp->bndx++;
509*0Sstevel@tonic-gate
510*0Sstevel@tonic-gate return (__ham_item(dbc, mode));
511*0Sstevel@tonic-gate }
512*0Sstevel@tonic-gate
513*0Sstevel@tonic-gate /*
514*0Sstevel@tonic-gate * PUBLIC: void __ham_putitem __P((PAGE *p, const DBT *, int));
515*0Sstevel@tonic-gate *
516*0Sstevel@tonic-gate * This is a little bit sleazy in that we're overloading the meaning
517*0Sstevel@tonic-gate * of the H_OFFPAGE type here. When we recover deletes, we have the
518*0Sstevel@tonic-gate * entire entry instead of having only the DBT, so we'll pass type
519*0Sstevel@tonic-gate * H_OFFPAGE to mean, "copy the whole entry" as opposed to constructing
520*0Sstevel@tonic-gate * an H_KEYDATA around it.
521*0Sstevel@tonic-gate */
522*0Sstevel@tonic-gate void
__ham_putitem(p,dbt,type)523*0Sstevel@tonic-gate __ham_putitem(p, dbt, type)
524*0Sstevel@tonic-gate PAGE *p;
525*0Sstevel@tonic-gate const DBT *dbt;
526*0Sstevel@tonic-gate int type;
527*0Sstevel@tonic-gate {
528*0Sstevel@tonic-gate u_int16_t n, off;
529*0Sstevel@tonic-gate
530*0Sstevel@tonic-gate n = NUM_ENT(p);
531*0Sstevel@tonic-gate
532*0Sstevel@tonic-gate /* Put the item element on the page. */
533*0Sstevel@tonic-gate if (type == H_OFFPAGE) {
534*0Sstevel@tonic-gate off = HOFFSET(p) - dbt->size;
535*0Sstevel@tonic-gate HOFFSET(p) = p->inp[n] = off;
536*0Sstevel@tonic-gate memcpy(P_ENTRY(p, n), dbt->data, dbt->size);
537*0Sstevel@tonic-gate } else {
538*0Sstevel@tonic-gate off = HOFFSET(p) - HKEYDATA_SIZE(dbt->size);
539*0Sstevel@tonic-gate HOFFSET(p) = p->inp[n] = off;
540*0Sstevel@tonic-gate PUT_HKEYDATA(P_ENTRY(p, n), dbt->data, dbt->size, type);
541*0Sstevel@tonic-gate }
542*0Sstevel@tonic-gate
543*0Sstevel@tonic-gate /* Adjust page info. */
544*0Sstevel@tonic-gate NUM_ENT(p) += 1;
545*0Sstevel@tonic-gate }
546*0Sstevel@tonic-gate
547*0Sstevel@tonic-gate /*
548*0Sstevel@tonic-gate * PUBLIC: void __ham_reputpair
549*0Sstevel@tonic-gate * PUBLIC: __P((PAGE *p, u_int32_t, u_int32_t, const DBT *, const DBT *));
550*0Sstevel@tonic-gate *
551*0Sstevel@tonic-gate * This is a special case to restore a key/data pair to its original
552*0Sstevel@tonic-gate * location during recovery. We are guaranteed that the pair fits
553*0Sstevel@tonic-gate * on the page and is not the last pair on the page (because if it's
554*0Sstevel@tonic-gate * the last pair, the normal insert works).
555*0Sstevel@tonic-gate */
556*0Sstevel@tonic-gate void
__ham_reputpair(p,psize,ndx,key,data)557*0Sstevel@tonic-gate __ham_reputpair(p, psize, ndx, key, data)
558*0Sstevel@tonic-gate PAGE *p;
559*0Sstevel@tonic-gate u_int32_t psize, ndx;
560*0Sstevel@tonic-gate const DBT *key, *data;
561*0Sstevel@tonic-gate {
562*0Sstevel@tonic-gate db_indx_t i, movebytes, newbytes;
563*0Sstevel@tonic-gate u_int8_t *from;
564*0Sstevel@tonic-gate
565*0Sstevel@tonic-gate /* First shuffle the existing items up on the page. */
566*0Sstevel@tonic-gate movebytes =
567*0Sstevel@tonic-gate (ndx == 0 ? psize : p->inp[H_DATAINDEX(ndx - 1)]) - HOFFSET(p);
568*0Sstevel@tonic-gate newbytes = key->size + data->size;
569*0Sstevel@tonic-gate from = (u_int8_t *)p + HOFFSET(p);
570*0Sstevel@tonic-gate memmove(from - newbytes, from, movebytes);
571*0Sstevel@tonic-gate
572*0Sstevel@tonic-gate /*
573*0Sstevel@tonic-gate * Adjust the indices and move them up 2 spaces. Note that we
574*0Sstevel@tonic-gate * have to check the exit condition inside the loop just in case
575*0Sstevel@tonic-gate * we are dealing with index 0 (db_indx_t's are unsigned).
576*0Sstevel@tonic-gate */
577*0Sstevel@tonic-gate for (i = NUM_ENT(p) - 1; ; i-- ) {
578*0Sstevel@tonic-gate p->inp[i + 2] = p->inp[i] - newbytes;
579*0Sstevel@tonic-gate if (i == H_KEYINDEX(ndx))
580*0Sstevel@tonic-gate break;
581*0Sstevel@tonic-gate }
582*0Sstevel@tonic-gate
583*0Sstevel@tonic-gate /* Put the key and data on the page. */
584*0Sstevel@tonic-gate p->inp[H_KEYINDEX(ndx)] =
585*0Sstevel@tonic-gate (ndx == 0 ? psize : p->inp[H_DATAINDEX(ndx - 1)]) - key->size;
586*0Sstevel@tonic-gate p->inp[H_DATAINDEX(ndx)] = p->inp[H_KEYINDEX(ndx)] - data->size;
587*0Sstevel@tonic-gate memcpy(P_ENTRY(p, H_KEYINDEX(ndx)), key->data, key->size);
588*0Sstevel@tonic-gate memcpy(P_ENTRY(p, H_DATAINDEX(ndx)), data->data, data->size);
589*0Sstevel@tonic-gate
590*0Sstevel@tonic-gate /* Adjust page info. */
591*0Sstevel@tonic-gate HOFFSET(p) -= newbytes;
592*0Sstevel@tonic-gate NUM_ENT(p) += 2;
593*0Sstevel@tonic-gate }
594*0Sstevel@tonic-gate
595*0Sstevel@tonic-gate
596*0Sstevel@tonic-gate /*
597*0Sstevel@tonic-gate * PUBLIC: int __ham_del_pair __P((DBC *, int));
598*0Sstevel@tonic-gate */
599*0Sstevel@tonic-gate int
__ham_del_pair(dbc,reclaim_page)600*0Sstevel@tonic-gate __ham_del_pair(dbc, reclaim_page)
601*0Sstevel@tonic-gate DBC *dbc;
602*0Sstevel@tonic-gate int reclaim_page;
603*0Sstevel@tonic-gate {
604*0Sstevel@tonic-gate DB *dbp;
605*0Sstevel@tonic-gate HASH_CURSOR *hcp;
606*0Sstevel@tonic-gate DBT data_dbt, key_dbt;
607*0Sstevel@tonic-gate DB_ENV *dbenv;
608*0Sstevel@tonic-gate DB_LSN new_lsn, *n_lsn, tmp_lsn;
609*0Sstevel@tonic-gate PAGE *p;
610*0Sstevel@tonic-gate db_indx_t ndx;
611*0Sstevel@tonic-gate db_pgno_t chg_pgno, pgno;
612*0Sstevel@tonic-gate int ret, tret;
613*0Sstevel@tonic-gate
614*0Sstevel@tonic-gate dbp = dbc->dbp;
615*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
616*0Sstevel@tonic-gate
617*0Sstevel@tonic-gate dbenv = dbp->dbenv;
618*0Sstevel@tonic-gate ndx = hcp->bndx;
619*0Sstevel@tonic-gate if (hcp->pagep == NULL &&
620*0Sstevel@tonic-gate (ret = __ham_get_page(dbp, hcp->pgno, &hcp->pagep)) != 0)
621*0Sstevel@tonic-gate return (ret);
622*0Sstevel@tonic-gate
623*0Sstevel@tonic-gate p = hcp->pagep;
624*0Sstevel@tonic-gate
625*0Sstevel@tonic-gate /*
626*0Sstevel@tonic-gate * We optimize for the normal case which is when neither the key nor
627*0Sstevel@tonic-gate * the data are large. In this case, we write a single log record
628*0Sstevel@tonic-gate * and do the delete. If either is large, we'll call __big_delete
629*0Sstevel@tonic-gate * to remove the big item and then update the page to remove the
630*0Sstevel@tonic-gate * entry referring to the big item.
631*0Sstevel@tonic-gate */
632*0Sstevel@tonic-gate ret = 0;
633*0Sstevel@tonic-gate if (HPAGE_PTYPE(H_PAIRKEY(p, ndx)) == H_OFFPAGE) {
634*0Sstevel@tonic-gate memcpy(&pgno, HOFFPAGE_PGNO(P_ENTRY(p, H_KEYINDEX(ndx))),
635*0Sstevel@tonic-gate sizeof(db_pgno_t));
636*0Sstevel@tonic-gate ret = __db_doff(dbc, pgno, __ham_del_page);
637*0Sstevel@tonic-gate }
638*0Sstevel@tonic-gate
639*0Sstevel@tonic-gate if (ret == 0)
640*0Sstevel@tonic-gate switch (HPAGE_PTYPE(H_PAIRDATA(p, ndx))) {
641*0Sstevel@tonic-gate case H_OFFPAGE:
642*0Sstevel@tonic-gate memcpy(&pgno,
643*0Sstevel@tonic-gate HOFFPAGE_PGNO(P_ENTRY(p, H_DATAINDEX(ndx))),
644*0Sstevel@tonic-gate sizeof(db_pgno_t));
645*0Sstevel@tonic-gate ret = __db_doff(dbc, pgno, __ham_del_page);
646*0Sstevel@tonic-gate break;
647*0Sstevel@tonic-gate case H_OFFDUP:
648*0Sstevel@tonic-gate memcpy(&pgno,
649*0Sstevel@tonic-gate HOFFDUP_PGNO(P_ENTRY(p, H_DATAINDEX(ndx))),
650*0Sstevel@tonic-gate sizeof(db_pgno_t));
651*0Sstevel@tonic-gate ret = __db_ddup(dbc, pgno, __ham_del_page);
652*0Sstevel@tonic-gate F_CLR(hcp, H_ISDUP);
653*0Sstevel@tonic-gate break;
654*0Sstevel@tonic-gate case H_DUPLICATE:
655*0Sstevel@tonic-gate /*
656*0Sstevel@tonic-gate * If we delete a pair that is/was a duplicate, then
657*0Sstevel@tonic-gate * we had better clear the flag so that we update the
658*0Sstevel@tonic-gate * cursor appropriately.
659*0Sstevel@tonic-gate */
660*0Sstevel@tonic-gate F_CLR(hcp, H_ISDUP);
661*0Sstevel@tonic-gate break;
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate
664*0Sstevel@tonic-gate if (ret)
665*0Sstevel@tonic-gate return (ret);
666*0Sstevel@tonic-gate
667*0Sstevel@tonic-gate /* Now log the delete off this page. */
668*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
669*0Sstevel@tonic-gate key_dbt.data = P_ENTRY(p, H_KEYINDEX(ndx));
670*0Sstevel@tonic-gate key_dbt.size =
671*0Sstevel@tonic-gate LEN_HITEM(p, hcp->hdr->pagesize, H_KEYINDEX(ndx));
672*0Sstevel@tonic-gate data_dbt.data = P_ENTRY(p, H_DATAINDEX(ndx));
673*0Sstevel@tonic-gate data_dbt.size =
674*0Sstevel@tonic-gate LEN_HITEM(p, hcp->hdr->pagesize, H_DATAINDEX(ndx));
675*0Sstevel@tonic-gate
676*0Sstevel@tonic-gate if ((ret = __ham_insdel_log(dbenv->lg_info,
677*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, DELPAIR,
678*0Sstevel@tonic-gate dbp->log_fileid, PGNO(p), (u_int32_t)ndx,
679*0Sstevel@tonic-gate &LSN(p), &key_dbt, &data_dbt)) != 0)
680*0Sstevel@tonic-gate return (ret);
681*0Sstevel@tonic-gate
682*0Sstevel@tonic-gate /* Move lsn onto page. */
683*0Sstevel@tonic-gate LSN(p) = new_lsn;
684*0Sstevel@tonic-gate }
685*0Sstevel@tonic-gate
686*0Sstevel@tonic-gate __ham_dpair(dbp, p, ndx);
687*0Sstevel@tonic-gate
688*0Sstevel@tonic-gate /*
689*0Sstevel@tonic-gate * If we are locking, we will not maintain this, because it is
690*0Sstevel@tonic-gate * a hot spot.
691*0Sstevel@tonic-gate * XXX perhaps we can retain incremental numbers and apply them
692*0Sstevel@tonic-gate * later.
693*0Sstevel@tonic-gate */
694*0Sstevel@tonic-gate if (!F_ISSET(dbp, DB_AM_LOCKING))
695*0Sstevel@tonic-gate --hcp->hdr->nelem;
696*0Sstevel@tonic-gate
697*0Sstevel@tonic-gate /*
698*0Sstevel@tonic-gate * If we need to reclaim the page, then check if the page is empty.
699*0Sstevel@tonic-gate * There are two cases. If it's empty and it's not the first page
700*0Sstevel@tonic-gate * in the bucket (i.e., the bucket page) then we can simply remove
701*0Sstevel@tonic-gate * it. If it is the first chain in the bucket, then we need to copy
702*0Sstevel@tonic-gate * the second page into it and remove the second page.
703*0Sstevel@tonic-gate */
704*0Sstevel@tonic-gate if (reclaim_page && NUM_ENT(p) == 0 && PREV_PGNO(p) == PGNO_INVALID &&
705*0Sstevel@tonic-gate NEXT_PGNO(p) != PGNO_INVALID) {
706*0Sstevel@tonic-gate PAGE *n_pagep, *nn_pagep;
707*0Sstevel@tonic-gate db_pgno_t tmp_pgno;
708*0Sstevel@tonic-gate
709*0Sstevel@tonic-gate /*
710*0Sstevel@tonic-gate * First page in chain is empty and we know that there
711*0Sstevel@tonic-gate * are more pages in the chain.
712*0Sstevel@tonic-gate */
713*0Sstevel@tonic-gate if ((ret =
714*0Sstevel@tonic-gate __ham_get_page(dbp, NEXT_PGNO(p), &n_pagep)) != 0)
715*0Sstevel@tonic-gate return (ret);
716*0Sstevel@tonic-gate
717*0Sstevel@tonic-gate if (NEXT_PGNO(n_pagep) != PGNO_INVALID) {
718*0Sstevel@tonic-gate if ((ret =
719*0Sstevel@tonic-gate __ham_get_page(dbp, NEXT_PGNO(n_pagep),
720*0Sstevel@tonic-gate &nn_pagep)) != 0) {
721*0Sstevel@tonic-gate (void) __ham_put_page(dbp, n_pagep, 0);
722*0Sstevel@tonic-gate return (ret);
723*0Sstevel@tonic-gate }
724*0Sstevel@tonic-gate }
725*0Sstevel@tonic-gate
726*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
727*0Sstevel@tonic-gate key_dbt.data = n_pagep;
728*0Sstevel@tonic-gate key_dbt.size = hcp->hdr->pagesize;
729*0Sstevel@tonic-gate if ((ret = __ham_copypage_log(dbenv->lg_info,
730*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, dbp->log_fileid, PGNO(p),
731*0Sstevel@tonic-gate &LSN(p), PGNO(n_pagep), &LSN(n_pagep),
732*0Sstevel@tonic-gate NEXT_PGNO(n_pagep),
733*0Sstevel@tonic-gate NEXT_PGNO(n_pagep) == PGNO_INVALID ? NULL :
734*0Sstevel@tonic-gate &LSN(nn_pagep), &key_dbt)) != 0)
735*0Sstevel@tonic-gate return (ret);
736*0Sstevel@tonic-gate
737*0Sstevel@tonic-gate /* Move lsn onto page. */
738*0Sstevel@tonic-gate LSN(p) = new_lsn; /* Structure assignment. */
739*0Sstevel@tonic-gate LSN(n_pagep) = new_lsn;
740*0Sstevel@tonic-gate if (NEXT_PGNO(n_pagep) != PGNO_INVALID)
741*0Sstevel@tonic-gate LSN(nn_pagep) = new_lsn;
742*0Sstevel@tonic-gate }
743*0Sstevel@tonic-gate if (NEXT_PGNO(n_pagep) != PGNO_INVALID) {
744*0Sstevel@tonic-gate PREV_PGNO(nn_pagep) = PGNO(p);
745*0Sstevel@tonic-gate (void)__ham_put_page(dbp, nn_pagep, 1);
746*0Sstevel@tonic-gate }
747*0Sstevel@tonic-gate
748*0Sstevel@tonic-gate tmp_pgno = PGNO(p);
749*0Sstevel@tonic-gate tmp_lsn = LSN(p);
750*0Sstevel@tonic-gate memcpy(p, n_pagep, hcp->hdr->pagesize);
751*0Sstevel@tonic-gate PGNO(p) = tmp_pgno;
752*0Sstevel@tonic-gate LSN(p) = tmp_lsn;
753*0Sstevel@tonic-gate PREV_PGNO(p) = PGNO_INVALID;
754*0Sstevel@tonic-gate
755*0Sstevel@tonic-gate /*
756*0Sstevel@tonic-gate * Cursor is advanced to the beginning of the next page.
757*0Sstevel@tonic-gate */
758*0Sstevel@tonic-gate hcp->bndx = 0;
759*0Sstevel@tonic-gate hcp->pgno = PGNO(p);
760*0Sstevel@tonic-gate F_SET(hcp, H_DELETED);
761*0Sstevel@tonic-gate chg_pgno = PGNO(p);
762*0Sstevel@tonic-gate if ((ret = __ham_dirty_page(dbp, p)) != 0 ||
763*0Sstevel@tonic-gate (ret = __ham_del_page(dbc, n_pagep)) != 0)
764*0Sstevel@tonic-gate return (ret);
765*0Sstevel@tonic-gate } else if (reclaim_page &&
766*0Sstevel@tonic-gate NUM_ENT(p) == 0 && PREV_PGNO(p) != PGNO_INVALID) {
767*0Sstevel@tonic-gate PAGE *n_pagep, *p_pagep;
768*0Sstevel@tonic-gate
769*0Sstevel@tonic-gate if ((ret =
770*0Sstevel@tonic-gate __ham_get_page(dbp, PREV_PGNO(p), &p_pagep)) != 0)
771*0Sstevel@tonic-gate return (ret);
772*0Sstevel@tonic-gate
773*0Sstevel@tonic-gate if (NEXT_PGNO(p) != PGNO_INVALID) {
774*0Sstevel@tonic-gate if ((ret = __ham_get_page(dbp,
775*0Sstevel@tonic-gate NEXT_PGNO(p), &n_pagep)) != 0) {
776*0Sstevel@tonic-gate (void)__ham_put_page(dbp, p_pagep, 0);
777*0Sstevel@tonic-gate return (ret);
778*0Sstevel@tonic-gate }
779*0Sstevel@tonic-gate n_lsn = &LSN(n_pagep);
780*0Sstevel@tonic-gate } else {
781*0Sstevel@tonic-gate n_pagep = NULL;
782*0Sstevel@tonic-gate n_lsn = NULL;
783*0Sstevel@tonic-gate }
784*0Sstevel@tonic-gate
785*0Sstevel@tonic-gate NEXT_PGNO(p_pagep) = NEXT_PGNO(p);
786*0Sstevel@tonic-gate if (n_pagep != NULL)
787*0Sstevel@tonic-gate PREV_PGNO(n_pagep) = PGNO(p_pagep);
788*0Sstevel@tonic-gate
789*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
790*0Sstevel@tonic-gate if ((ret = __ham_newpage_log(dbenv->lg_info,
791*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, DELOVFL,
792*0Sstevel@tonic-gate dbp->log_fileid, PREV_PGNO(p), &LSN(p_pagep),
793*0Sstevel@tonic-gate PGNO(p), &LSN(p), NEXT_PGNO(p), n_lsn)) != 0)
794*0Sstevel@tonic-gate return (ret);
795*0Sstevel@tonic-gate
796*0Sstevel@tonic-gate /* Move lsn onto page. */
797*0Sstevel@tonic-gate LSN(p_pagep) = new_lsn; /* Structure assignment. */
798*0Sstevel@tonic-gate if (n_pagep)
799*0Sstevel@tonic-gate LSN(n_pagep) = new_lsn;
800*0Sstevel@tonic-gate LSN(p) = new_lsn;
801*0Sstevel@tonic-gate }
802*0Sstevel@tonic-gate hcp->pgno = NEXT_PGNO(p);
803*0Sstevel@tonic-gate hcp->bndx = 0;
804*0Sstevel@tonic-gate /*
805*0Sstevel@tonic-gate * Since we are about to delete the cursor page and we have
806*0Sstevel@tonic-gate * just moved the cursor, we need to make sure that the
807*0Sstevel@tonic-gate * old page pointer isn't left hanging around in the cursor.
808*0Sstevel@tonic-gate */
809*0Sstevel@tonic-gate hcp->pagep = NULL;
810*0Sstevel@tonic-gate chg_pgno = PGNO(p);
811*0Sstevel@tonic-gate ret = __ham_del_page(dbc, p);
812*0Sstevel@tonic-gate if ((tret = __ham_put_page(dbp, p_pagep, 1)) != 0 &&
813*0Sstevel@tonic-gate ret == 0)
814*0Sstevel@tonic-gate ret = tret;
815*0Sstevel@tonic-gate if (n_pagep != NULL &&
816*0Sstevel@tonic-gate (tret = __ham_put_page(dbp, n_pagep, 1)) != 0 &&
817*0Sstevel@tonic-gate ret == 0)
818*0Sstevel@tonic-gate ret = tret;
819*0Sstevel@tonic-gate if (ret != 0)
820*0Sstevel@tonic-gate return (ret);
821*0Sstevel@tonic-gate } else {
822*0Sstevel@tonic-gate /*
823*0Sstevel@tonic-gate * Mark item deleted so that we don't try to return it, and
824*0Sstevel@tonic-gate * so that we update the cursor correctly on the next call
825*0Sstevel@tonic-gate * to next.
826*0Sstevel@tonic-gate */
827*0Sstevel@tonic-gate F_SET(hcp, H_DELETED);
828*0Sstevel@tonic-gate chg_pgno = hcp->pgno;
829*0Sstevel@tonic-gate ret = __ham_dirty_page(dbp, p);
830*0Sstevel@tonic-gate }
831*0Sstevel@tonic-gate __ham_c_update(hcp, chg_pgno, 0, 0, 0);
832*0Sstevel@tonic-gate
833*0Sstevel@tonic-gate /*
834*0Sstevel@tonic-gate * Since we just deleted a pair from the master page, anything
835*0Sstevel@tonic-gate * in hcp->dpgno should be cleared.
836*0Sstevel@tonic-gate */
837*0Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID;
838*0Sstevel@tonic-gate
839*0Sstevel@tonic-gate F_CLR(hcp, H_OK);
840*0Sstevel@tonic-gate return (ret);
841*0Sstevel@tonic-gate }
842*0Sstevel@tonic-gate
843*0Sstevel@tonic-gate /*
844*0Sstevel@tonic-gate * __ham_replpair --
845*0Sstevel@tonic-gate * Given the key data indicated by the cursor, replace part/all of it
846*0Sstevel@tonic-gate * according to the fields in the dbt.
847*0Sstevel@tonic-gate *
848*0Sstevel@tonic-gate * PUBLIC: int __ham_replpair __P((DBC *, DBT *, u_int32_t));
849*0Sstevel@tonic-gate */
850*0Sstevel@tonic-gate int
__ham_replpair(dbc,dbt,make_dup)851*0Sstevel@tonic-gate __ham_replpair(dbc, dbt, make_dup)
852*0Sstevel@tonic-gate DBC *dbc;
853*0Sstevel@tonic-gate DBT *dbt;
854*0Sstevel@tonic-gate u_int32_t make_dup;
855*0Sstevel@tonic-gate {
856*0Sstevel@tonic-gate DB *dbp;
857*0Sstevel@tonic-gate HASH_CURSOR *hcp;
858*0Sstevel@tonic-gate DBT old_dbt, tdata, tmp;
859*0Sstevel@tonic-gate DB_LSN new_lsn;
860*0Sstevel@tonic-gate int32_t change; /* XXX: Possible overflow. */
861*0Sstevel@tonic-gate u_int32_t len;
862*0Sstevel@tonic-gate int is_big, ret, type;
863*0Sstevel@tonic-gate u_int8_t *beg, *dest, *end, *hk, *src;
864*0Sstevel@tonic-gate
865*0Sstevel@tonic-gate /*
866*0Sstevel@tonic-gate * Big item replacements are handled in generic code.
867*0Sstevel@tonic-gate * Items that fit on the current page fall into 4 classes.
868*0Sstevel@tonic-gate * 1. On-page element, same size
869*0Sstevel@tonic-gate * 2. On-page element, new is bigger (fits)
870*0Sstevel@tonic-gate * 3. On-page element, new is bigger (does not fit)
871*0Sstevel@tonic-gate * 4. On-page element, old is bigger
872*0Sstevel@tonic-gate * Numbers 1, 2, and 4 are essentially the same (and should
873*0Sstevel@tonic-gate * be the common case). We handle case 3 as a delete and
874*0Sstevel@tonic-gate * add.
875*0Sstevel@tonic-gate */
876*0Sstevel@tonic-gate dbp = dbc->dbp;
877*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
878*0Sstevel@tonic-gate
879*0Sstevel@tonic-gate /*
880*0Sstevel@tonic-gate * We need to compute the number of bytes that we are adding or
881*0Sstevel@tonic-gate * removing from the entry. Normally, we can simply substract
882*0Sstevel@tonic-gate * the number of bytes we are replacing (dbt->dlen) from the
883*0Sstevel@tonic-gate * number of bytes we are inserting (dbt->size). However, if
884*0Sstevel@tonic-gate * we are doing a partial put off the end of a record, then this
885*0Sstevel@tonic-gate * formula doesn't work, because we are essentially adding
886*0Sstevel@tonic-gate * new bytes.
887*0Sstevel@tonic-gate */
888*0Sstevel@tonic-gate change = dbt->size - dbt->dlen;
889*0Sstevel@tonic-gate
890*0Sstevel@tonic-gate hk = H_PAIRDATA(hcp->pagep, hcp->bndx);
891*0Sstevel@tonic-gate is_big = HPAGE_PTYPE(hk) == H_OFFPAGE;
892*0Sstevel@tonic-gate
893*0Sstevel@tonic-gate if (is_big)
894*0Sstevel@tonic-gate memcpy(&len, HOFFPAGE_TLEN(hk), sizeof(u_int32_t));
895*0Sstevel@tonic-gate else
896*0Sstevel@tonic-gate len = LEN_HKEYDATA(hcp->pagep,
897*0Sstevel@tonic-gate dbp->pgsize, H_DATAINDEX(hcp->bndx));
898*0Sstevel@tonic-gate
899*0Sstevel@tonic-gate if (dbt->doff + dbt->dlen > len)
900*0Sstevel@tonic-gate change += dbt->doff + dbt->dlen - len;
901*0Sstevel@tonic-gate
902*0Sstevel@tonic-gate
903*0Sstevel@tonic-gate if (change > (int32_t)P_FREESPACE(hcp->pagep) || is_big) {
904*0Sstevel@tonic-gate /*
905*0Sstevel@tonic-gate * Case 3 -- two subcases.
906*0Sstevel@tonic-gate * A. This is not really a partial operation, but an overwrite.
907*0Sstevel@tonic-gate * Simple del and add works.
908*0Sstevel@tonic-gate * B. This is a partial and we need to construct the data that
909*0Sstevel@tonic-gate * we are really inserting (yuck).
910*0Sstevel@tonic-gate * In both cases, we need to grab the key off the page (in
911*0Sstevel@tonic-gate * some cases we could do this outside of this routine; for
912*0Sstevel@tonic-gate * cleanliness we do it here. If you happen to be on a big
913*0Sstevel@tonic-gate * key, this could be a performance hit).
914*0Sstevel@tonic-gate */
915*0Sstevel@tonic-gate tmp.flags = 0;
916*0Sstevel@tonic-gate F_SET(&tmp, DB_DBT_MALLOC | DB_DBT_INTERNAL);
917*0Sstevel@tonic-gate if ((ret =
918*0Sstevel@tonic-gate __db_ret(dbp, hcp->pagep, H_KEYINDEX(hcp->bndx),
919*0Sstevel@tonic-gate &tmp, &dbc->rkey.data, &dbc->rkey.size)) != 0)
920*0Sstevel@tonic-gate return (ret);
921*0Sstevel@tonic-gate
922*0Sstevel@tonic-gate if (dbt->doff == 0 && dbt->dlen == len) {
923*0Sstevel@tonic-gate ret = __ham_del_pair(dbc, 0);
924*0Sstevel@tonic-gate if (ret == 0)
925*0Sstevel@tonic-gate ret = __ham_add_el(dbc, &tmp, dbt, H_KEYDATA);
926*0Sstevel@tonic-gate } else { /* Case B */
927*0Sstevel@tonic-gate type = HPAGE_PTYPE(hk) != H_OFFPAGE ?
928*0Sstevel@tonic-gate HPAGE_PTYPE(hk) : H_KEYDATA;
929*0Sstevel@tonic-gate tdata.flags = 0;
930*0Sstevel@tonic-gate F_SET(&tdata, DB_DBT_MALLOC | DB_DBT_INTERNAL);
931*0Sstevel@tonic-gate
932*0Sstevel@tonic-gate if ((ret = __db_ret(dbp, hcp->pagep,
933*0Sstevel@tonic-gate H_DATAINDEX(hcp->bndx), &tdata, &dbc->rdata.data,
934*0Sstevel@tonic-gate &dbc->rdata.size)) != 0)
935*0Sstevel@tonic-gate goto err;
936*0Sstevel@tonic-gate
937*0Sstevel@tonic-gate /* Now we can delete the item. */
938*0Sstevel@tonic-gate if ((ret = __ham_del_pair(dbc, 0)) != 0) {
939*0Sstevel@tonic-gate __os_free(tdata.data, tdata.size);
940*0Sstevel@tonic-gate goto err;
941*0Sstevel@tonic-gate }
942*0Sstevel@tonic-gate
943*0Sstevel@tonic-gate /* Now shift old data around to make room for new. */
944*0Sstevel@tonic-gate if (change > 0) {
945*0Sstevel@tonic-gate if ((ret = __os_realloc(&tdata.data,
946*0Sstevel@tonic-gate tdata.size + change)) != 0)
947*0Sstevel@tonic-gate return (ret);
948*0Sstevel@tonic-gate memset((u_int8_t *)tdata.data + tdata.size,
949*0Sstevel@tonic-gate 0, change);
950*0Sstevel@tonic-gate }
951*0Sstevel@tonic-gate end = (u_int8_t *)tdata.data + tdata.size;
952*0Sstevel@tonic-gate
953*0Sstevel@tonic-gate src = (u_int8_t *)tdata.data + dbt->doff + dbt->dlen;
954*0Sstevel@tonic-gate if (src < end && tdata.size > dbt->doff + dbt->dlen) {
955*0Sstevel@tonic-gate len = tdata.size - dbt->doff - dbt->dlen;
956*0Sstevel@tonic-gate dest = src + change;
957*0Sstevel@tonic-gate memmove(dest, src, len);
958*0Sstevel@tonic-gate }
959*0Sstevel@tonic-gate memcpy((u_int8_t *)tdata.data + dbt->doff,
960*0Sstevel@tonic-gate dbt->data, dbt->size);
961*0Sstevel@tonic-gate tdata.size += change;
962*0Sstevel@tonic-gate
963*0Sstevel@tonic-gate /* Now add the pair. */
964*0Sstevel@tonic-gate ret = __ham_add_el(dbc, &tmp, &tdata, type);
965*0Sstevel@tonic-gate __os_free(tdata.data, tdata.size);
966*0Sstevel@tonic-gate }
967*0Sstevel@tonic-gate err: __os_free(tmp.data, tmp.size);
968*0Sstevel@tonic-gate return (ret);
969*0Sstevel@tonic-gate }
970*0Sstevel@tonic-gate
971*0Sstevel@tonic-gate /*
972*0Sstevel@tonic-gate * Set up pointer into existing data. Do it before the log
973*0Sstevel@tonic-gate * message so we can use it inside of the log setup.
974*0Sstevel@tonic-gate */
975*0Sstevel@tonic-gate beg = HKEYDATA_DATA(H_PAIRDATA(hcp->pagep, hcp->bndx));
976*0Sstevel@tonic-gate beg += dbt->doff;
977*0Sstevel@tonic-gate
978*0Sstevel@tonic-gate /*
979*0Sstevel@tonic-gate * If we are going to have to move bytes at all, figure out
980*0Sstevel@tonic-gate * all the parameters here. Then log the call before moving
981*0Sstevel@tonic-gate * anything around.
982*0Sstevel@tonic-gate */
983*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
984*0Sstevel@tonic-gate old_dbt.data = beg;
985*0Sstevel@tonic-gate old_dbt.size = dbt->dlen;
986*0Sstevel@tonic-gate if ((ret = __ham_replace_log(dbp->dbenv->lg_info,
987*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, dbp->log_fileid, PGNO(hcp->pagep),
988*0Sstevel@tonic-gate (u_int32_t)H_DATAINDEX(hcp->bndx), &LSN(hcp->pagep),
989*0Sstevel@tonic-gate (u_int32_t)dbt->doff, &old_dbt, dbt, make_dup)) != 0)
990*0Sstevel@tonic-gate return (ret);
991*0Sstevel@tonic-gate
992*0Sstevel@tonic-gate LSN(hcp->pagep) = new_lsn; /* Structure assignment. */
993*0Sstevel@tonic-gate }
994*0Sstevel@tonic-gate
995*0Sstevel@tonic-gate __ham_onpage_replace(hcp->pagep, dbp->pgsize,
996*0Sstevel@tonic-gate (u_int32_t)H_DATAINDEX(hcp->bndx), (int32_t)dbt->doff, change, dbt);
997*0Sstevel@tonic-gate
998*0Sstevel@tonic-gate return (0);
999*0Sstevel@tonic-gate }
1000*0Sstevel@tonic-gate
1001*0Sstevel@tonic-gate /*
1002*0Sstevel@tonic-gate * Replace data on a page with new data, possibly growing or shrinking what's
1003*0Sstevel@tonic-gate * there. This is called on two different occasions. On one (from replpair)
1004*0Sstevel@tonic-gate * we are interested in changing only the data. On the other (from recovery)
1005*0Sstevel@tonic-gate * we are replacing the entire data (header and all) with a new element. In
1006*0Sstevel@tonic-gate * the latter case, the off argument is negative.
1007*0Sstevel@tonic-gate * pagep: the page that we're changing
1008*0Sstevel@tonic-gate * ndx: page index of the element that is growing/shrinking.
1009*0Sstevel@tonic-gate * off: Offset at which we are beginning the replacement.
1010*0Sstevel@tonic-gate * change: the number of bytes (+ or -) that the element is growing/shrinking.
1011*0Sstevel@tonic-gate * dbt: the new data that gets written at beg.
1012*0Sstevel@tonic-gate * PUBLIC: void __ham_onpage_replace __P((PAGE *, size_t, u_int32_t, int32_t,
1013*0Sstevel@tonic-gate * PUBLIC: int32_t, DBT *));
1014*0Sstevel@tonic-gate */
1015*0Sstevel@tonic-gate void
__ham_onpage_replace(pagep,pgsize,ndx,off,change,dbt)1016*0Sstevel@tonic-gate __ham_onpage_replace(pagep, pgsize, ndx, off, change, dbt)
1017*0Sstevel@tonic-gate PAGE *pagep;
1018*0Sstevel@tonic-gate size_t pgsize;
1019*0Sstevel@tonic-gate u_int32_t ndx;
1020*0Sstevel@tonic-gate int32_t off;
1021*0Sstevel@tonic-gate int32_t change;
1022*0Sstevel@tonic-gate DBT *dbt;
1023*0Sstevel@tonic-gate {
1024*0Sstevel@tonic-gate db_indx_t i;
1025*0Sstevel@tonic-gate int32_t len;
1026*0Sstevel@tonic-gate u_int8_t *src, *dest;
1027*0Sstevel@tonic-gate int zero_me;
1028*0Sstevel@tonic-gate
1029*0Sstevel@tonic-gate if (change != 0) {
1030*0Sstevel@tonic-gate zero_me = 0;
1031*0Sstevel@tonic-gate src = (u_int8_t *)(pagep) + HOFFSET(pagep);
1032*0Sstevel@tonic-gate if (off < 0)
1033*0Sstevel@tonic-gate len = pagep->inp[ndx] - HOFFSET(pagep);
1034*0Sstevel@tonic-gate else if ((u_int32_t)off >= LEN_HKEYDATA(pagep, pgsize, ndx)) {
1035*0Sstevel@tonic-gate len = HKEYDATA_DATA(P_ENTRY(pagep, ndx)) +
1036*0Sstevel@tonic-gate LEN_HKEYDATA(pagep, pgsize, ndx) - src;
1037*0Sstevel@tonic-gate zero_me = 1;
1038*0Sstevel@tonic-gate } else
1039*0Sstevel@tonic-gate len = (HKEYDATA_DATA(P_ENTRY(pagep, ndx)) + off) - src;
1040*0Sstevel@tonic-gate dest = src - change;
1041*0Sstevel@tonic-gate memmove(dest, src, len);
1042*0Sstevel@tonic-gate if (zero_me)
1043*0Sstevel@tonic-gate memset(dest + len, 0, change);
1044*0Sstevel@tonic-gate
1045*0Sstevel@tonic-gate /* Now update the indices. */
1046*0Sstevel@tonic-gate for (i = ndx; i < NUM_ENT(pagep); i++)
1047*0Sstevel@tonic-gate pagep->inp[i] -= change;
1048*0Sstevel@tonic-gate HOFFSET(pagep) -= change;
1049*0Sstevel@tonic-gate }
1050*0Sstevel@tonic-gate if (off >= 0)
1051*0Sstevel@tonic-gate memcpy(HKEYDATA_DATA(P_ENTRY(pagep, ndx)) + off,
1052*0Sstevel@tonic-gate dbt->data, dbt->size);
1053*0Sstevel@tonic-gate else
1054*0Sstevel@tonic-gate memcpy(P_ENTRY(pagep, ndx), dbt->data, dbt->size);
1055*0Sstevel@tonic-gate }
1056*0Sstevel@tonic-gate
1057*0Sstevel@tonic-gate /*
1058*0Sstevel@tonic-gate * PUBLIC: int __ham_split_page __P((DBC *, u_int32_t, u_int32_t));
1059*0Sstevel@tonic-gate */
1060*0Sstevel@tonic-gate int
__ham_split_page(dbc,obucket,nbucket)1061*0Sstevel@tonic-gate __ham_split_page(dbc, obucket, nbucket)
1062*0Sstevel@tonic-gate DBC *dbc;
1063*0Sstevel@tonic-gate u_int32_t obucket, nbucket;
1064*0Sstevel@tonic-gate {
1065*0Sstevel@tonic-gate DB *dbp;
1066*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1067*0Sstevel@tonic-gate DBT key, page_dbt;
1068*0Sstevel@tonic-gate DB_ENV *dbenv;
1069*0Sstevel@tonic-gate DB_LSN new_lsn;
1070*0Sstevel@tonic-gate PAGE **pp, *old_pagep, *temp_pagep, *new_pagep;
1071*0Sstevel@tonic-gate db_indx_t n;
1072*0Sstevel@tonic-gate db_pgno_t bucket_pgno, next_pgno;
1073*0Sstevel@tonic-gate u_int32_t big_len, len;
1074*0Sstevel@tonic-gate int ret, tret;
1075*0Sstevel@tonic-gate void *big_buf;
1076*0Sstevel@tonic-gate
1077*0Sstevel@tonic-gate dbp = dbc->dbp;
1078*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1079*0Sstevel@tonic-gate dbenv = dbp->dbenv;
1080*0Sstevel@tonic-gate temp_pagep = old_pagep = new_pagep = NULL;
1081*0Sstevel@tonic-gate
1082*0Sstevel@tonic-gate bucket_pgno = BUCKET_TO_PAGE(hcp, obucket);
1083*0Sstevel@tonic-gate if ((ret = __ham_get_page(dbp, bucket_pgno, &old_pagep)) != 0)
1084*0Sstevel@tonic-gate return (ret);
1085*0Sstevel@tonic-gate if ((ret = __ham_new_page(dbp, BUCKET_TO_PAGE(hcp, nbucket), P_HASH,
1086*0Sstevel@tonic-gate &new_pagep)) != 0)
1087*0Sstevel@tonic-gate goto err;
1088*0Sstevel@tonic-gate
1089*0Sstevel@tonic-gate temp_pagep = hcp->split_buf;
1090*0Sstevel@tonic-gate memcpy(temp_pagep, old_pagep, hcp->hdr->pagesize);
1091*0Sstevel@tonic-gate
1092*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
1093*0Sstevel@tonic-gate page_dbt.size = hcp->hdr->pagesize;
1094*0Sstevel@tonic-gate page_dbt.data = old_pagep;
1095*0Sstevel@tonic-gate if ((ret = __ham_splitdata_log(dbenv->lg_info,
1096*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, dbp->log_fileid, SPLITOLD,
1097*0Sstevel@tonic-gate PGNO(old_pagep), &page_dbt, &LSN(old_pagep))) != 0)
1098*0Sstevel@tonic-gate goto err;
1099*0Sstevel@tonic-gate }
1100*0Sstevel@tonic-gate
1101*0Sstevel@tonic-gate P_INIT(old_pagep, hcp->hdr->pagesize, PGNO(old_pagep), PGNO_INVALID,
1102*0Sstevel@tonic-gate PGNO_INVALID, 0, P_HASH);
1103*0Sstevel@tonic-gate
1104*0Sstevel@tonic-gate if (DB_LOGGING(dbc))
1105*0Sstevel@tonic-gate LSN(old_pagep) = new_lsn; /* Structure assignment. */
1106*0Sstevel@tonic-gate
1107*0Sstevel@tonic-gate big_len = 0;
1108*0Sstevel@tonic-gate big_buf = NULL;
1109*0Sstevel@tonic-gate key.flags = 0;
1110*0Sstevel@tonic-gate while (temp_pagep != NULL) {
1111*0Sstevel@tonic-gate for (n = 0; n < (db_indx_t)H_NUMPAIRS(temp_pagep); n++) {
1112*0Sstevel@tonic-gate if ((ret =
1113*0Sstevel@tonic-gate __db_ret(dbp, temp_pagep, H_KEYINDEX(n),
1114*0Sstevel@tonic-gate &key, &big_buf, &big_len)) != 0)
1115*0Sstevel@tonic-gate goto err;
1116*0Sstevel@tonic-gate
1117*0Sstevel@tonic-gate if (__ham_call_hash(hcp, key.data, key.size)
1118*0Sstevel@tonic-gate == obucket)
1119*0Sstevel@tonic-gate pp = &old_pagep;
1120*0Sstevel@tonic-gate else
1121*0Sstevel@tonic-gate pp = &new_pagep;
1122*0Sstevel@tonic-gate
1123*0Sstevel@tonic-gate /*
1124*0Sstevel@tonic-gate * Figure out how many bytes we need on the new
1125*0Sstevel@tonic-gate * page to store the key/data pair.
1126*0Sstevel@tonic-gate */
1127*0Sstevel@tonic-gate
1128*0Sstevel@tonic-gate len = LEN_HITEM(temp_pagep, hcp->hdr->pagesize,
1129*0Sstevel@tonic-gate H_DATAINDEX(n)) +
1130*0Sstevel@tonic-gate LEN_HITEM(temp_pagep, hcp->hdr->pagesize,
1131*0Sstevel@tonic-gate H_KEYINDEX(n)) +
1132*0Sstevel@tonic-gate 2 * sizeof(db_indx_t);
1133*0Sstevel@tonic-gate
1134*0Sstevel@tonic-gate if (P_FREESPACE(*pp) < len) {
1135*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
1136*0Sstevel@tonic-gate page_dbt.size = hcp->hdr->pagesize;
1137*0Sstevel@tonic-gate page_dbt.data = *pp;
1138*0Sstevel@tonic-gate if ((ret = __ham_splitdata_log(
1139*0Sstevel@tonic-gate dbenv->lg_info, dbc->txn,
1140*0Sstevel@tonic-gate &new_lsn, 0, dbp->log_fileid,
1141*0Sstevel@tonic-gate SPLITNEW, PGNO(*pp), &page_dbt,
1142*0Sstevel@tonic-gate &LSN(*pp))) != 0)
1143*0Sstevel@tonic-gate goto err;
1144*0Sstevel@tonic-gate LSN(*pp) = new_lsn;
1145*0Sstevel@tonic-gate }
1146*0Sstevel@tonic-gate if ((ret =
1147*0Sstevel@tonic-gate __ham_add_ovflpage(dbc, *pp, 1, pp)) != 0)
1148*0Sstevel@tonic-gate goto err;
1149*0Sstevel@tonic-gate }
1150*0Sstevel@tonic-gate __ham_copy_item(dbp->pgsize,
1151*0Sstevel@tonic-gate temp_pagep, H_KEYINDEX(n), *pp);
1152*0Sstevel@tonic-gate __ham_copy_item(dbp->pgsize,
1153*0Sstevel@tonic-gate temp_pagep, H_DATAINDEX(n), *pp);
1154*0Sstevel@tonic-gate }
1155*0Sstevel@tonic-gate next_pgno = NEXT_PGNO(temp_pagep);
1156*0Sstevel@tonic-gate
1157*0Sstevel@tonic-gate /* Clear temp_page; if it's a link overflow page, free it. */
1158*0Sstevel@tonic-gate if (PGNO(temp_pagep) != bucket_pgno && (ret =
1159*0Sstevel@tonic-gate __ham_del_page(dbc, temp_pagep)) != 0)
1160*0Sstevel@tonic-gate goto err;
1161*0Sstevel@tonic-gate
1162*0Sstevel@tonic-gate if (next_pgno == PGNO_INVALID)
1163*0Sstevel@tonic-gate temp_pagep = NULL;
1164*0Sstevel@tonic-gate else if ((ret =
1165*0Sstevel@tonic-gate __ham_get_page(dbp, next_pgno, &temp_pagep)) != 0)
1166*0Sstevel@tonic-gate goto err;
1167*0Sstevel@tonic-gate
1168*0Sstevel@tonic-gate if (temp_pagep != NULL && DB_LOGGING(dbc)) {
1169*0Sstevel@tonic-gate page_dbt.size = hcp->hdr->pagesize;
1170*0Sstevel@tonic-gate page_dbt.data = temp_pagep;
1171*0Sstevel@tonic-gate if ((ret = __ham_splitdata_log(dbenv->lg_info,
1172*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, dbp->log_fileid,
1173*0Sstevel@tonic-gate SPLITOLD, PGNO(temp_pagep),
1174*0Sstevel@tonic-gate &page_dbt, &LSN(temp_pagep))) != 0)
1175*0Sstevel@tonic-gate goto err;
1176*0Sstevel@tonic-gate LSN(temp_pagep) = new_lsn;
1177*0Sstevel@tonic-gate }
1178*0Sstevel@tonic-gate }
1179*0Sstevel@tonic-gate if (big_buf != NULL)
1180*0Sstevel@tonic-gate __os_free(big_buf, big_len);
1181*0Sstevel@tonic-gate
1182*0Sstevel@tonic-gate /*
1183*0Sstevel@tonic-gate * If the original bucket spanned multiple pages, then we've got
1184*0Sstevel@tonic-gate * a pointer to a page that used to be on the bucket chain. It
1185*0Sstevel@tonic-gate * should be deleted.
1186*0Sstevel@tonic-gate */
1187*0Sstevel@tonic-gate if (temp_pagep != NULL && PGNO(temp_pagep) != bucket_pgno &&
1188*0Sstevel@tonic-gate (ret = __ham_del_page(dbc, temp_pagep)) != 0)
1189*0Sstevel@tonic-gate goto err;
1190*0Sstevel@tonic-gate
1191*0Sstevel@tonic-gate /*
1192*0Sstevel@tonic-gate * Write new buckets out.
1193*0Sstevel@tonic-gate */
1194*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
1195*0Sstevel@tonic-gate page_dbt.size = hcp->hdr->pagesize;
1196*0Sstevel@tonic-gate page_dbt.data = old_pagep;
1197*0Sstevel@tonic-gate if ((ret = __ham_splitdata_log(dbenv->lg_info,
1198*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, dbp->log_fileid,
1199*0Sstevel@tonic-gate SPLITNEW, PGNO(old_pagep),
1200*0Sstevel@tonic-gate &page_dbt, &LSN(old_pagep))) != 0)
1201*0Sstevel@tonic-gate goto err;
1202*0Sstevel@tonic-gate LSN(old_pagep) = new_lsn;
1203*0Sstevel@tonic-gate
1204*0Sstevel@tonic-gate page_dbt.data = new_pagep;
1205*0Sstevel@tonic-gate if ((ret = __ham_splitdata_log(dbenv->lg_info,
1206*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, dbp->log_fileid,
1207*0Sstevel@tonic-gate SPLITNEW, PGNO(new_pagep), &page_dbt, &LSN(new_pagep))) != 0)
1208*0Sstevel@tonic-gate goto err;
1209*0Sstevel@tonic-gate LSN(new_pagep) = new_lsn;
1210*0Sstevel@tonic-gate }
1211*0Sstevel@tonic-gate ret = __ham_put_page(dbp, old_pagep, 1);
1212*0Sstevel@tonic-gate if ((tret = __ham_put_page(dbp, new_pagep, 1)) != 0 &&
1213*0Sstevel@tonic-gate ret == 0)
1214*0Sstevel@tonic-gate ret = tret;
1215*0Sstevel@tonic-gate
1216*0Sstevel@tonic-gate if (0) {
1217*0Sstevel@tonic-gate err: if (old_pagep != NULL)
1218*0Sstevel@tonic-gate (void)__ham_put_page(dbp, old_pagep, 1);
1219*0Sstevel@tonic-gate if (new_pagep != NULL)
1220*0Sstevel@tonic-gate (void)__ham_put_page(dbp, new_pagep, 1);
1221*0Sstevel@tonic-gate if (temp_pagep != NULL && PGNO(temp_pagep) != bucket_pgno)
1222*0Sstevel@tonic-gate (void)__ham_put_page(dbp, temp_pagep, 1);
1223*0Sstevel@tonic-gate }
1224*0Sstevel@tonic-gate return (ret);
1225*0Sstevel@tonic-gate }
1226*0Sstevel@tonic-gate
1227*0Sstevel@tonic-gate /*
1228*0Sstevel@tonic-gate * Add the given pair to the page. The page in question may already be
1229*0Sstevel@tonic-gate * held (i.e. it was already gotten). If it is, then the page is passed
1230*0Sstevel@tonic-gate * in via the pagep parameter. On return, pagep will contain the page
1231*0Sstevel@tonic-gate * to which we just added something. This allows us to link overflow
1232*0Sstevel@tonic-gate * pages and return the new page having correctly put the last page.
1233*0Sstevel@tonic-gate *
1234*0Sstevel@tonic-gate * PUBLIC: int __ham_add_el __P((DBC *, const DBT *, const DBT *, int));
1235*0Sstevel@tonic-gate */
1236*0Sstevel@tonic-gate int
__ham_add_el(dbc,key,val,type)1237*0Sstevel@tonic-gate __ham_add_el(dbc, key, val, type)
1238*0Sstevel@tonic-gate DBC *dbc;
1239*0Sstevel@tonic-gate const DBT *key, *val;
1240*0Sstevel@tonic-gate int type;
1241*0Sstevel@tonic-gate {
1242*0Sstevel@tonic-gate DB *dbp;
1243*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1244*0Sstevel@tonic-gate const DBT *pkey, *pdata;
1245*0Sstevel@tonic-gate DBT key_dbt, data_dbt;
1246*0Sstevel@tonic-gate DB_LSN new_lsn;
1247*0Sstevel@tonic-gate HOFFPAGE doff, koff;
1248*0Sstevel@tonic-gate db_pgno_t next_pgno;
1249*0Sstevel@tonic-gate u_int32_t data_size, key_size, pairsize, rectype;
1250*0Sstevel@tonic-gate int do_expand, is_keybig, is_databig, ret;
1251*0Sstevel@tonic-gate int key_type, data_type;
1252*0Sstevel@tonic-gate
1253*0Sstevel@tonic-gate dbp = dbc->dbp;
1254*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1255*0Sstevel@tonic-gate do_expand = 0;
1256*0Sstevel@tonic-gate
1257*0Sstevel@tonic-gate if (hcp->pagep == NULL && (ret = __ham_get_page(dbp,
1258*0Sstevel@tonic-gate hcp->seek_found_page != PGNO_INVALID ? hcp->seek_found_page :
1259*0Sstevel@tonic-gate hcp->pgno, &hcp->pagep)) != 0)
1260*0Sstevel@tonic-gate return (ret);
1261*0Sstevel@tonic-gate
1262*0Sstevel@tonic-gate key_size = HKEYDATA_PSIZE(key->size);
1263*0Sstevel@tonic-gate data_size = HKEYDATA_PSIZE(val->size);
1264*0Sstevel@tonic-gate is_keybig = ISBIG(hcp, key->size);
1265*0Sstevel@tonic-gate is_databig = ISBIG(hcp, val->size);
1266*0Sstevel@tonic-gate if (is_keybig)
1267*0Sstevel@tonic-gate key_size = HOFFPAGE_PSIZE;
1268*0Sstevel@tonic-gate if (is_databig)
1269*0Sstevel@tonic-gate data_size = HOFFPAGE_PSIZE;
1270*0Sstevel@tonic-gate
1271*0Sstevel@tonic-gate pairsize = key_size + data_size;
1272*0Sstevel@tonic-gate
1273*0Sstevel@tonic-gate /* Advance to first page in chain with room for item. */
1274*0Sstevel@tonic-gate while (H_NUMPAIRS(hcp->pagep) && NEXT_PGNO(hcp->pagep) !=
1275*0Sstevel@tonic-gate PGNO_INVALID) {
1276*0Sstevel@tonic-gate /*
1277*0Sstevel@tonic-gate * This may not be the end of the chain, but the pair may fit
1278*0Sstevel@tonic-gate * anyway. Check if it's a bigpair that fits or a regular
1279*0Sstevel@tonic-gate * pair that fits.
1280*0Sstevel@tonic-gate */
1281*0Sstevel@tonic-gate if (P_FREESPACE(hcp->pagep) >= pairsize)
1282*0Sstevel@tonic-gate break;
1283*0Sstevel@tonic-gate next_pgno = NEXT_PGNO(hcp->pagep);
1284*0Sstevel@tonic-gate if ((ret =
1285*0Sstevel@tonic-gate __ham_next_cpage(dbc, next_pgno, 0, 0)) != 0)
1286*0Sstevel@tonic-gate return (ret);
1287*0Sstevel@tonic-gate }
1288*0Sstevel@tonic-gate
1289*0Sstevel@tonic-gate /*
1290*0Sstevel@tonic-gate * Check if we need to allocate a new page.
1291*0Sstevel@tonic-gate */
1292*0Sstevel@tonic-gate if (P_FREESPACE(hcp->pagep) < pairsize) {
1293*0Sstevel@tonic-gate do_expand = 1;
1294*0Sstevel@tonic-gate if ((ret = __ham_add_ovflpage(dbc,
1295*0Sstevel@tonic-gate hcp->pagep, 1, &hcp->pagep)) != 0)
1296*0Sstevel@tonic-gate return (ret);
1297*0Sstevel@tonic-gate hcp->pgno = PGNO(hcp->pagep);
1298*0Sstevel@tonic-gate }
1299*0Sstevel@tonic-gate
1300*0Sstevel@tonic-gate /*
1301*0Sstevel@tonic-gate * Update cursor.
1302*0Sstevel@tonic-gate */
1303*0Sstevel@tonic-gate hcp->bndx = H_NUMPAIRS(hcp->pagep);
1304*0Sstevel@tonic-gate F_CLR(hcp, H_DELETED);
1305*0Sstevel@tonic-gate if (is_keybig) {
1306*0Sstevel@tonic-gate koff.type = H_OFFPAGE;
1307*0Sstevel@tonic-gate UMRW(koff.unused[0]);
1308*0Sstevel@tonic-gate UMRW(koff.unused[1]);
1309*0Sstevel@tonic-gate UMRW(koff.unused[2]);
1310*0Sstevel@tonic-gate if ((ret = __db_poff(dbc,
1311*0Sstevel@tonic-gate key, &koff.pgno, __ham_overflow_page)) != 0)
1312*0Sstevel@tonic-gate return (ret);
1313*0Sstevel@tonic-gate koff.tlen = key->size;
1314*0Sstevel@tonic-gate key_dbt.data = &koff;
1315*0Sstevel@tonic-gate key_dbt.size = sizeof(koff);
1316*0Sstevel@tonic-gate pkey = &key_dbt;
1317*0Sstevel@tonic-gate key_type = H_OFFPAGE;
1318*0Sstevel@tonic-gate } else {
1319*0Sstevel@tonic-gate pkey = key;
1320*0Sstevel@tonic-gate key_type = H_KEYDATA;
1321*0Sstevel@tonic-gate }
1322*0Sstevel@tonic-gate
1323*0Sstevel@tonic-gate if (is_databig) {
1324*0Sstevel@tonic-gate doff.type = H_OFFPAGE;
1325*0Sstevel@tonic-gate UMRW(doff.unused[0]);
1326*0Sstevel@tonic-gate UMRW(doff.unused[1]);
1327*0Sstevel@tonic-gate UMRW(doff.unused[2]);
1328*0Sstevel@tonic-gate if ((ret = __db_poff(dbc,
1329*0Sstevel@tonic-gate val, &doff.pgno, __ham_overflow_page)) != 0)
1330*0Sstevel@tonic-gate return (ret);
1331*0Sstevel@tonic-gate doff.tlen = val->size;
1332*0Sstevel@tonic-gate data_dbt.data = &doff;
1333*0Sstevel@tonic-gate data_dbt.size = sizeof(doff);
1334*0Sstevel@tonic-gate pdata = &data_dbt;
1335*0Sstevel@tonic-gate data_type = H_OFFPAGE;
1336*0Sstevel@tonic-gate } else {
1337*0Sstevel@tonic-gate pdata = val;
1338*0Sstevel@tonic-gate data_type = type;
1339*0Sstevel@tonic-gate }
1340*0Sstevel@tonic-gate
1341*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
1342*0Sstevel@tonic-gate rectype = PUTPAIR;
1343*0Sstevel@tonic-gate if (is_databig)
1344*0Sstevel@tonic-gate rectype |= PAIR_DATAMASK;
1345*0Sstevel@tonic-gate if (is_keybig)
1346*0Sstevel@tonic-gate rectype |= PAIR_KEYMASK;
1347*0Sstevel@tonic-gate
1348*0Sstevel@tonic-gate if ((ret = __ham_insdel_log(dbp->dbenv->lg_info,
1349*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, rectype,
1350*0Sstevel@tonic-gate dbp->log_fileid, PGNO(hcp->pagep),
1351*0Sstevel@tonic-gate (u_int32_t)H_NUMPAIRS(hcp->pagep),
1352*0Sstevel@tonic-gate &LSN(hcp->pagep), pkey, pdata)) != 0)
1353*0Sstevel@tonic-gate return (ret);
1354*0Sstevel@tonic-gate
1355*0Sstevel@tonic-gate /* Move lsn onto page. */
1356*0Sstevel@tonic-gate LSN(hcp->pagep) = new_lsn; /* Structure assignment. */
1357*0Sstevel@tonic-gate }
1358*0Sstevel@tonic-gate
1359*0Sstevel@tonic-gate __ham_putitem(hcp->pagep, pkey, key_type);
1360*0Sstevel@tonic-gate __ham_putitem(hcp->pagep, pdata, data_type);
1361*0Sstevel@tonic-gate
1362*0Sstevel@tonic-gate /*
1363*0Sstevel@tonic-gate * For splits, we are going to update item_info's page number
1364*0Sstevel@tonic-gate * field, so that we can easily return to the same page the
1365*0Sstevel@tonic-gate * next time we come in here. For other operations, this shouldn't
1366*0Sstevel@tonic-gate * matter, since odds are this is the last thing that happens before
1367*0Sstevel@tonic-gate * we return to the user program.
1368*0Sstevel@tonic-gate */
1369*0Sstevel@tonic-gate hcp->pgno = PGNO(hcp->pagep);
1370*0Sstevel@tonic-gate
1371*0Sstevel@tonic-gate /*
1372*0Sstevel@tonic-gate * XXX Maybe keep incremental numbers here
1373*0Sstevel@tonic-gate */
1374*0Sstevel@tonic-gate if (!F_ISSET(dbp, DB_AM_LOCKING))
1375*0Sstevel@tonic-gate hcp->hdr->nelem++;
1376*0Sstevel@tonic-gate
1377*0Sstevel@tonic-gate if (do_expand || (hcp->hdr->ffactor != 0 &&
1378*0Sstevel@tonic-gate (u_int32_t)H_NUMPAIRS(hcp->pagep) > hcp->hdr->ffactor))
1379*0Sstevel@tonic-gate F_SET(hcp, H_EXPAND);
1380*0Sstevel@tonic-gate return (0);
1381*0Sstevel@tonic-gate }
1382*0Sstevel@tonic-gate
1383*0Sstevel@tonic-gate
1384*0Sstevel@tonic-gate /*
1385*0Sstevel@tonic-gate * Special __putitem call used in splitting -- copies one entry to
1386*0Sstevel@tonic-gate * another. Works for all types of hash entries (H_OFFPAGE, H_KEYDATA,
1387*0Sstevel@tonic-gate * H_DUPLICATE, H_OFFDUP). Since we log splits at a high level, we
1388*0Sstevel@tonic-gate * do not need to do any logging here.
1389*0Sstevel@tonic-gate *
1390*0Sstevel@tonic-gate * PUBLIC: void __ham_copy_item __P((size_t, PAGE *, u_int32_t, PAGE *));
1391*0Sstevel@tonic-gate */
1392*0Sstevel@tonic-gate void
__ham_copy_item(pgsize,src_page,src_ndx,dest_page)1393*0Sstevel@tonic-gate __ham_copy_item(pgsize, src_page, src_ndx, dest_page)
1394*0Sstevel@tonic-gate size_t pgsize;
1395*0Sstevel@tonic-gate PAGE *src_page;
1396*0Sstevel@tonic-gate u_int32_t src_ndx;
1397*0Sstevel@tonic-gate PAGE *dest_page;
1398*0Sstevel@tonic-gate {
1399*0Sstevel@tonic-gate u_int32_t len;
1400*0Sstevel@tonic-gate void *src, *dest;
1401*0Sstevel@tonic-gate
1402*0Sstevel@tonic-gate /*
1403*0Sstevel@tonic-gate * Copy the key and data entries onto this new page.
1404*0Sstevel@tonic-gate */
1405*0Sstevel@tonic-gate src = P_ENTRY(src_page, src_ndx);
1406*0Sstevel@tonic-gate
1407*0Sstevel@tonic-gate /* Set up space on dest. */
1408*0Sstevel@tonic-gate len = LEN_HITEM(src_page, pgsize, src_ndx);
1409*0Sstevel@tonic-gate HOFFSET(dest_page) -= len;
1410*0Sstevel@tonic-gate dest_page->inp[NUM_ENT(dest_page)] = HOFFSET(dest_page);
1411*0Sstevel@tonic-gate dest = P_ENTRY(dest_page, NUM_ENT(dest_page));
1412*0Sstevel@tonic-gate NUM_ENT(dest_page)++;
1413*0Sstevel@tonic-gate
1414*0Sstevel@tonic-gate memcpy(dest, src, len);
1415*0Sstevel@tonic-gate }
1416*0Sstevel@tonic-gate
1417*0Sstevel@tonic-gate /*
1418*0Sstevel@tonic-gate *
1419*0Sstevel@tonic-gate * Returns:
1420*0Sstevel@tonic-gate * pointer on success
1421*0Sstevel@tonic-gate * NULL on error
1422*0Sstevel@tonic-gate *
1423*0Sstevel@tonic-gate * PUBLIC: int __ham_add_ovflpage __P((DBC *, PAGE *, int, PAGE **));
1424*0Sstevel@tonic-gate */
1425*0Sstevel@tonic-gate int
__ham_add_ovflpage(dbc,pagep,release,pp)1426*0Sstevel@tonic-gate __ham_add_ovflpage(dbc, pagep, release, pp)
1427*0Sstevel@tonic-gate DBC *dbc;
1428*0Sstevel@tonic-gate PAGE *pagep;
1429*0Sstevel@tonic-gate int release;
1430*0Sstevel@tonic-gate PAGE **pp;
1431*0Sstevel@tonic-gate {
1432*0Sstevel@tonic-gate DB *dbp;
1433*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1434*0Sstevel@tonic-gate DB_LSN new_lsn;
1435*0Sstevel@tonic-gate PAGE *new_pagep;
1436*0Sstevel@tonic-gate int ret;
1437*0Sstevel@tonic-gate
1438*0Sstevel@tonic-gate dbp = dbc->dbp;
1439*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1440*0Sstevel@tonic-gate
1441*0Sstevel@tonic-gate if ((ret = __ham_overflow_page(dbc, P_HASH, &new_pagep)) != 0)
1442*0Sstevel@tonic-gate return (ret);
1443*0Sstevel@tonic-gate
1444*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
1445*0Sstevel@tonic-gate if ((ret = __ham_newpage_log(dbp->dbenv->lg_info,
1446*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, PUTOVFL,
1447*0Sstevel@tonic-gate dbp->log_fileid, PGNO(pagep), &LSN(pagep),
1448*0Sstevel@tonic-gate PGNO(new_pagep), &LSN(new_pagep), PGNO_INVALID, NULL)) != 0)
1449*0Sstevel@tonic-gate return (ret);
1450*0Sstevel@tonic-gate
1451*0Sstevel@tonic-gate /* Move lsn onto page. */
1452*0Sstevel@tonic-gate LSN(pagep) = LSN(new_pagep) = new_lsn;
1453*0Sstevel@tonic-gate }
1454*0Sstevel@tonic-gate NEXT_PGNO(pagep) = PGNO(new_pagep);
1455*0Sstevel@tonic-gate PREV_PGNO(new_pagep) = PGNO(pagep);
1456*0Sstevel@tonic-gate
1457*0Sstevel@tonic-gate if (release)
1458*0Sstevel@tonic-gate ret = __ham_put_page(dbp, pagep, 1);
1459*0Sstevel@tonic-gate
1460*0Sstevel@tonic-gate hcp->stats.hash_overflows++;
1461*0Sstevel@tonic-gate *pp = new_pagep;
1462*0Sstevel@tonic-gate return (ret);
1463*0Sstevel@tonic-gate }
1464*0Sstevel@tonic-gate
1465*0Sstevel@tonic-gate
1466*0Sstevel@tonic-gate /*
1467*0Sstevel@tonic-gate * PUBLIC: int __ham_new_page __P((DB *, u_int32_t, u_int32_t, PAGE **));
1468*0Sstevel@tonic-gate */
1469*0Sstevel@tonic-gate int
__ham_new_page(dbp,addr,type,pp)1470*0Sstevel@tonic-gate __ham_new_page(dbp, addr, type, pp)
1471*0Sstevel@tonic-gate DB *dbp;
1472*0Sstevel@tonic-gate u_int32_t addr, type;
1473*0Sstevel@tonic-gate PAGE **pp;
1474*0Sstevel@tonic-gate {
1475*0Sstevel@tonic-gate PAGE *pagep;
1476*0Sstevel@tonic-gate int ret;
1477*0Sstevel@tonic-gate
1478*0Sstevel@tonic-gate if ((ret = memp_fget(dbp->mpf,
1479*0Sstevel@tonic-gate &addr, DB_MPOOL_CREATE, &pagep)) != 0)
1480*0Sstevel@tonic-gate return (ret);
1481*0Sstevel@tonic-gate
1482*0Sstevel@tonic-gate /* This should not be necessary because page-in should do it. */
1483*0Sstevel@tonic-gate P_INIT(pagep, dbp->pgsize, addr, PGNO_INVALID, PGNO_INVALID, 0, type);
1484*0Sstevel@tonic-gate
1485*0Sstevel@tonic-gate *pp = pagep;
1486*0Sstevel@tonic-gate return (0);
1487*0Sstevel@tonic-gate }
1488*0Sstevel@tonic-gate
1489*0Sstevel@tonic-gate /*
1490*0Sstevel@tonic-gate * PUBLIC: int __ham_del_page __P((DBC *, PAGE *));
1491*0Sstevel@tonic-gate */
1492*0Sstevel@tonic-gate int
__ham_del_page(dbc,pagep)1493*0Sstevel@tonic-gate __ham_del_page(dbc, pagep)
1494*0Sstevel@tonic-gate DBC *dbc;
1495*0Sstevel@tonic-gate PAGE *pagep;
1496*0Sstevel@tonic-gate {
1497*0Sstevel@tonic-gate DB *dbp;
1498*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1499*0Sstevel@tonic-gate DB_LSN new_lsn;
1500*0Sstevel@tonic-gate int ret;
1501*0Sstevel@tonic-gate
1502*0Sstevel@tonic-gate dbp = dbc->dbp;
1503*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1504*0Sstevel@tonic-gate ret = 0;
1505*0Sstevel@tonic-gate DIRTY_META(dbp, hcp, ret);
1506*0Sstevel@tonic-gate if (ret != 0) {
1507*0Sstevel@tonic-gate if (ret != EAGAIN)
1508*0Sstevel@tonic-gate __db_err(dbp->dbenv,
1509*0Sstevel@tonic-gate "free_ovflpage: unable to lock meta data page %s\n",
1510*0Sstevel@tonic-gate strerror(ret));
1511*0Sstevel@tonic-gate /*
1512*0Sstevel@tonic-gate * If we are going to return an error, then we should free
1513*0Sstevel@tonic-gate * the page, so it doesn't stay pinned forever.
1514*0Sstevel@tonic-gate */
1515*0Sstevel@tonic-gate (void)__ham_put_page(dbp, pagep, 0);
1516*0Sstevel@tonic-gate return (ret);
1517*0Sstevel@tonic-gate }
1518*0Sstevel@tonic-gate
1519*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
1520*0Sstevel@tonic-gate if ((ret = __ham_newpgno_log(dbp->dbenv->lg_info,
1521*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, DELPGNO,
1522*0Sstevel@tonic-gate dbp->log_fileid, PGNO(pagep), hcp->hdr->last_freed,
1523*0Sstevel@tonic-gate (u_int32_t)TYPE(pagep), NEXT_PGNO(pagep), P_INVALID,
1524*0Sstevel@tonic-gate &LSN(pagep), &hcp->hdr->lsn)) != 0)
1525*0Sstevel@tonic-gate return (ret);
1526*0Sstevel@tonic-gate
1527*0Sstevel@tonic-gate hcp->hdr->lsn = new_lsn;
1528*0Sstevel@tonic-gate LSN(pagep) = new_lsn;
1529*0Sstevel@tonic-gate }
1530*0Sstevel@tonic-gate
1531*0Sstevel@tonic-gate #ifdef DIAGNOSTIC
1532*0Sstevel@tonic-gate {
1533*0Sstevel@tonic-gate db_pgno_t __pgno;
1534*0Sstevel@tonic-gate DB_LSN __lsn;
1535*0Sstevel@tonic-gate __pgno = pagep->pgno;
1536*0Sstevel@tonic-gate __lsn = pagep->lsn;
1537*0Sstevel@tonic-gate memset(pagep, 0xdb, dbp->pgsize);
1538*0Sstevel@tonic-gate pagep->pgno = __pgno;
1539*0Sstevel@tonic-gate pagep->lsn = __lsn;
1540*0Sstevel@tonic-gate }
1541*0Sstevel@tonic-gate #endif
1542*0Sstevel@tonic-gate TYPE(pagep) = P_INVALID;
1543*0Sstevel@tonic-gate NEXT_PGNO(pagep) = hcp->hdr->last_freed;
1544*0Sstevel@tonic-gate hcp->hdr->last_freed = PGNO(pagep);
1545*0Sstevel@tonic-gate
1546*0Sstevel@tonic-gate return (__ham_put_page(dbp, pagep, 1));
1547*0Sstevel@tonic-gate }
1548*0Sstevel@tonic-gate
1549*0Sstevel@tonic-gate
1550*0Sstevel@tonic-gate /*
1551*0Sstevel@tonic-gate * PUBLIC: int __ham_put_page __P((DB *, PAGE *, int32_t));
1552*0Sstevel@tonic-gate */
1553*0Sstevel@tonic-gate int
__ham_put_page(dbp,pagep,is_dirty)1554*0Sstevel@tonic-gate __ham_put_page(dbp, pagep, is_dirty)
1555*0Sstevel@tonic-gate DB *dbp;
1556*0Sstevel@tonic-gate PAGE *pagep;
1557*0Sstevel@tonic-gate int32_t is_dirty;
1558*0Sstevel@tonic-gate {
1559*0Sstevel@tonic-gate #ifdef DEBUG_SLOW
1560*0Sstevel@tonic-gate __account_page(dbp, ((BKT *)((char *)pagep - sizeof(BKT)))->pgno, -1);
1561*0Sstevel@tonic-gate #endif
1562*0Sstevel@tonic-gate return (memp_fput(dbp->mpf, pagep, (is_dirty ? DB_MPOOL_DIRTY : 0)));
1563*0Sstevel@tonic-gate }
1564*0Sstevel@tonic-gate
1565*0Sstevel@tonic-gate /*
1566*0Sstevel@tonic-gate * __ham_dirty_page --
1567*0Sstevel@tonic-gate * Mark a page dirty.
1568*0Sstevel@tonic-gate *
1569*0Sstevel@tonic-gate * PUBLIC: int __ham_dirty_page __P((DB *, PAGE *));
1570*0Sstevel@tonic-gate */
1571*0Sstevel@tonic-gate int
__ham_dirty_page(dbp,pagep)1572*0Sstevel@tonic-gate __ham_dirty_page(dbp, pagep)
1573*0Sstevel@tonic-gate DB *dbp;
1574*0Sstevel@tonic-gate PAGE *pagep;
1575*0Sstevel@tonic-gate {
1576*0Sstevel@tonic-gate return (memp_fset(dbp->mpf, pagep, DB_MPOOL_DIRTY));
1577*0Sstevel@tonic-gate }
1578*0Sstevel@tonic-gate
1579*0Sstevel@tonic-gate /*
1580*0Sstevel@tonic-gate * PUBLIC: int __ham_get_page __P((DB *, db_pgno_t, PAGE **));
1581*0Sstevel@tonic-gate */
1582*0Sstevel@tonic-gate int
__ham_get_page(dbp,addr,pagep)1583*0Sstevel@tonic-gate __ham_get_page(dbp, addr, pagep)
1584*0Sstevel@tonic-gate DB *dbp;
1585*0Sstevel@tonic-gate db_pgno_t addr;
1586*0Sstevel@tonic-gate PAGE **pagep;
1587*0Sstevel@tonic-gate {
1588*0Sstevel@tonic-gate int ret;
1589*0Sstevel@tonic-gate
1590*0Sstevel@tonic-gate ret = memp_fget(dbp->mpf, &addr, DB_MPOOL_CREATE, pagep);
1591*0Sstevel@tonic-gate #ifdef DEBUG_SLOW
1592*0Sstevel@tonic-gate if (*pagep != NULL)
1593*0Sstevel@tonic-gate __account_page(dbp, addr, 1);
1594*0Sstevel@tonic-gate #endif
1595*0Sstevel@tonic-gate return (ret);
1596*0Sstevel@tonic-gate }
1597*0Sstevel@tonic-gate
1598*0Sstevel@tonic-gate /*
1599*0Sstevel@tonic-gate * PUBLIC: int __ham_overflow_page
1600*0Sstevel@tonic-gate * PUBLIC: __P((DBC *, u_int32_t, PAGE **));
1601*0Sstevel@tonic-gate */
1602*0Sstevel@tonic-gate int
__ham_overflow_page(dbc,type,pp)1603*0Sstevel@tonic-gate __ham_overflow_page(dbc, type, pp)
1604*0Sstevel@tonic-gate DBC *dbc;
1605*0Sstevel@tonic-gate u_int32_t type;
1606*0Sstevel@tonic-gate PAGE **pp;
1607*0Sstevel@tonic-gate {
1608*0Sstevel@tonic-gate DB *dbp;
1609*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1610*0Sstevel@tonic-gate DB_LSN *lsnp, new_lsn;
1611*0Sstevel@tonic-gate PAGE *p;
1612*0Sstevel@tonic-gate db_pgno_t new_addr, next_free, newalloc_flag;
1613*0Sstevel@tonic-gate u_int32_t offset, splitnum;
1614*0Sstevel@tonic-gate int ret;
1615*0Sstevel@tonic-gate
1616*0Sstevel@tonic-gate ret = 0;
1617*0Sstevel@tonic-gate dbp = dbc->dbp;
1618*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1619*0Sstevel@tonic-gate DIRTY_META(dbp, hcp, ret);
1620*0Sstevel@tonic-gate if (ret != 0)
1621*0Sstevel@tonic-gate return (ret);
1622*0Sstevel@tonic-gate
1623*0Sstevel@tonic-gate /*
1624*0Sstevel@tonic-gate * This routine is split up into two parts. First we have
1625*0Sstevel@tonic-gate * to figure out the address of the new page that we are
1626*0Sstevel@tonic-gate * allocating. Then we have to log the allocation. Only
1627*0Sstevel@tonic-gate * after the log do we get to complete allocation of the
1628*0Sstevel@tonic-gate * new page.
1629*0Sstevel@tonic-gate */
1630*0Sstevel@tonic-gate new_addr = hcp->hdr->last_freed;
1631*0Sstevel@tonic-gate if (new_addr != PGNO_INVALID) {
1632*0Sstevel@tonic-gate if ((ret = __ham_get_page(dbp, new_addr, &p)) != 0)
1633*0Sstevel@tonic-gate return (ret);
1634*0Sstevel@tonic-gate next_free = NEXT_PGNO(p);
1635*0Sstevel@tonic-gate lsnp = &LSN(p);
1636*0Sstevel@tonic-gate newalloc_flag = 0;
1637*0Sstevel@tonic-gate } else {
1638*0Sstevel@tonic-gate splitnum = hcp->hdr->ovfl_point;
1639*0Sstevel@tonic-gate hcp->hdr->spares[splitnum]++;
1640*0Sstevel@tonic-gate offset = hcp->hdr->spares[splitnum] -
1641*0Sstevel@tonic-gate (splitnum ? hcp->hdr->spares[splitnum - 1] : 0);
1642*0Sstevel@tonic-gate new_addr = PGNO_OF(hcp, hcp->hdr->ovfl_point, offset);
1643*0Sstevel@tonic-gate if (new_addr > MAX_PAGES(hcp)) {
1644*0Sstevel@tonic-gate __db_err(dbp->dbenv, "hash: out of file pages");
1645*0Sstevel@tonic-gate hcp->hdr->spares[splitnum]--;
1646*0Sstevel@tonic-gate return (ENOMEM);
1647*0Sstevel@tonic-gate }
1648*0Sstevel@tonic-gate next_free = PGNO_INVALID;
1649*0Sstevel@tonic-gate p = NULL;
1650*0Sstevel@tonic-gate lsnp = NULL;
1651*0Sstevel@tonic-gate newalloc_flag = 1;
1652*0Sstevel@tonic-gate }
1653*0Sstevel@tonic-gate
1654*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
1655*0Sstevel@tonic-gate if ((ret = __ham_newpgno_log(dbp->dbenv->lg_info,
1656*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, ALLOCPGNO,
1657*0Sstevel@tonic-gate dbp->log_fileid, new_addr, next_free,
1658*0Sstevel@tonic-gate 0, newalloc_flag, type, lsnp, &hcp->hdr->lsn)) != 0)
1659*0Sstevel@tonic-gate return (ret);
1660*0Sstevel@tonic-gate
1661*0Sstevel@tonic-gate hcp->hdr->lsn = new_lsn;
1662*0Sstevel@tonic-gate if (lsnp != NULL)
1663*0Sstevel@tonic-gate *lsnp = new_lsn;
1664*0Sstevel@tonic-gate }
1665*0Sstevel@tonic-gate
1666*0Sstevel@tonic-gate if (p != NULL) {
1667*0Sstevel@tonic-gate /* We just took something off the free list, initialize it. */
1668*0Sstevel@tonic-gate hcp->hdr->last_freed = next_free;
1669*0Sstevel@tonic-gate P_INIT(p, hcp->hdr->pagesize, PGNO(p), PGNO_INVALID,
1670*0Sstevel@tonic-gate PGNO_INVALID, 0, (u_int8_t)type);
1671*0Sstevel@tonic-gate } else {
1672*0Sstevel@tonic-gate /* Get the new page. */
1673*0Sstevel@tonic-gate if ((ret = __ham_new_page(dbp, new_addr, type, &p)) != 0)
1674*0Sstevel@tonic-gate return (ret);
1675*0Sstevel@tonic-gate }
1676*0Sstevel@tonic-gate if (DB_LOGGING(dbc))
1677*0Sstevel@tonic-gate LSN(p) = new_lsn;
1678*0Sstevel@tonic-gate
1679*0Sstevel@tonic-gate *pp = p;
1680*0Sstevel@tonic-gate return (0);
1681*0Sstevel@tonic-gate }
1682*0Sstevel@tonic-gate
1683*0Sstevel@tonic-gate #ifdef DEBUG
1684*0Sstevel@tonic-gate /*
1685*0Sstevel@tonic-gate * PUBLIC: #ifdef DEBUG
1686*0Sstevel@tonic-gate * PUBLIC: db_pgno_t __bucket_to_page __P((HASH_CURSOR *, db_pgno_t));
1687*0Sstevel@tonic-gate * PUBLIC: #endif
1688*0Sstevel@tonic-gate */
1689*0Sstevel@tonic-gate db_pgno_t
__bucket_to_page(hcp,n)1690*0Sstevel@tonic-gate __bucket_to_page(hcp, n)
1691*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1692*0Sstevel@tonic-gate db_pgno_t n;
1693*0Sstevel@tonic-gate {
1694*0Sstevel@tonic-gate int ret_val;
1695*0Sstevel@tonic-gate
1696*0Sstevel@tonic-gate ret_val = n + 1;
1697*0Sstevel@tonic-gate if (n != 0)
1698*0Sstevel@tonic-gate ret_val += hcp->hdr->spares[__db_log2(n + 1) - 1];
1699*0Sstevel@tonic-gate return (ret_val);
1700*0Sstevel@tonic-gate }
1701*0Sstevel@tonic-gate #endif
1702*0Sstevel@tonic-gate
1703*0Sstevel@tonic-gate /*
1704*0Sstevel@tonic-gate * Create a bunch of overflow pages at the current split point.
1705*0Sstevel@tonic-gate * PUBLIC: void __ham_init_ovflpages __P((DBC *));
1706*0Sstevel@tonic-gate */
1707*0Sstevel@tonic-gate void
__ham_init_ovflpages(dbc)1708*0Sstevel@tonic-gate __ham_init_ovflpages(dbc)
1709*0Sstevel@tonic-gate DBC *dbc;
1710*0Sstevel@tonic-gate {
1711*0Sstevel@tonic-gate DB *dbp;
1712*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1713*0Sstevel@tonic-gate DB_LSN new_lsn;
1714*0Sstevel@tonic-gate PAGE *p;
1715*0Sstevel@tonic-gate db_pgno_t last_pgno, new_pgno;
1716*0Sstevel@tonic-gate u_int32_t i, curpages, numpages;
1717*0Sstevel@tonic-gate
1718*0Sstevel@tonic-gate dbp = dbc->dbp;
1719*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1720*0Sstevel@tonic-gate
1721*0Sstevel@tonic-gate curpages = hcp->hdr->spares[hcp->hdr->ovfl_point] -
1722*0Sstevel@tonic-gate hcp->hdr->spares[hcp->hdr->ovfl_point - 1];
1723*0Sstevel@tonic-gate numpages = hcp->hdr->ovfl_point + 1 - curpages;
1724*0Sstevel@tonic-gate
1725*0Sstevel@tonic-gate last_pgno = hcp->hdr->last_freed;
1726*0Sstevel@tonic-gate new_pgno = PGNO_OF(hcp, hcp->hdr->ovfl_point, curpages + 1);
1727*0Sstevel@tonic-gate if (DB_LOGGING(dbc)) {
1728*0Sstevel@tonic-gate (void)__ham_ovfl_log(dbp->dbenv->lg_info,
1729*0Sstevel@tonic-gate dbc->txn, &new_lsn, 0, dbp->log_fileid, new_pgno,
1730*0Sstevel@tonic-gate numpages, last_pgno, hcp->hdr->ovfl_point, &hcp->hdr->lsn);
1731*0Sstevel@tonic-gate hcp->hdr->lsn = new_lsn;
1732*0Sstevel@tonic-gate } else
1733*0Sstevel@tonic-gate ZERO_LSN(new_lsn);
1734*0Sstevel@tonic-gate
1735*0Sstevel@tonic-gate hcp->hdr->spares[hcp->hdr->ovfl_point] += numpages;
1736*0Sstevel@tonic-gate for (i = numpages; i > 0; i--) {
1737*0Sstevel@tonic-gate if (__ham_new_page(dbp,
1738*0Sstevel@tonic-gate PGNO_OF(hcp, hcp->hdr->ovfl_point, curpages + i),
1739*0Sstevel@tonic-gate P_INVALID, &p) != 0)
1740*0Sstevel@tonic-gate break;
1741*0Sstevel@tonic-gate LSN(p) = new_lsn;
1742*0Sstevel@tonic-gate NEXT_PGNO(p) = last_pgno;
1743*0Sstevel@tonic-gate last_pgno = PGNO(p);
1744*0Sstevel@tonic-gate (void)__ham_put_page(dbp, p, 1);
1745*0Sstevel@tonic-gate }
1746*0Sstevel@tonic-gate hcp->hdr->last_freed = last_pgno;
1747*0Sstevel@tonic-gate }
1748*0Sstevel@tonic-gate
1749*0Sstevel@tonic-gate /*
1750*0Sstevel@tonic-gate * PUBLIC: int __ham_get_cpage __P((DBC *, db_lockmode_t));
1751*0Sstevel@tonic-gate */
1752*0Sstevel@tonic-gate int
__ham_get_cpage(dbc,mode)1753*0Sstevel@tonic-gate __ham_get_cpage(dbc, mode)
1754*0Sstevel@tonic-gate DBC *dbc;
1755*0Sstevel@tonic-gate db_lockmode_t mode;
1756*0Sstevel@tonic-gate {
1757*0Sstevel@tonic-gate DB *dbp;
1758*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1759*0Sstevel@tonic-gate int ret;
1760*0Sstevel@tonic-gate
1761*0Sstevel@tonic-gate dbp = dbc->dbp;
1762*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1763*0Sstevel@tonic-gate
1764*0Sstevel@tonic-gate /*
1765*0Sstevel@tonic-gate * There are three cases with respect to buckets and locks. If there
1766*0Sstevel@tonic-gate * is no lock held, then if we are locking, we should get the lock.
1767*0Sstevel@tonic-gate * If there is a lock held and it's for the current bucket, we don't
1768*0Sstevel@tonic-gate * need to do anything. If there is a lock, but it's for a different
1769*0Sstevel@tonic-gate * bucket, then we need to release and get.
1770*0Sstevel@tonic-gate */
1771*0Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_LOCKING)) {
1772*0Sstevel@tonic-gate if (hcp->lock != 0 && hcp->lbucket != hcp->bucket) {
1773*0Sstevel@tonic-gate /*
1774*0Sstevel@tonic-gate * If this is the original lock, don't release it,
1775*0Sstevel@tonic-gate * because we may need to restore it upon exit.
1776*0Sstevel@tonic-gate */
1777*0Sstevel@tonic-gate if (dbc->txn == NULL &&
1778*0Sstevel@tonic-gate !F_ISSET(hcp, H_ORIGINAL) && (ret =
1779*0Sstevel@tonic-gate lock_put(dbp->dbenv->lk_info, hcp->lock)) != 0)
1780*0Sstevel@tonic-gate return (ret);
1781*0Sstevel@tonic-gate F_CLR(hcp, H_ORIGINAL);
1782*0Sstevel@tonic-gate hcp->lock = 0;
1783*0Sstevel@tonic-gate }
1784*0Sstevel@tonic-gate if (hcp->lock == 0 && (ret = __ham_lock_bucket(dbc, mode)) != 0)
1785*0Sstevel@tonic-gate return (ret);
1786*0Sstevel@tonic-gate hcp->lbucket = hcp->bucket;
1787*0Sstevel@tonic-gate }
1788*0Sstevel@tonic-gate
1789*0Sstevel@tonic-gate if (hcp->pagep == NULL) {
1790*0Sstevel@tonic-gate if (hcp->pgno == PGNO_INVALID) {
1791*0Sstevel@tonic-gate hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket);
1792*0Sstevel@tonic-gate hcp->bndx = 0;
1793*0Sstevel@tonic-gate }
1794*0Sstevel@tonic-gate
1795*0Sstevel@tonic-gate if ((ret =
1796*0Sstevel@tonic-gate __ham_get_page(dbp, hcp->pgno, &hcp->pagep)) != 0)
1797*0Sstevel@tonic-gate return (ret);
1798*0Sstevel@tonic-gate }
1799*0Sstevel@tonic-gate
1800*0Sstevel@tonic-gate if (hcp->dpgno != PGNO_INVALID && hcp->dpagep == NULL)
1801*0Sstevel@tonic-gate if ((ret =
1802*0Sstevel@tonic-gate __ham_get_page(dbp, hcp->dpgno, &hcp->dpagep)) != 0)
1803*0Sstevel@tonic-gate return (ret);
1804*0Sstevel@tonic-gate return (0);
1805*0Sstevel@tonic-gate }
1806*0Sstevel@tonic-gate
1807*0Sstevel@tonic-gate /*
1808*0Sstevel@tonic-gate * Get a new page at the cursor, putting the last page if necessary.
1809*0Sstevel@tonic-gate * If the flag is set to H_ISDUP, then we are talking about the
1810*0Sstevel@tonic-gate * duplicate page, not the main page.
1811*0Sstevel@tonic-gate *
1812*0Sstevel@tonic-gate * PUBLIC: int __ham_next_cpage __P((DBC *, db_pgno_t, int, u_int32_t));
1813*0Sstevel@tonic-gate */
1814*0Sstevel@tonic-gate int
__ham_next_cpage(dbc,pgno,dirty,flags)1815*0Sstevel@tonic-gate __ham_next_cpage(dbc, pgno, dirty, flags)
1816*0Sstevel@tonic-gate DBC *dbc;
1817*0Sstevel@tonic-gate db_pgno_t pgno;
1818*0Sstevel@tonic-gate int dirty;
1819*0Sstevel@tonic-gate u_int32_t flags;
1820*0Sstevel@tonic-gate {
1821*0Sstevel@tonic-gate DB *dbp;
1822*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1823*0Sstevel@tonic-gate PAGE *p;
1824*0Sstevel@tonic-gate int ret;
1825*0Sstevel@tonic-gate
1826*0Sstevel@tonic-gate dbp = dbc->dbp;
1827*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1828*0Sstevel@tonic-gate if (LF_ISSET(H_ISDUP) && hcp->dpagep != NULL &&
1829*0Sstevel@tonic-gate (ret = __ham_put_page(dbp, hcp->dpagep, dirty)) != 0)
1830*0Sstevel@tonic-gate return (ret);
1831*0Sstevel@tonic-gate else if (!LF_ISSET(H_ISDUP) && hcp->pagep != NULL &&
1832*0Sstevel@tonic-gate (ret = __ham_put_page(dbp, hcp->pagep, dirty)) != 0)
1833*0Sstevel@tonic-gate return (ret);
1834*0Sstevel@tonic-gate
1835*0Sstevel@tonic-gate if ((ret = __ham_get_page(dbp, pgno, &p)) != 0)
1836*0Sstevel@tonic-gate return (ret);
1837*0Sstevel@tonic-gate
1838*0Sstevel@tonic-gate if (LF_ISSET(H_ISDUP)) {
1839*0Sstevel@tonic-gate hcp->dpagep = p;
1840*0Sstevel@tonic-gate hcp->dpgno = pgno;
1841*0Sstevel@tonic-gate hcp->dndx = 0;
1842*0Sstevel@tonic-gate } else {
1843*0Sstevel@tonic-gate hcp->pagep = p;
1844*0Sstevel@tonic-gate hcp->pgno = pgno;
1845*0Sstevel@tonic-gate hcp->bndx = 0;
1846*0Sstevel@tonic-gate }
1847*0Sstevel@tonic-gate
1848*0Sstevel@tonic-gate return (0);
1849*0Sstevel@tonic-gate }
1850*0Sstevel@tonic-gate
1851*0Sstevel@tonic-gate /*
1852*0Sstevel@tonic-gate * __ham_lock_bucket --
1853*0Sstevel@tonic-gate * Get the lock on a particular bucket.
1854*0Sstevel@tonic-gate */
1855*0Sstevel@tonic-gate static int
__ham_lock_bucket(dbc,mode)1856*0Sstevel@tonic-gate __ham_lock_bucket(dbc, mode)
1857*0Sstevel@tonic-gate DBC *dbc;
1858*0Sstevel@tonic-gate db_lockmode_t mode;
1859*0Sstevel@tonic-gate {
1860*0Sstevel@tonic-gate HASH_CURSOR *hcp;
1861*0Sstevel@tonic-gate int ret;
1862*0Sstevel@tonic-gate
1863*0Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal;
1864*0Sstevel@tonic-gate dbc->lock.pgno = (db_pgno_t)(hcp->bucket);
1865*0Sstevel@tonic-gate if (dbc->txn == NULL)
1866*0Sstevel@tonic-gate ret = lock_get(dbc->dbp->dbenv->lk_info, dbc->locker, 0,
1867*0Sstevel@tonic-gate &dbc->lock_dbt, mode, &hcp->lock);
1868*0Sstevel@tonic-gate else
1869*0Sstevel@tonic-gate ret = lock_tget(dbc->dbp->dbenv->lk_info, dbc->txn, 0,
1870*0Sstevel@tonic-gate &dbc->lock_dbt, mode, &hcp->lock);
1871*0Sstevel@tonic-gate
1872*0Sstevel@tonic-gate return (ret < 0 ? EAGAIN : ret);
1873*0Sstevel@tonic-gate }
1874*0Sstevel@tonic-gate
1875*0Sstevel@tonic-gate /*
1876*0Sstevel@tonic-gate * __ham_dpair --
1877*0Sstevel@tonic-gate * Delete a pair on a page, paying no attention to what the pair
1878*0Sstevel@tonic-gate * represents. The caller is responsible for freeing up duplicates
1879*0Sstevel@tonic-gate * or offpage entries that might be referenced by this pair.
1880*0Sstevel@tonic-gate *
1881*0Sstevel@tonic-gate * PUBLIC: void __ham_dpair __P((DB *, PAGE *, u_int32_t));
1882*0Sstevel@tonic-gate */
1883*0Sstevel@tonic-gate void
__ham_dpair(dbp,p,pndx)1884*0Sstevel@tonic-gate __ham_dpair(dbp, p, pndx)
1885*0Sstevel@tonic-gate DB *dbp;
1886*0Sstevel@tonic-gate PAGE *p;
1887*0Sstevel@tonic-gate u_int32_t pndx;
1888*0Sstevel@tonic-gate {
1889*0Sstevel@tonic-gate db_indx_t delta, n;
1890*0Sstevel@tonic-gate u_int8_t *dest, *src;
1891*0Sstevel@tonic-gate
1892*0Sstevel@tonic-gate /*
1893*0Sstevel@tonic-gate * Compute "delta", the amount we have to shift all of the
1894*0Sstevel@tonic-gate * offsets. To find the delta, we just need to calculate
1895*0Sstevel@tonic-gate * the size of the pair of elements we are removing.
1896*0Sstevel@tonic-gate */
1897*0Sstevel@tonic-gate delta = H_PAIRSIZE(p, dbp->pgsize, pndx);
1898*0Sstevel@tonic-gate
1899*0Sstevel@tonic-gate /*
1900*0Sstevel@tonic-gate * The hard case: we want to remove something other than
1901*0Sstevel@tonic-gate * the last item on the page. We need to shift data and
1902*0Sstevel@tonic-gate * offsets down.
1903*0Sstevel@tonic-gate */
1904*0Sstevel@tonic-gate if ((db_indx_t)pndx != H_NUMPAIRS(p) - 1) {
1905*0Sstevel@tonic-gate /*
1906*0Sstevel@tonic-gate * Move the data: src is the first occupied byte on
1907*0Sstevel@tonic-gate * the page. (Length is delta.)
1908*0Sstevel@tonic-gate */
1909*0Sstevel@tonic-gate src = (u_int8_t *)p + HOFFSET(p);
1910*0Sstevel@tonic-gate
1911*0Sstevel@tonic-gate /*
1912*0Sstevel@tonic-gate * Destination is delta bytes beyond src. This might
1913*0Sstevel@tonic-gate * be an overlapping copy, so we have to use memmove.
1914*0Sstevel@tonic-gate */
1915*0Sstevel@tonic-gate dest = src + delta;
1916*0Sstevel@tonic-gate memmove(dest, src, p->inp[H_DATAINDEX(pndx)] - HOFFSET(p));
1917*0Sstevel@tonic-gate }
1918*0Sstevel@tonic-gate
1919*0Sstevel@tonic-gate /* Adjust the offsets. */
1920*0Sstevel@tonic-gate for (n = (db_indx_t)pndx; n < (db_indx_t)(H_NUMPAIRS(p) - 1); n++) {
1921*0Sstevel@tonic-gate p->inp[H_KEYINDEX(n)] = p->inp[H_KEYINDEX(n+1)] + delta;
1922*0Sstevel@tonic-gate p->inp[H_DATAINDEX(n)] = p->inp[H_DATAINDEX(n+1)] + delta;
1923*0Sstevel@tonic-gate }
1924*0Sstevel@tonic-gate
1925*0Sstevel@tonic-gate /* Adjust page metadata. */
1926*0Sstevel@tonic-gate HOFFSET(p) = HOFFSET(p) + delta;
1927*0Sstevel@tonic-gate NUM_ENT(p) = NUM_ENT(p) - 2;
1928*0Sstevel@tonic-gate }
1929*0Sstevel@tonic-gate
1930