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