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.c 10.63 (Sleepycat) 12/11/98"; 51*7c478bd9Sstevel@tonic-gate #endif /* not lint */ 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES 54*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate #include <errno.h> 57*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 58*7c478bd9Sstevel@tonic-gate #include <string.h> 59*7c478bd9Sstevel@tonic-gate #endif 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate #include "db_int.h" 62*7c478bd9Sstevel@tonic-gate #include "shqueue.h" 63*7c478bd9Sstevel@tonic-gate #include "db_page.h" 64*7c478bd9Sstevel@tonic-gate #include "db_am.h" 65*7c478bd9Sstevel@tonic-gate #include "db_ext.h" 66*7c478bd9Sstevel@tonic-gate #include "hash.h" 67*7c478bd9Sstevel@tonic-gate #include "btree.h" 68*7c478bd9Sstevel@tonic-gate #include "log.h" 69*7c478bd9Sstevel@tonic-gate #include "db_shash.h" 70*7c478bd9Sstevel@tonic-gate #include "lock.h" 71*7c478bd9Sstevel@tonic-gate #include "lock_ext.h" 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate static int __ham_c_close __P((DBC *)); 74*7c478bd9Sstevel@tonic-gate static int __ham_c_del __P((DBC *, u_int32_t)); 75*7c478bd9Sstevel@tonic-gate static int __ham_c_destroy __P((DBC *)); 76*7c478bd9Sstevel@tonic-gate static int __ham_c_get __P((DBC *, DBT *, DBT *, u_int32_t)); 77*7c478bd9Sstevel@tonic-gate static int __ham_c_put __P((DBC *, DBT *, DBT *, u_int32_t)); 78*7c478bd9Sstevel@tonic-gate static int __ham_delete __P((DB *, DB_TXN *, DBT *, u_int32_t)); 79*7c478bd9Sstevel@tonic-gate static int __ham_dup_return __P((DBC *, DBT *, u_int32_t)); 80*7c478bd9Sstevel@tonic-gate static int __ham_expand_table __P((DBC *)); 81*7c478bd9Sstevel@tonic-gate static void __ham_init_htab __P((DBC *, u_int32_t, u_int32_t)); 82*7c478bd9Sstevel@tonic-gate static int __ham_lookup __P((DBC *, const DBT *, u_int32_t, db_lockmode_t)); 83*7c478bd9Sstevel@tonic-gate static int __ham_overwrite __P((DBC *, DBT *)); 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate /************************** INTERFACE ROUTINES ***************************/ 86*7c478bd9Sstevel@tonic-gate /* OPEN/CLOSE */ 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* 89*7c478bd9Sstevel@tonic-gate * __ham_open -- 90*7c478bd9Sstevel@tonic-gate * 91*7c478bd9Sstevel@tonic-gate * PUBLIC: int __ham_open __P((DB *, DB_INFO *)); 92*7c478bd9Sstevel@tonic-gate */ 93*7c478bd9Sstevel@tonic-gate int 94*7c478bd9Sstevel@tonic-gate __ham_open(dbp, dbinfo) 95*7c478bd9Sstevel@tonic-gate DB *dbp; 96*7c478bd9Sstevel@tonic-gate DB_INFO *dbinfo; 97*7c478bd9Sstevel@tonic-gate { 98*7c478bd9Sstevel@tonic-gate DB_ENV *dbenv; 99*7c478bd9Sstevel@tonic-gate DBC *dbc; 100*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 101*7c478bd9Sstevel@tonic-gate int file_existed, ret; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate dbc = NULL; 104*7c478bd9Sstevel@tonic-gate dbenv = dbp->dbenv; 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate /* Set the hash function if specified by the user. */ 107*7c478bd9Sstevel@tonic-gate if (dbinfo != NULL && dbinfo->h_hash != NULL) 108*7c478bd9Sstevel@tonic-gate dbp->h_hash = dbinfo->h_hash; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate /* 111*7c478bd9Sstevel@tonic-gate * Initialize the remaining fields of the dbp. The only function 112*7c478bd9Sstevel@tonic-gate * that differs from the default set is __ham_stat(). 113*7c478bd9Sstevel@tonic-gate */ 114*7c478bd9Sstevel@tonic-gate dbp->internal = NULL; 115*7c478bd9Sstevel@tonic-gate dbp->am_close = __ham_close; 116*7c478bd9Sstevel@tonic-gate dbp->del = __ham_delete; 117*7c478bd9Sstevel@tonic-gate dbp->stat = __ham_stat; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* Get a cursor we can use for the rest of this function. */ 120*7c478bd9Sstevel@tonic-gate if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) 121*7c478bd9Sstevel@tonic-gate goto out; 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 124*7c478bd9Sstevel@tonic-gate GET_META(dbp, hcp, ret); 125*7c478bd9Sstevel@tonic-gate if (ret != 0) 126*7c478bd9Sstevel@tonic-gate goto out; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate /* 129*7c478bd9Sstevel@tonic-gate * If this is a new file, initialize it, and put it back dirty. 130*7c478bd9Sstevel@tonic-gate */ 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* Initialize the hdr structure */ 133*7c478bd9Sstevel@tonic-gate if (hcp->hdr->magic == DB_HASHMAGIC) { 134*7c478bd9Sstevel@tonic-gate file_existed = 1; 135*7c478bd9Sstevel@tonic-gate /* File exists, verify the data in the header. */ 136*7c478bd9Sstevel@tonic-gate if (dbp->h_hash == NULL) 137*7c478bd9Sstevel@tonic-gate dbp->h_hash = 138*7c478bd9Sstevel@tonic-gate hcp->hdr->version < 5 ? __ham_func4 : __ham_func5; 139*7c478bd9Sstevel@tonic-gate if (dbp->h_hash(CHARKEY, sizeof(CHARKEY)) != 140*7c478bd9Sstevel@tonic-gate hcp->hdr->h_charkey) { 141*7c478bd9Sstevel@tonic-gate __db_err(dbp->dbenv, "hash: incompatible hash function"); 142*7c478bd9Sstevel@tonic-gate ret = EINVAL; 143*7c478bd9Sstevel@tonic-gate goto out; 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp->hdr, DB_HASH_DUP)) 146*7c478bd9Sstevel@tonic-gate F_SET(dbp, DB_AM_DUP); 147*7c478bd9Sstevel@tonic-gate } else { 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * File does not exist, we must initialize the header. If 150*7c478bd9Sstevel@tonic-gate * locking is enabled that means getting a write lock first. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate file_existed = 0; 153*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_LOCKING) && 154*7c478bd9Sstevel@tonic-gate ((ret = lock_put(dbenv->lk_info, hcp->hlock)) != 0 || 155*7c478bd9Sstevel@tonic-gate (ret = lock_get(dbenv->lk_info, dbc->locker, 0, 156*7c478bd9Sstevel@tonic-gate &dbc->lock_dbt, DB_LOCK_WRITE, &hcp->hlock)) != 0)) { 157*7c478bd9Sstevel@tonic-gate if (ret < 0) 158*7c478bd9Sstevel@tonic-gate ret = EAGAIN; 159*7c478bd9Sstevel@tonic-gate goto out; 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate __ham_init_htab(dbc, dbinfo != NULL ? dbinfo->h_nelem : 0, 163*7c478bd9Sstevel@tonic-gate dbinfo != NULL ? dbinfo->h_ffactor : 0); 164*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_DUP)) 165*7c478bd9Sstevel@tonic-gate F_SET(hcp->hdr, DB_HASH_DUP); 166*7c478bd9Sstevel@tonic-gate if ((ret = __ham_dirty_page(dbp, (PAGE *)hcp->hdr)) != 0) 167*7c478bd9Sstevel@tonic-gate goto out; 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate /* Release the meta data page */ 171*7c478bd9Sstevel@tonic-gate RELEASE_META(dbp, hcp); 172*7c478bd9Sstevel@tonic-gate if ((ret = dbc->c_close(dbc)) != 0) 173*7c478bd9Sstevel@tonic-gate goto out; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate /* Sync the file so that we know that the meta data goes to disk. */ 176*7c478bd9Sstevel@tonic-gate if (!file_existed && (ret = dbp->sync(dbp, 0)) != 0) 177*7c478bd9Sstevel@tonic-gate goto out; 178*7c478bd9Sstevel@tonic-gate return (0); 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate out: (void)__ham_close(dbp); 181*7c478bd9Sstevel@tonic-gate return (ret); 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate /* 185*7c478bd9Sstevel@tonic-gate * PUBLIC: int __ham_close __P((DB *)); 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate int 188*7c478bd9Sstevel@tonic-gate __ham_close(dbp) 189*7c478bd9Sstevel@tonic-gate DB *dbp; 190*7c478bd9Sstevel@tonic-gate { 191*7c478bd9Sstevel@tonic-gate COMPQUIET(dbp, NULL); 192*7c478bd9Sstevel@tonic-gate return (0); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /************************** LOCAL CREATION ROUTINES **********************/ 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * Returns 0 on No Error 198*7c478bd9Sstevel@tonic-gate */ 199*7c478bd9Sstevel@tonic-gate static void 200*7c478bd9Sstevel@tonic-gate __ham_init_htab(dbc, nelem, ffactor) 201*7c478bd9Sstevel@tonic-gate DBC *dbc; 202*7c478bd9Sstevel@tonic-gate u_int32_t nelem, ffactor; 203*7c478bd9Sstevel@tonic-gate { 204*7c478bd9Sstevel@tonic-gate DB *dbp; 205*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 206*7c478bd9Sstevel@tonic-gate int32_t l2, nbuckets; 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 209*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 210*7c478bd9Sstevel@tonic-gate memset(hcp->hdr, 0, sizeof(HASHHDR)); 211*7c478bd9Sstevel@tonic-gate hcp->hdr->ffactor = ffactor; 212*7c478bd9Sstevel@tonic-gate hcp->hdr->pagesize = dbp->pgsize; 213*7c478bd9Sstevel@tonic-gate ZERO_LSN(hcp->hdr->lsn); 214*7c478bd9Sstevel@tonic-gate hcp->hdr->magic = DB_HASHMAGIC; 215*7c478bd9Sstevel@tonic-gate hcp->hdr->version = DB_HASHVERSION; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate if (dbp->h_hash == NULL) 218*7c478bd9Sstevel@tonic-gate dbp->h_hash = hcp->hdr->version < 5 ? __ham_func4 : __ham_func5; 219*7c478bd9Sstevel@tonic-gate hcp->hdr->h_charkey = dbp->h_hash(CHARKEY, sizeof(CHARKEY)); 220*7c478bd9Sstevel@tonic-gate if (nelem != 0 && hcp->hdr->ffactor != 0) { 221*7c478bd9Sstevel@tonic-gate nelem = (nelem - 1) / hcp->hdr->ffactor + 1; 222*7c478bd9Sstevel@tonic-gate l2 = __db_log2(nelem > 2 ? nelem : 2); 223*7c478bd9Sstevel@tonic-gate } else 224*7c478bd9Sstevel@tonic-gate l2 = 2; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate nbuckets = 1 << l2; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate hcp->hdr->ovfl_point = l2; 229*7c478bd9Sstevel@tonic-gate hcp->hdr->last_freed = PGNO_INVALID; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate hcp->hdr->max_bucket = hcp->hdr->high_mask = nbuckets - 1; 232*7c478bd9Sstevel@tonic-gate hcp->hdr->low_mask = (nbuckets >> 1) - 1; 233*7c478bd9Sstevel@tonic-gate memcpy(hcp->hdr->uid, dbp->fileid, DB_FILE_ID_LEN); 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate static int 237*7c478bd9Sstevel@tonic-gate __ham_delete(dbp, txn, key, flags) 238*7c478bd9Sstevel@tonic-gate DB *dbp; 239*7c478bd9Sstevel@tonic-gate DB_TXN *txn; 240*7c478bd9Sstevel@tonic-gate DBT *key; 241*7c478bd9Sstevel@tonic-gate u_int32_t flags; 242*7c478bd9Sstevel@tonic-gate { 243*7c478bd9Sstevel@tonic-gate DBC *dbc; 244*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 245*7c478bd9Sstevel@tonic-gate int ret, tret; 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if ((ret = 250*7c478bd9Sstevel@tonic-gate __db_delchk(dbp, key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0) 251*7c478bd9Sstevel@tonic-gate return (ret); 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) 254*7c478bd9Sstevel@tonic-gate return (ret); 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate DEBUG_LWRITE(dbc, txn, "ham_delete", key, NULL, flags); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 259*7c478bd9Sstevel@tonic-gate GET_META(dbp, hcp, ret); 260*7c478bd9Sstevel@tonic-gate if (ret != 0) 261*7c478bd9Sstevel@tonic-gate goto out; 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate hcp->stats.hash_deleted++; 264*7c478bd9Sstevel@tonic-gate if ((ret = __ham_lookup(dbc, key, 0, DB_LOCK_WRITE)) == 0) 265*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_OK)) 266*7c478bd9Sstevel@tonic-gate ret = __ham_del_pair(dbc, 1); 267*7c478bd9Sstevel@tonic-gate else 268*7c478bd9Sstevel@tonic-gate ret = DB_NOTFOUND; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate RELEASE_META(dbp, hcp); 271*7c478bd9Sstevel@tonic-gate out: if ((tret = dbc->c_close(dbc)) != 0 && ret == 0) 272*7c478bd9Sstevel@tonic-gate ret = tret; 273*7c478bd9Sstevel@tonic-gate return (ret); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* ****************** CURSORS ********************************** */ 277*7c478bd9Sstevel@tonic-gate /* 278*7c478bd9Sstevel@tonic-gate * __ham_c_init -- 279*7c478bd9Sstevel@tonic-gate * Initialize the hash-specific portion of a cursor. 280*7c478bd9Sstevel@tonic-gate * 281*7c478bd9Sstevel@tonic-gate * PUBLIC: int __ham_c_init __P((DBC *)); 282*7c478bd9Sstevel@tonic-gate */ 283*7c478bd9Sstevel@tonic-gate int 284*7c478bd9Sstevel@tonic-gate __ham_c_init(dbc) 285*7c478bd9Sstevel@tonic-gate DBC *dbc; 286*7c478bd9Sstevel@tonic-gate { 287*7c478bd9Sstevel@tonic-gate HASH_CURSOR *new_curs; 288*7c478bd9Sstevel@tonic-gate int ret; 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate if ((ret = __os_calloc(1, sizeof(struct cursor_t), &new_curs)) != 0) 291*7c478bd9Sstevel@tonic-gate return (ret); 292*7c478bd9Sstevel@tonic-gate if ((ret = 293*7c478bd9Sstevel@tonic-gate __os_malloc(dbc->dbp->pgsize, NULL, &new_curs->split_buf)) != 0) { 294*7c478bd9Sstevel@tonic-gate __os_free(new_curs, sizeof(*new_curs)); 295*7c478bd9Sstevel@tonic-gate return (ret); 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate new_curs->dbc = dbc; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate dbc->internal = new_curs; 301*7c478bd9Sstevel@tonic-gate dbc->c_am_close = __ham_c_close; 302*7c478bd9Sstevel@tonic-gate dbc->c_am_destroy = __ham_c_destroy; 303*7c478bd9Sstevel@tonic-gate dbc->c_del = __ham_c_del; 304*7c478bd9Sstevel@tonic-gate dbc->c_get = __ham_c_get; 305*7c478bd9Sstevel@tonic-gate dbc->c_put = __ham_c_put; 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate __ham_item_init(new_curs); 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate return (0); 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate /* 313*7c478bd9Sstevel@tonic-gate * __ham_c_close -- 314*7c478bd9Sstevel@tonic-gate * Close down the cursor from a single use. 315*7c478bd9Sstevel@tonic-gate */ 316*7c478bd9Sstevel@tonic-gate static int 317*7c478bd9Sstevel@tonic-gate __ham_c_close(dbc) 318*7c478bd9Sstevel@tonic-gate DBC *dbc; 319*7c478bd9Sstevel@tonic-gate { 320*7c478bd9Sstevel@tonic-gate int ret; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate if ((ret = __ham_item_done(dbc, 0)) != 0) 323*7c478bd9Sstevel@tonic-gate return (ret); 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate __ham_item_init((HASH_CURSOR *)dbc->internal); 326*7c478bd9Sstevel@tonic-gate return (0); 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate /* 330*7c478bd9Sstevel@tonic-gate * __ham_c_destroy -- 331*7c478bd9Sstevel@tonic-gate * Cleanup the access method private part of a cursor. 332*7c478bd9Sstevel@tonic-gate */ 333*7c478bd9Sstevel@tonic-gate static int 334*7c478bd9Sstevel@tonic-gate __ham_c_destroy(dbc) 335*7c478bd9Sstevel@tonic-gate DBC *dbc; 336*7c478bd9Sstevel@tonic-gate { 337*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 340*7c478bd9Sstevel@tonic-gate if (hcp->split_buf != NULL) 341*7c478bd9Sstevel@tonic-gate __os_free(hcp->split_buf, dbc->dbp->pgsize); 342*7c478bd9Sstevel@tonic-gate __os_free(hcp, sizeof(HASH_CURSOR)); 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate return (0); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate static int 348*7c478bd9Sstevel@tonic-gate __ham_c_del(dbc, flags) 349*7c478bd9Sstevel@tonic-gate DBC *dbc; 350*7c478bd9Sstevel@tonic-gate u_int32_t flags; 351*7c478bd9Sstevel@tonic-gate { 352*7c478bd9Sstevel@tonic-gate DB *dbp; 353*7c478bd9Sstevel@tonic-gate DBT repldbt; 354*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 355*7c478bd9Sstevel@tonic-gate HASH_CURSOR save_curs; 356*7c478bd9Sstevel@tonic-gate db_pgno_t ppgno, chg_pgno; 357*7c478bd9Sstevel@tonic-gate int ret, t_ret; 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate DEBUG_LWRITE(dbc, dbc->txn, "ham_c_del", NULL, NULL, flags); 360*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 361*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 362*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate if ((ret = __db_cdelchk(dbc->dbp, flags, 365*7c478bd9Sstevel@tonic-gate F_ISSET(dbc->dbp, DB_AM_RDONLY), IS_VALID(hcp))) != 0) 366*7c478bd9Sstevel@tonic-gate return (ret); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_DELETED)) 369*7c478bd9Sstevel@tonic-gate return (DB_NOTFOUND); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * If we are in the concurrent DB product and this cursor 373*7c478bd9Sstevel@tonic-gate * is not a write cursor, then this request is invalid. 374*7c478bd9Sstevel@tonic-gate * If it is a simple write cursor, then we need to upgrade its 375*7c478bd9Sstevel@tonic-gate * lock. 376*7c478bd9Sstevel@tonic-gate */ 377*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_CDB)) { 378*7c478bd9Sstevel@tonic-gate /* Make sure it's a valid update cursor. */ 379*7c478bd9Sstevel@tonic-gate if (!F_ISSET(dbc, DBC_RMW | DBC_WRITER)) 380*7c478bd9Sstevel@tonic-gate return (EINVAL); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbc, DBC_RMW) && 383*7c478bd9Sstevel@tonic-gate (ret = lock_get(dbp->dbenv->lk_info, dbc->locker, 384*7c478bd9Sstevel@tonic-gate DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE, 385*7c478bd9Sstevel@tonic-gate &dbc->mylock)) != 0) 386*7c478bd9Sstevel@tonic-gate return (EAGAIN); 387*7c478bd9Sstevel@tonic-gate } 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate GET_META(dbp, hcp, ret); 390*7c478bd9Sstevel@tonic-gate if (ret != 0) 391*7c478bd9Sstevel@tonic-gate return (ret); 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate SAVE_CURSOR(hcp, &save_curs); 394*7c478bd9Sstevel@tonic-gate hcp->stats.hash_deleted++; 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate if ((ret = __ham_get_cpage(dbc, DB_LOCK_WRITE)) != 0) 397*7c478bd9Sstevel@tonic-gate goto out; 398*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_ISDUP) && hcp->dpgno != PGNO_INVALID) { 399*7c478bd9Sstevel@tonic-gate /* 400*7c478bd9Sstevel@tonic-gate * We are about to remove a duplicate from offpage. 401*7c478bd9Sstevel@tonic-gate * 402*7c478bd9Sstevel@tonic-gate * There are 4 cases. 403*7c478bd9Sstevel@tonic-gate * 1. We will remove an item on a page, but there are more 404*7c478bd9Sstevel@tonic-gate * items on that page. 405*7c478bd9Sstevel@tonic-gate * 2. We will remove the last item on a page, but there is a 406*7c478bd9Sstevel@tonic-gate * following page of duplicates. 407*7c478bd9Sstevel@tonic-gate * 3. We will remove the last item on a page, this page was the 408*7c478bd9Sstevel@tonic-gate * last page in a duplicate set, but there were dups before 409*7c478bd9Sstevel@tonic-gate * it. 410*7c478bd9Sstevel@tonic-gate * 4. We will remove the last item on a page, removing the last 411*7c478bd9Sstevel@tonic-gate * duplicate. 412*7c478bd9Sstevel@tonic-gate * In case 1 hcp->dpagep is unchanged. 413*7c478bd9Sstevel@tonic-gate * In case 2 hcp->dpagep comes back pointing to the next dup 414*7c478bd9Sstevel@tonic-gate * page. 415*7c478bd9Sstevel@tonic-gate * In case 3 hcp->dpagep comes back NULL. 416*7c478bd9Sstevel@tonic-gate * In case 4 hcp->dpagep comes back NULL. 417*7c478bd9Sstevel@tonic-gate * 418*7c478bd9Sstevel@tonic-gate * Case 4 results in deleting the pair off the master page. 419*7c478bd9Sstevel@tonic-gate * The normal code for doing this knows how to delete the 420*7c478bd9Sstevel@tonic-gate * duplicates, so we will handle this case in the normal code. 421*7c478bd9Sstevel@tonic-gate */ 422*7c478bd9Sstevel@tonic-gate ppgno = PREV_PGNO(hcp->dpagep); 423*7c478bd9Sstevel@tonic-gate if (ppgno == PGNO_INVALID && 424*7c478bd9Sstevel@tonic-gate NEXT_PGNO(hcp->dpagep) == PGNO_INVALID && 425*7c478bd9Sstevel@tonic-gate NUM_ENT(hcp->dpagep) == 1) 426*7c478bd9Sstevel@tonic-gate goto normal; 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate /* Remove item from duplicate page. */ 429*7c478bd9Sstevel@tonic-gate chg_pgno = hcp->dpgno; 430*7c478bd9Sstevel@tonic-gate if ((ret = __db_drem(dbc, 431*7c478bd9Sstevel@tonic-gate &hcp->dpagep, hcp->dndx, __ham_del_page)) != 0) 432*7c478bd9Sstevel@tonic-gate goto out; 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate if (hcp->dpagep == NULL) { 435*7c478bd9Sstevel@tonic-gate if (ppgno != PGNO_INVALID) { /* Case 3 */ 436*7c478bd9Sstevel@tonic-gate hcp->dpgno = ppgno; 437*7c478bd9Sstevel@tonic-gate if ((ret = __ham_get_cpage(dbc, 438*7c478bd9Sstevel@tonic-gate DB_LOCK_READ)) != 0) 439*7c478bd9Sstevel@tonic-gate goto out; 440*7c478bd9Sstevel@tonic-gate hcp->dndx = NUM_ENT(hcp->dpagep); 441*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_DELETED); 442*7c478bd9Sstevel@tonic-gate } else { /* Case 4 */ 443*7c478bd9Sstevel@tonic-gate ret = __ham_del_pair(dbc, 1); 444*7c478bd9Sstevel@tonic-gate hcp->dpgno = PGNO_INVALID; 445*7c478bd9Sstevel@tonic-gate /* 446*7c478bd9Sstevel@tonic-gate * Delpair updated the cursor queue, so we 447*7c478bd9Sstevel@tonic-gate * don't have to do that here. 448*7c478bd9Sstevel@tonic-gate */ 449*7c478bd9Sstevel@tonic-gate chg_pgno = PGNO_INVALID; 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate } else if (PGNO(hcp->dpagep) != hcp->dpgno) { 452*7c478bd9Sstevel@tonic-gate hcp->dndx = 0; /* Case 2 */ 453*7c478bd9Sstevel@tonic-gate hcp->dpgno = PGNO(hcp->dpagep); 454*7c478bd9Sstevel@tonic-gate if (ppgno == PGNO_INVALID) 455*7c478bd9Sstevel@tonic-gate memcpy(HOFFDUP_PGNO(P_ENTRY(hcp->pagep, 456*7c478bd9Sstevel@tonic-gate H_DATAINDEX(hcp->bndx))), 457*7c478bd9Sstevel@tonic-gate &hcp->dpgno, sizeof(db_pgno_t)); 458*7c478bd9Sstevel@tonic-gate /* 459*7c478bd9Sstevel@tonic-gate * We need to put the master page here, because 460*7c478bd9Sstevel@tonic-gate * although we have a duplicate page, the master 461*7c478bd9Sstevel@tonic-gate * page is dirty, and ham_item_done assumes that 462*7c478bd9Sstevel@tonic-gate * if you have a duplicate page, it's the only one 463*7c478bd9Sstevel@tonic-gate * that can be dirty. 464*7c478bd9Sstevel@tonic-gate */ 465*7c478bd9Sstevel@tonic-gate ret = __ham_put_page(dbp, hcp->pagep, 1); 466*7c478bd9Sstevel@tonic-gate hcp->pagep = NULL; 467*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_DELETED); 468*7c478bd9Sstevel@tonic-gate } else /* Case 1 */ 469*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_DELETED); 470*7c478bd9Sstevel@tonic-gate if (chg_pgno != PGNO_INVALID) 471*7c478bd9Sstevel@tonic-gate __ham_c_update(hcp, chg_pgno, 0, 0, 1); 472*7c478bd9Sstevel@tonic-gate } else if (F_ISSET(hcp, H_ISDUP)) { /* on page */ 473*7c478bd9Sstevel@tonic-gate if (hcp->dup_off == 0 && DUP_SIZE(hcp->dup_len) == 474*7c478bd9Sstevel@tonic-gate LEN_HDATA(hcp->pagep, hcp->hdr->pagesize, hcp->bndx)) 475*7c478bd9Sstevel@tonic-gate ret = __ham_del_pair(dbc, 1); 476*7c478bd9Sstevel@tonic-gate else { 477*7c478bd9Sstevel@tonic-gate repldbt.flags = 0; 478*7c478bd9Sstevel@tonic-gate F_SET(&repldbt, DB_DBT_PARTIAL); 479*7c478bd9Sstevel@tonic-gate repldbt.doff = hcp->dup_off; 480*7c478bd9Sstevel@tonic-gate repldbt.dlen = DUP_SIZE(hcp->dup_len); 481*7c478bd9Sstevel@tonic-gate repldbt.size = 0; 482*7c478bd9Sstevel@tonic-gate repldbt.data = 483*7c478bd9Sstevel@tonic-gate HKEYDATA_DATA(H_PAIRDATA(hcp->pagep, hcp->bndx)); 484*7c478bd9Sstevel@tonic-gate ret = __ham_replpair(dbc, &repldbt, 0); 485*7c478bd9Sstevel@tonic-gate hcp->dup_tlen -= DUP_SIZE(hcp->dup_len); 486*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_DELETED); 487*7c478bd9Sstevel@tonic-gate __ham_c_update(hcp, hcp->pgno, 488*7c478bd9Sstevel@tonic-gate DUP_SIZE(hcp->dup_len), 0, 1); 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate } else 492*7c478bd9Sstevel@tonic-gate /* Not a duplicate */ 493*7c478bd9Sstevel@tonic-gate normal: ret = __ham_del_pair(dbc, 1); 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate out: if ((t_ret = __ham_item_done(dbc, ret == 0)) != 0 && ret == 0) 496*7c478bd9Sstevel@tonic-gate ret = t_ret; 497*7c478bd9Sstevel@tonic-gate RELEASE_META(dbp, hcp); 498*7c478bd9Sstevel@tonic-gate RESTORE_CURSOR(dbp, hcp, &save_curs, ret); 499*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_CDB) && F_ISSET(dbc, DBC_RMW)) 500*7c478bd9Sstevel@tonic-gate (void)__lock_downgrade(dbp->dbenv->lk_info, dbc->mylock, 501*7c478bd9Sstevel@tonic-gate DB_LOCK_IWRITE, 0); 502*7c478bd9Sstevel@tonic-gate return (ret); 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate static int 506*7c478bd9Sstevel@tonic-gate __ham_c_get(dbc, key, data, flags) 507*7c478bd9Sstevel@tonic-gate DBC *dbc; 508*7c478bd9Sstevel@tonic-gate DBT *key; 509*7c478bd9Sstevel@tonic-gate DBT *data; 510*7c478bd9Sstevel@tonic-gate u_int32_t flags; 511*7c478bd9Sstevel@tonic-gate { 512*7c478bd9Sstevel@tonic-gate DB *dbp; 513*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp, save_curs; 514*7c478bd9Sstevel@tonic-gate db_lockmode_t lock_type; 515*7c478bd9Sstevel@tonic-gate int get_key, ret, t_ret; 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate DEBUG_LREAD(dbc, dbc->txn, "ham_c_get", 518*7c478bd9Sstevel@tonic-gate flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, 519*7c478bd9Sstevel@tonic-gate NULL, flags); 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 522*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 523*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 524*7c478bd9Sstevel@tonic-gate SAVE_CURSOR(hcp, &save_curs); 525*7c478bd9Sstevel@tonic-gate if ((ret = 526*7c478bd9Sstevel@tonic-gate __db_cgetchk(dbp, key, data, flags, IS_VALID(hcp))) != 0) 527*7c478bd9Sstevel@tonic-gate return (ret); 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate /* Clear OR'd in additional bits so we can check for flag equality. */ 530*7c478bd9Sstevel@tonic-gate if (LF_ISSET(DB_RMW)) { 531*7c478bd9Sstevel@tonic-gate lock_type = DB_LOCK_WRITE; 532*7c478bd9Sstevel@tonic-gate LF_CLR(DB_RMW); 533*7c478bd9Sstevel@tonic-gate } else 534*7c478bd9Sstevel@tonic-gate lock_type = DB_LOCK_READ; 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate GET_META(dbp, hcp, ret); 537*7c478bd9Sstevel@tonic-gate if (ret != 0) 538*7c478bd9Sstevel@tonic-gate return (ret); 539*7c478bd9Sstevel@tonic-gate hcp->stats.hash_get++; 540*7c478bd9Sstevel@tonic-gate hcp->seek_size = 0; 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate ret = 0; 543*7c478bd9Sstevel@tonic-gate get_key = 1; 544*7c478bd9Sstevel@tonic-gate switch (flags) { 545*7c478bd9Sstevel@tonic-gate case DB_PREV: 546*7c478bd9Sstevel@tonic-gate if (hcp->bucket != BUCKET_INVALID) { 547*7c478bd9Sstevel@tonic-gate ret = __ham_item_prev(dbc, lock_type); 548*7c478bd9Sstevel@tonic-gate break; 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 551*7c478bd9Sstevel@tonic-gate case DB_LAST: 552*7c478bd9Sstevel@tonic-gate ret = __ham_item_last(dbc, lock_type); 553*7c478bd9Sstevel@tonic-gate break; 554*7c478bd9Sstevel@tonic-gate case DB_FIRST: 555*7c478bd9Sstevel@tonic-gate ret = __ham_item_first(dbc, lock_type); 556*7c478bd9Sstevel@tonic-gate break; 557*7c478bd9Sstevel@tonic-gate case DB_NEXT_DUP: 558*7c478bd9Sstevel@tonic-gate if (hcp->bucket == BUCKET_INVALID) 559*7c478bd9Sstevel@tonic-gate ret = EINVAL; 560*7c478bd9Sstevel@tonic-gate else { 561*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_DUPONLY); 562*7c478bd9Sstevel@tonic-gate ret = __ham_item_next(dbc, lock_type); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate break; 565*7c478bd9Sstevel@tonic-gate case DB_NEXT: 566*7c478bd9Sstevel@tonic-gate if (hcp->bucket == BUCKET_INVALID) 567*7c478bd9Sstevel@tonic-gate hcp->bucket = 0; 568*7c478bd9Sstevel@tonic-gate ret = __ham_item_next(dbc, lock_type); 569*7c478bd9Sstevel@tonic-gate break; 570*7c478bd9Sstevel@tonic-gate case DB_SET: 571*7c478bd9Sstevel@tonic-gate case DB_SET_RANGE: 572*7c478bd9Sstevel@tonic-gate case DB_GET_BOTH: 573*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbc, DBC_CONTINUE)) { 574*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_DUPONLY); 575*7c478bd9Sstevel@tonic-gate ret = __ham_item_next(dbc, lock_type); 576*7c478bd9Sstevel@tonic-gate } else if (F_ISSET(dbc, DBC_KEYSET)) 577*7c478bd9Sstevel@tonic-gate ret = __ham_item(dbc, lock_type); 578*7c478bd9Sstevel@tonic-gate else 579*7c478bd9Sstevel@tonic-gate ret = __ham_lookup(dbc, key, 0, lock_type); 580*7c478bd9Sstevel@tonic-gate get_key = 0; 581*7c478bd9Sstevel@tonic-gate break; 582*7c478bd9Sstevel@tonic-gate case DB_CURRENT: 583*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_DELETED)) { 584*7c478bd9Sstevel@tonic-gate ret = DB_KEYEMPTY; 585*7c478bd9Sstevel@tonic-gate goto out; 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate ret = __ham_item(dbc, lock_type); 589*7c478bd9Sstevel@tonic-gate break; 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate /* 593*7c478bd9Sstevel@tonic-gate * Must always enter this loop to do error handling and 594*7c478bd9Sstevel@tonic-gate * check for big key/data pair. 595*7c478bd9Sstevel@tonic-gate */ 596*7c478bd9Sstevel@tonic-gate while (1) { 597*7c478bd9Sstevel@tonic-gate if (ret != 0 && ret != DB_NOTFOUND) 598*7c478bd9Sstevel@tonic-gate goto out1; 599*7c478bd9Sstevel@tonic-gate else if (F_ISSET(hcp, H_OK)) { 600*7c478bd9Sstevel@tonic-gate /* Get the key. */ 601*7c478bd9Sstevel@tonic-gate if (get_key && (ret = __db_ret(dbp, hcp->pagep, 602*7c478bd9Sstevel@tonic-gate H_KEYINDEX(hcp->bndx), key, &dbc->rkey.data, 603*7c478bd9Sstevel@tonic-gate &dbc->rkey.size)) != 0) 604*7c478bd9Sstevel@tonic-gate goto out1; 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate ret = __ham_dup_return(dbc, data, flags); 607*7c478bd9Sstevel@tonic-gate break; 608*7c478bd9Sstevel@tonic-gate } else if (!F_ISSET(hcp, H_NOMORE)) { 609*7c478bd9Sstevel@tonic-gate abort(); 610*7c478bd9Sstevel@tonic-gate break; 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate /* 614*7c478bd9Sstevel@tonic-gate * Ran out of entries in a bucket; change buckets. 615*7c478bd9Sstevel@tonic-gate */ 616*7c478bd9Sstevel@tonic-gate switch (flags) { 617*7c478bd9Sstevel@tonic-gate case DB_LAST: 618*7c478bd9Sstevel@tonic-gate case DB_PREV: 619*7c478bd9Sstevel@tonic-gate ret = __ham_item_done(dbc, 0); 620*7c478bd9Sstevel@tonic-gate if (hcp->bucket == 0) { 621*7c478bd9Sstevel@tonic-gate ret = DB_NOTFOUND; 622*7c478bd9Sstevel@tonic-gate goto out1; 623*7c478bd9Sstevel@tonic-gate } 624*7c478bd9Sstevel@tonic-gate hcp->bucket--; 625*7c478bd9Sstevel@tonic-gate hcp->bndx = NDX_INVALID; 626*7c478bd9Sstevel@tonic-gate if (ret == 0) 627*7c478bd9Sstevel@tonic-gate ret = __ham_item_prev(dbc, lock_type); 628*7c478bd9Sstevel@tonic-gate break; 629*7c478bd9Sstevel@tonic-gate case DB_FIRST: 630*7c478bd9Sstevel@tonic-gate case DB_NEXT: 631*7c478bd9Sstevel@tonic-gate ret = __ham_item_done(dbc, 0); 632*7c478bd9Sstevel@tonic-gate hcp->bndx = NDX_INVALID; 633*7c478bd9Sstevel@tonic-gate hcp->bucket++; 634*7c478bd9Sstevel@tonic-gate hcp->pgno = PGNO_INVALID; 635*7c478bd9Sstevel@tonic-gate hcp->pagep = NULL; 636*7c478bd9Sstevel@tonic-gate if (hcp->bucket > hcp->hdr->max_bucket) { 637*7c478bd9Sstevel@tonic-gate ret = DB_NOTFOUND; 638*7c478bd9Sstevel@tonic-gate goto out1; 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate if (ret == 0) 641*7c478bd9Sstevel@tonic-gate ret = __ham_item_next(dbc, lock_type); 642*7c478bd9Sstevel@tonic-gate break; 643*7c478bd9Sstevel@tonic-gate case DB_GET_BOTH: 644*7c478bd9Sstevel@tonic-gate case DB_NEXT_DUP: 645*7c478bd9Sstevel@tonic-gate case DB_SET: 646*7c478bd9Sstevel@tonic-gate case DB_SET_RANGE: 647*7c478bd9Sstevel@tonic-gate /* Key not found. */ 648*7c478bd9Sstevel@tonic-gate ret = DB_NOTFOUND; 649*7c478bd9Sstevel@tonic-gate goto out1; 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate out1: if ((t_ret = __ham_item_done(dbc, 0)) != 0 && ret == 0) 653*7c478bd9Sstevel@tonic-gate ret = t_ret; 654*7c478bd9Sstevel@tonic-gate out: RELEASE_META(dbp, hcp); 655*7c478bd9Sstevel@tonic-gate RESTORE_CURSOR(dbp, hcp, &save_curs, ret); 656*7c478bd9Sstevel@tonic-gate return (ret); 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate static int 660*7c478bd9Sstevel@tonic-gate __ham_c_put(dbc, key, data, flags) 661*7c478bd9Sstevel@tonic-gate DBC *dbc; 662*7c478bd9Sstevel@tonic-gate DBT *key; 663*7c478bd9Sstevel@tonic-gate DBT *data; 664*7c478bd9Sstevel@tonic-gate u_int32_t flags; 665*7c478bd9Sstevel@tonic-gate { 666*7c478bd9Sstevel@tonic-gate DB *dbp; 667*7c478bd9Sstevel@tonic-gate DBT tmp_val, *myval; 668*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp, save_curs; 669*7c478bd9Sstevel@tonic-gate u_int32_t nbytes; 670*7c478bd9Sstevel@tonic-gate int ret, t_ret; 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 673*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 674*7c478bd9Sstevel@tonic-gate DEBUG_LWRITE(dbc, dbc->txn, "ham_c_put", 675*7c478bd9Sstevel@tonic-gate flags == DB_KEYFIRST || flags == DB_KEYLAST ? key : NULL, 676*7c478bd9Sstevel@tonic-gate data, flags); 677*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate if ((ret = __db_cputchk(dbp, key, data, flags, 680*7c478bd9Sstevel@tonic-gate F_ISSET(dbp, DB_AM_RDONLY), IS_VALID(hcp))) != 0) 681*7c478bd9Sstevel@tonic-gate return (ret); 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_DELETED) && 684*7c478bd9Sstevel@tonic-gate flags != DB_KEYFIRST && flags != DB_KEYLAST) 685*7c478bd9Sstevel@tonic-gate return (DB_NOTFOUND); 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate /* 688*7c478bd9Sstevel@tonic-gate * If we are in the concurrent DB product and this cursor 689*7c478bd9Sstevel@tonic-gate * is not a write cursor, then this request is invalid. 690*7c478bd9Sstevel@tonic-gate * If it is a simple write cursor, then we need to upgrade its 691*7c478bd9Sstevel@tonic-gate * lock. 692*7c478bd9Sstevel@tonic-gate */ 693*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_CDB)) { 694*7c478bd9Sstevel@tonic-gate /* Make sure it's a valid update cursor. */ 695*7c478bd9Sstevel@tonic-gate if (!F_ISSET(dbc, DBC_RMW | DBC_WRITER)) 696*7c478bd9Sstevel@tonic-gate return (EINVAL); 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbc, DBC_RMW) && 699*7c478bd9Sstevel@tonic-gate (ret = lock_get(dbp->dbenv->lk_info, dbc->locker, 700*7c478bd9Sstevel@tonic-gate DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE, 701*7c478bd9Sstevel@tonic-gate &dbc->mylock)) != 0) 702*7c478bd9Sstevel@tonic-gate return (EAGAIN); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate GET_META(dbp, hcp, ret); 706*7c478bd9Sstevel@tonic-gate if (ret != 0) 707*7c478bd9Sstevel@tonic-gate return (ret); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate SAVE_CURSOR(hcp, &save_curs); 710*7c478bd9Sstevel@tonic-gate hcp->stats.hash_put++; 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate switch (flags) { 713*7c478bd9Sstevel@tonic-gate case DB_KEYLAST: 714*7c478bd9Sstevel@tonic-gate case DB_KEYFIRST: 715*7c478bd9Sstevel@tonic-gate nbytes = (ISBIG(hcp, key->size) ? HOFFPAGE_PSIZE : 716*7c478bd9Sstevel@tonic-gate HKEYDATA_PSIZE(key->size)) + 717*7c478bd9Sstevel@tonic-gate (ISBIG(hcp, data->size) ? HOFFPAGE_PSIZE : 718*7c478bd9Sstevel@tonic-gate HKEYDATA_PSIZE(data->size)); 719*7c478bd9Sstevel@tonic-gate if ((ret = __ham_lookup(dbc, 720*7c478bd9Sstevel@tonic-gate key, nbytes, DB_LOCK_WRITE)) == DB_NOTFOUND) { 721*7c478bd9Sstevel@tonic-gate ret = 0; 722*7c478bd9Sstevel@tonic-gate if (hcp->seek_found_page != PGNO_INVALID && 723*7c478bd9Sstevel@tonic-gate hcp->seek_found_page != hcp->pgno) { 724*7c478bd9Sstevel@tonic-gate if ((ret = __ham_item_done(dbc, 0)) != 0) 725*7c478bd9Sstevel@tonic-gate goto out; 726*7c478bd9Sstevel@tonic-gate hcp->pgno = hcp->seek_found_page; 727*7c478bd9Sstevel@tonic-gate hcp->bndx = NDX_INVALID; 728*7c478bd9Sstevel@tonic-gate } 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate if (F_ISSET(data, DB_DBT_PARTIAL) && data->doff != 0) { 731*7c478bd9Sstevel@tonic-gate /* 732*7c478bd9Sstevel@tonic-gate * A partial put, but the key does not exist 733*7c478bd9Sstevel@tonic-gate * and we are not beginning the write at 0. 734*7c478bd9Sstevel@tonic-gate * We must create a data item padded up to doff 735*7c478bd9Sstevel@tonic-gate * and then write the new bytes represented by 736*7c478bd9Sstevel@tonic-gate * val. 737*7c478bd9Sstevel@tonic-gate */ 738*7c478bd9Sstevel@tonic-gate if ((ret = __ham_init_dbt(&tmp_val, 739*7c478bd9Sstevel@tonic-gate data->size + data->doff, 740*7c478bd9Sstevel@tonic-gate &dbc->rdata.data, &dbc->rdata.size)) == 0) { 741*7c478bd9Sstevel@tonic-gate memset(tmp_val.data, 0, data->doff); 742*7c478bd9Sstevel@tonic-gate memcpy((u_int8_t *)tmp_val.data + 743*7c478bd9Sstevel@tonic-gate data->doff, data->data, data->size); 744*7c478bd9Sstevel@tonic-gate myval = &tmp_val; 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate } else 747*7c478bd9Sstevel@tonic-gate myval = (DBT *)data; 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate if (ret == 0) 750*7c478bd9Sstevel@tonic-gate ret = __ham_add_el(dbc, key, myval, H_KEYDATA); 751*7c478bd9Sstevel@tonic-gate goto done; 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate break; 754*7c478bd9Sstevel@tonic-gate case DB_BEFORE: 755*7c478bd9Sstevel@tonic-gate case DB_AFTER: 756*7c478bd9Sstevel@tonic-gate case DB_CURRENT: 757*7c478bd9Sstevel@tonic-gate ret = __ham_item(dbc, DB_LOCK_WRITE); 758*7c478bd9Sstevel@tonic-gate break; 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate if (ret == 0) { 762*7c478bd9Sstevel@tonic-gate if ((flags == DB_CURRENT && !F_ISSET(hcp, H_ISDUP)) || 763*7c478bd9Sstevel@tonic-gate ((flags == DB_KEYFIRST || flags == DB_KEYLAST) && 764*7c478bd9Sstevel@tonic-gate !F_ISSET(dbp, DB_AM_DUP))) 765*7c478bd9Sstevel@tonic-gate ret = __ham_overwrite(dbc, data); 766*7c478bd9Sstevel@tonic-gate else 767*7c478bd9Sstevel@tonic-gate ret = __ham_add_dup(dbc, data, flags); 768*7c478bd9Sstevel@tonic-gate } 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate done: if (ret == 0 && F_ISSET(hcp, H_EXPAND)) { 771*7c478bd9Sstevel@tonic-gate ret = __ham_expand_table(dbc); 772*7c478bd9Sstevel@tonic-gate F_CLR(hcp, H_EXPAND); 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate if ((t_ret = __ham_item_done(dbc, ret == 0)) != 0 && ret == 0) 776*7c478bd9Sstevel@tonic-gate ret = t_ret; 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate out: RELEASE_META(dbp, hcp); 779*7c478bd9Sstevel@tonic-gate RESTORE_CURSOR(dbp, hcp, &save_curs, ret); 780*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_CDB) && F_ISSET(dbc, DBC_RMW)) 781*7c478bd9Sstevel@tonic-gate (void)__lock_downgrade(dbp->dbenv->lk_info, dbc->mylock, 782*7c478bd9Sstevel@tonic-gate DB_LOCK_IWRITE, 0); 783*7c478bd9Sstevel@tonic-gate return (ret); 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate /********************************* UTILITIES ************************/ 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate /* 789*7c478bd9Sstevel@tonic-gate * __ham_expand_table -- 790*7c478bd9Sstevel@tonic-gate */ 791*7c478bd9Sstevel@tonic-gate static int 792*7c478bd9Sstevel@tonic-gate __ham_expand_table(dbc) 793*7c478bd9Sstevel@tonic-gate DBC *dbc; 794*7c478bd9Sstevel@tonic-gate { 795*7c478bd9Sstevel@tonic-gate DB *dbp; 796*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 797*7c478bd9Sstevel@tonic-gate DB_LSN new_lsn; 798*7c478bd9Sstevel@tonic-gate u_int32_t old_bucket, new_bucket, spare_ndx; 799*7c478bd9Sstevel@tonic-gate int ret; 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 802*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 803*7c478bd9Sstevel@tonic-gate ret = 0; 804*7c478bd9Sstevel@tonic-gate DIRTY_META(dbp, hcp, ret); 805*7c478bd9Sstevel@tonic-gate if (ret) 806*7c478bd9Sstevel@tonic-gate return (ret); 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate /* 809*7c478bd9Sstevel@tonic-gate * If the split point is about to increase, make sure that we 810*7c478bd9Sstevel@tonic-gate * have enough extra pages. The calculation here is weird. 811*7c478bd9Sstevel@tonic-gate * We'd like to do this after we've upped max_bucket, but it's 812*7c478bd9Sstevel@tonic-gate * too late then because we've logged the meta-data split. What 813*7c478bd9Sstevel@tonic-gate * we'll do between then and now is increment max bucket and then 814*7c478bd9Sstevel@tonic-gate * see what the log of one greater than that is; here we have to 815*7c478bd9Sstevel@tonic-gate * look at the log of max + 2. VERY NASTY STUFF. 816*7c478bd9Sstevel@tonic-gate */ 817*7c478bd9Sstevel@tonic-gate if (__db_log2(hcp->hdr->max_bucket + 2) > hcp->hdr->ovfl_point) { 818*7c478bd9Sstevel@tonic-gate /* 819*7c478bd9Sstevel@tonic-gate * We are about to shift the split point. Make sure that 820*7c478bd9Sstevel@tonic-gate * if the next doubling is going to be big (more than 8 821*7c478bd9Sstevel@tonic-gate * pages), we have some extra pages around. 822*7c478bd9Sstevel@tonic-gate */ 823*7c478bd9Sstevel@tonic-gate if (hcp->hdr->max_bucket + 1 >= 8 && 824*7c478bd9Sstevel@tonic-gate hcp->hdr->spares[hcp->hdr->ovfl_point] < 825*7c478bd9Sstevel@tonic-gate hcp->hdr->spares[hcp->hdr->ovfl_point - 1] + 826*7c478bd9Sstevel@tonic-gate hcp->hdr->ovfl_point + 1) 827*7c478bd9Sstevel@tonic-gate __ham_init_ovflpages(dbc); 828*7c478bd9Sstevel@tonic-gate } 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate /* Now we can log the meta-data split. */ 831*7c478bd9Sstevel@tonic-gate if (DB_LOGGING(dbc)) { 832*7c478bd9Sstevel@tonic-gate if ((ret = __ham_splitmeta_log(dbp->dbenv->lg_info, 833*7c478bd9Sstevel@tonic-gate dbc->txn, &new_lsn, 0, dbp->log_fileid, 834*7c478bd9Sstevel@tonic-gate hcp->hdr->max_bucket, hcp->hdr->ovfl_point, 835*7c478bd9Sstevel@tonic-gate hcp->hdr->spares[hcp->hdr->ovfl_point], 836*7c478bd9Sstevel@tonic-gate &hcp->hdr->lsn)) != 0) 837*7c478bd9Sstevel@tonic-gate return (ret); 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate hcp->hdr->lsn = new_lsn; 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate hcp->stats.hash_expansions++; 843*7c478bd9Sstevel@tonic-gate new_bucket = ++hcp->hdr->max_bucket; 844*7c478bd9Sstevel@tonic-gate old_bucket = (hcp->hdr->max_bucket & hcp->hdr->low_mask); 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate /* 847*7c478bd9Sstevel@tonic-gate * If the split point is increasing, copy the current contents 848*7c478bd9Sstevel@tonic-gate * of the spare split bucket to the next bucket. 849*7c478bd9Sstevel@tonic-gate */ 850*7c478bd9Sstevel@tonic-gate spare_ndx = __db_log2(hcp->hdr->max_bucket + 1); 851*7c478bd9Sstevel@tonic-gate if (spare_ndx > hcp->hdr->ovfl_point) { 852*7c478bd9Sstevel@tonic-gate hcp->hdr->spares[spare_ndx] = 853*7c478bd9Sstevel@tonic-gate hcp->hdr->spares[hcp->hdr->ovfl_point]; 854*7c478bd9Sstevel@tonic-gate hcp->hdr->ovfl_point = spare_ndx; 855*7c478bd9Sstevel@tonic-gate } 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate if (new_bucket > hcp->hdr->high_mask) { 858*7c478bd9Sstevel@tonic-gate /* Starting a new doubling */ 859*7c478bd9Sstevel@tonic-gate hcp->hdr->low_mask = hcp->hdr->high_mask; 860*7c478bd9Sstevel@tonic-gate hcp->hdr->high_mask = new_bucket | hcp->hdr->low_mask; 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate if (BUCKET_TO_PAGE(hcp, new_bucket) > MAX_PAGES(hcp)) { 864*7c478bd9Sstevel@tonic-gate __db_err(dbp->dbenv, 865*7c478bd9Sstevel@tonic-gate "hash: Cannot allocate new bucket. Pages exhausted."); 866*7c478bd9Sstevel@tonic-gate return (ENOSPC); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate /* Relocate records to the new bucket */ 870*7c478bd9Sstevel@tonic-gate return (__ham_split_page(dbc, old_bucket, new_bucket)); 871*7c478bd9Sstevel@tonic-gate } 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate /* 874*7c478bd9Sstevel@tonic-gate * PUBLIC: u_int32_t __ham_call_hash __P((HASH_CURSOR *, u_int8_t *, int32_t)); 875*7c478bd9Sstevel@tonic-gate */ 876*7c478bd9Sstevel@tonic-gate u_int32_t 877*7c478bd9Sstevel@tonic-gate __ham_call_hash(hcp, k, len) 878*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 879*7c478bd9Sstevel@tonic-gate u_int8_t *k; 880*7c478bd9Sstevel@tonic-gate int32_t len; 881*7c478bd9Sstevel@tonic-gate { 882*7c478bd9Sstevel@tonic-gate u_int32_t n, bucket; 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate n = (u_int32_t)(hcp->dbc->dbp->h_hash(k, len)); 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate bucket = n & hcp->hdr->high_mask; 887*7c478bd9Sstevel@tonic-gate if (bucket > hcp->hdr->max_bucket) 888*7c478bd9Sstevel@tonic-gate bucket = bucket & hcp->hdr->low_mask; 889*7c478bd9Sstevel@tonic-gate return (bucket); 890*7c478bd9Sstevel@tonic-gate } 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate /* 893*7c478bd9Sstevel@tonic-gate * Check for duplicates, and call __db_ret appropriately. Release 894*7c478bd9Sstevel@tonic-gate * everything held by the cursor. 895*7c478bd9Sstevel@tonic-gate */ 896*7c478bd9Sstevel@tonic-gate static int 897*7c478bd9Sstevel@tonic-gate __ham_dup_return(dbc, val, flags) 898*7c478bd9Sstevel@tonic-gate DBC *dbc; 899*7c478bd9Sstevel@tonic-gate DBT *val; 900*7c478bd9Sstevel@tonic-gate u_int32_t flags; 901*7c478bd9Sstevel@tonic-gate { 902*7c478bd9Sstevel@tonic-gate DB *dbp; 903*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 904*7c478bd9Sstevel@tonic-gate PAGE *pp; 905*7c478bd9Sstevel@tonic-gate DBT *myval, tmp_val; 906*7c478bd9Sstevel@tonic-gate db_indx_t ndx; 907*7c478bd9Sstevel@tonic-gate db_pgno_t pgno; 908*7c478bd9Sstevel@tonic-gate u_int32_t off, tlen; 909*7c478bd9Sstevel@tonic-gate u_int8_t *hk, type; 910*7c478bd9Sstevel@tonic-gate int cmp, ret; 911*7c478bd9Sstevel@tonic-gate db_indx_t len; 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate /* Check for duplicate and return the first one. */ 914*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 915*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 916*7c478bd9Sstevel@tonic-gate ndx = H_DATAINDEX(hcp->bndx); 917*7c478bd9Sstevel@tonic-gate type = HPAGE_TYPE(hcp->pagep, ndx); 918*7c478bd9Sstevel@tonic-gate pp = hcp->pagep; 919*7c478bd9Sstevel@tonic-gate myval = val; 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate /* 922*7c478bd9Sstevel@tonic-gate * There are 4 cases: 923*7c478bd9Sstevel@tonic-gate * 1. We are not in duplicate, simply call db_ret. 924*7c478bd9Sstevel@tonic-gate * 2. We are looking at keys and stumbled onto a duplicate. 925*7c478bd9Sstevel@tonic-gate * 3. We are in the middle of a duplicate set. (ISDUP set) 926*7c478bd9Sstevel@tonic-gate * 4. This is a duplicate and we need to return a specific item. 927*7c478bd9Sstevel@tonic-gate */ 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate /* 930*7c478bd9Sstevel@tonic-gate * Here we check for the case where we just stumbled onto a 931*7c478bd9Sstevel@tonic-gate * duplicate. In this case, we do initialization and then 932*7c478bd9Sstevel@tonic-gate * let the normal duplicate code handle it. 933*7c478bd9Sstevel@tonic-gate */ 934*7c478bd9Sstevel@tonic-gate if (!F_ISSET(hcp, H_ISDUP)) 935*7c478bd9Sstevel@tonic-gate if (type == H_DUPLICATE) { 936*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_ISDUP); 937*7c478bd9Sstevel@tonic-gate hcp->dup_tlen = LEN_HDATA(hcp->pagep, 938*7c478bd9Sstevel@tonic-gate hcp->hdr->pagesize, hcp->bndx); 939*7c478bd9Sstevel@tonic-gate hk = H_PAIRDATA(hcp->pagep, hcp->bndx); 940*7c478bd9Sstevel@tonic-gate if (flags == DB_LAST || flags == DB_PREV) { 941*7c478bd9Sstevel@tonic-gate hcp->dndx = 0; 942*7c478bd9Sstevel@tonic-gate hcp->dup_off = 0; 943*7c478bd9Sstevel@tonic-gate do { 944*7c478bd9Sstevel@tonic-gate memcpy(&len, 945*7c478bd9Sstevel@tonic-gate HKEYDATA_DATA(hk) + hcp->dup_off, 946*7c478bd9Sstevel@tonic-gate sizeof(db_indx_t)); 947*7c478bd9Sstevel@tonic-gate hcp->dup_off += DUP_SIZE(len); 948*7c478bd9Sstevel@tonic-gate hcp->dndx++; 949*7c478bd9Sstevel@tonic-gate } while (hcp->dup_off < hcp->dup_tlen); 950*7c478bd9Sstevel@tonic-gate hcp->dup_off -= DUP_SIZE(len); 951*7c478bd9Sstevel@tonic-gate hcp->dndx--; 952*7c478bd9Sstevel@tonic-gate } else { 953*7c478bd9Sstevel@tonic-gate memcpy(&len, 954*7c478bd9Sstevel@tonic-gate HKEYDATA_DATA(hk), sizeof(db_indx_t)); 955*7c478bd9Sstevel@tonic-gate hcp->dup_off = 0; 956*7c478bd9Sstevel@tonic-gate hcp->dndx = 0; 957*7c478bd9Sstevel@tonic-gate } 958*7c478bd9Sstevel@tonic-gate hcp->dup_len = len; 959*7c478bd9Sstevel@tonic-gate } else if (type == H_OFFDUP) { 960*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_ISDUP); 961*7c478bd9Sstevel@tonic-gate memcpy(&pgno, HOFFDUP_PGNO(P_ENTRY(hcp->pagep, ndx)), 962*7c478bd9Sstevel@tonic-gate sizeof(db_pgno_t)); 963*7c478bd9Sstevel@tonic-gate if (flags == DB_LAST || flags == DB_PREV) { 964*7c478bd9Sstevel@tonic-gate if ((ret = __db_dend(dbc, 965*7c478bd9Sstevel@tonic-gate pgno, &hcp->dpagep)) != 0) 966*7c478bd9Sstevel@tonic-gate return (ret); 967*7c478bd9Sstevel@tonic-gate hcp->dpgno = PGNO(hcp->dpagep); 968*7c478bd9Sstevel@tonic-gate hcp->dndx = NUM_ENT(hcp->dpagep) - 1; 969*7c478bd9Sstevel@tonic-gate } else if ((ret = __ham_next_cpage(dbc, 970*7c478bd9Sstevel@tonic-gate pgno, 0, H_ISDUP)) != 0) 971*7c478bd9Sstevel@tonic-gate return (ret); 972*7c478bd9Sstevel@tonic-gate } 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate 975*7c478bd9Sstevel@tonic-gate /* 976*7c478bd9Sstevel@tonic-gate * If we are retrieving a specific key/data pair, then we 977*7c478bd9Sstevel@tonic-gate * may need to adjust the cursor before returning data. 978*7c478bd9Sstevel@tonic-gate */ 979*7c478bd9Sstevel@tonic-gate if (flags == DB_GET_BOTH) { 980*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_ISDUP)) { 981*7c478bd9Sstevel@tonic-gate if (hcp->dpgno != PGNO_INVALID) { 982*7c478bd9Sstevel@tonic-gate if ((ret = __db_dsearch(dbc, 0, val, 983*7c478bd9Sstevel@tonic-gate hcp->dpgno, &hcp->dndx, &hcp->dpagep, &cmp)) 984*7c478bd9Sstevel@tonic-gate != 0) 985*7c478bd9Sstevel@tonic-gate return (ret); 986*7c478bd9Sstevel@tonic-gate if (cmp == 0) 987*7c478bd9Sstevel@tonic-gate hcp->dpgno = PGNO(hcp->dpagep); 988*7c478bd9Sstevel@tonic-gate } else { 989*7c478bd9Sstevel@tonic-gate __ham_dsearch(dbc, val, &off, &cmp); 990*7c478bd9Sstevel@tonic-gate hcp->dup_off = off; 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate } else { 993*7c478bd9Sstevel@tonic-gate hk = H_PAIRDATA(hcp->pagep, hcp->bndx); 994*7c478bd9Sstevel@tonic-gate if (((HKEYDATA *)hk)->type == H_OFFPAGE) { 995*7c478bd9Sstevel@tonic-gate memcpy(&tlen, 996*7c478bd9Sstevel@tonic-gate HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); 997*7c478bd9Sstevel@tonic-gate memcpy(&pgno, 998*7c478bd9Sstevel@tonic-gate HOFFPAGE_PGNO(hk), sizeof(db_pgno_t)); 999*7c478bd9Sstevel@tonic-gate if ((ret = __db_moff(dbp, val, 1000*7c478bd9Sstevel@tonic-gate pgno, tlen, dbp->dup_compare, &cmp)) != 0) 1001*7c478bd9Sstevel@tonic-gate return (ret); 1002*7c478bd9Sstevel@tonic-gate } else { 1003*7c478bd9Sstevel@tonic-gate /* 1004*7c478bd9Sstevel@tonic-gate * We do not zero tmp_val since the comparison 1005*7c478bd9Sstevel@tonic-gate * routines may only look at data and size. 1006*7c478bd9Sstevel@tonic-gate */ 1007*7c478bd9Sstevel@tonic-gate tmp_val.data = HKEYDATA_DATA(hk); 1008*7c478bd9Sstevel@tonic-gate tmp_val.size = LEN_HDATA(hcp->pagep, 1009*7c478bd9Sstevel@tonic-gate dbp->pgsize, hcp->bndx); 1010*7c478bd9Sstevel@tonic-gate cmp = dbp->dup_compare == NULL ? 1011*7c478bd9Sstevel@tonic-gate __bam_defcmp(&tmp_val, val) : 1012*7c478bd9Sstevel@tonic-gate dbp->dup_compare(&tmp_val, val); 1013*7c478bd9Sstevel@tonic-gate } 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate if (cmp != 0) 1017*7c478bd9Sstevel@tonic-gate return (DB_NOTFOUND); 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate /* 1021*7c478bd9Sstevel@tonic-gate * Now, everything is initialized, grab a duplicate if 1022*7c478bd9Sstevel@tonic-gate * necessary. 1023*7c478bd9Sstevel@tonic-gate */ 1024*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_ISDUP)) 1025*7c478bd9Sstevel@tonic-gate if (hcp->dpgno != PGNO_INVALID) { 1026*7c478bd9Sstevel@tonic-gate pp = hcp->dpagep; 1027*7c478bd9Sstevel@tonic-gate ndx = hcp->dndx; 1028*7c478bd9Sstevel@tonic-gate } else { 1029*7c478bd9Sstevel@tonic-gate /* 1030*7c478bd9Sstevel@tonic-gate * Copy the DBT in case we are retrieving into user 1031*7c478bd9Sstevel@tonic-gate * memory and we need the parameters for it. If the 1032*7c478bd9Sstevel@tonic-gate * user requested a partial, then we need to adjust 1033*7c478bd9Sstevel@tonic-gate * the user's parameters to get the partial of the 1034*7c478bd9Sstevel@tonic-gate * duplicate which is itself a partial. 1035*7c478bd9Sstevel@tonic-gate */ 1036*7c478bd9Sstevel@tonic-gate memcpy(&tmp_val, val, sizeof(*val)); 1037*7c478bd9Sstevel@tonic-gate if (F_ISSET(&tmp_val, DB_DBT_PARTIAL)) { 1038*7c478bd9Sstevel@tonic-gate /* 1039*7c478bd9Sstevel@tonic-gate * Take the user's length unless it would go 1040*7c478bd9Sstevel@tonic-gate * beyond the end of the duplicate. 1041*7c478bd9Sstevel@tonic-gate */ 1042*7c478bd9Sstevel@tonic-gate if (tmp_val.doff + hcp->dup_off > hcp->dup_len) 1043*7c478bd9Sstevel@tonic-gate tmp_val.dlen = 0; 1044*7c478bd9Sstevel@tonic-gate else if (tmp_val.dlen + tmp_val.doff > 1045*7c478bd9Sstevel@tonic-gate hcp->dup_len) 1046*7c478bd9Sstevel@tonic-gate tmp_val.dlen = 1047*7c478bd9Sstevel@tonic-gate hcp->dup_len - tmp_val.doff; 1048*7c478bd9Sstevel@tonic-gate 1049*7c478bd9Sstevel@tonic-gate /* 1050*7c478bd9Sstevel@tonic-gate * Calculate the new offset. 1051*7c478bd9Sstevel@tonic-gate */ 1052*7c478bd9Sstevel@tonic-gate tmp_val.doff += hcp->dup_off; 1053*7c478bd9Sstevel@tonic-gate } else { 1054*7c478bd9Sstevel@tonic-gate F_SET(&tmp_val, DB_DBT_PARTIAL); 1055*7c478bd9Sstevel@tonic-gate tmp_val.dlen = hcp->dup_len; 1056*7c478bd9Sstevel@tonic-gate tmp_val.doff = hcp->dup_off + sizeof(db_indx_t); 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate myval = &tmp_val; 1059*7c478bd9Sstevel@tonic-gate } 1060*7c478bd9Sstevel@tonic-gate 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate /* 1063*7c478bd9Sstevel@tonic-gate * Finally, if we had a duplicate, pp, ndx, and myval should be 1064*7c478bd9Sstevel@tonic-gate * set appropriately. 1065*7c478bd9Sstevel@tonic-gate */ 1066*7c478bd9Sstevel@tonic-gate if ((ret = __db_ret(dbp, pp, ndx, myval, &dbc->rdata.data, 1067*7c478bd9Sstevel@tonic-gate &dbc->rdata.size)) != 0) 1068*7c478bd9Sstevel@tonic-gate return (ret); 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate /* 1071*7c478bd9Sstevel@tonic-gate * In case we sent a temporary off to db_ret, set the real 1072*7c478bd9Sstevel@tonic-gate * return values. 1073*7c478bd9Sstevel@tonic-gate */ 1074*7c478bd9Sstevel@tonic-gate val->data = myval->data; 1075*7c478bd9Sstevel@tonic-gate val->size = myval->size; 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate return (0); 1078*7c478bd9Sstevel@tonic-gate } 1079*7c478bd9Sstevel@tonic-gate 1080*7c478bd9Sstevel@tonic-gate static int 1081*7c478bd9Sstevel@tonic-gate __ham_overwrite(dbc, nval) 1082*7c478bd9Sstevel@tonic-gate DBC *dbc; 1083*7c478bd9Sstevel@tonic-gate DBT *nval; 1084*7c478bd9Sstevel@tonic-gate { 1085*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 1086*7c478bd9Sstevel@tonic-gate DBT *myval, tmp_val; 1087*7c478bd9Sstevel@tonic-gate u_int8_t *hk; 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 1090*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbc->dbp, DB_AM_DUP)) 1091*7c478bd9Sstevel@tonic-gate return (__ham_add_dup(dbc, nval, DB_KEYLAST)); 1092*7c478bd9Sstevel@tonic-gate else if (!F_ISSET(nval, DB_DBT_PARTIAL)) { 1093*7c478bd9Sstevel@tonic-gate /* Put/overwrite */ 1094*7c478bd9Sstevel@tonic-gate memcpy(&tmp_val, nval, sizeof(*nval)); 1095*7c478bd9Sstevel@tonic-gate F_SET(&tmp_val, DB_DBT_PARTIAL); 1096*7c478bd9Sstevel@tonic-gate tmp_val.doff = 0; 1097*7c478bd9Sstevel@tonic-gate hk = H_PAIRDATA(hcp->pagep, hcp->bndx); 1098*7c478bd9Sstevel@tonic-gate if (HPAGE_PTYPE(hk) == H_OFFPAGE) 1099*7c478bd9Sstevel@tonic-gate memcpy(&tmp_val.dlen, 1100*7c478bd9Sstevel@tonic-gate HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); 1101*7c478bd9Sstevel@tonic-gate else 1102*7c478bd9Sstevel@tonic-gate tmp_val.dlen = LEN_HDATA(hcp->pagep, 1103*7c478bd9Sstevel@tonic-gate hcp->hdr->pagesize,hcp->bndx); 1104*7c478bd9Sstevel@tonic-gate myval = &tmp_val; 1105*7c478bd9Sstevel@tonic-gate } else /* Regular partial put */ 1106*7c478bd9Sstevel@tonic-gate myval = nval; 1107*7c478bd9Sstevel@tonic-gate 1108*7c478bd9Sstevel@tonic-gate return (__ham_replpair(dbc, myval, 0)); 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate /* 1112*7c478bd9Sstevel@tonic-gate * Given a key and a cursor, sets the cursor to the page/ndx on which 1113*7c478bd9Sstevel@tonic-gate * the key resides. If the key is found, the cursor H_OK flag is set 1114*7c478bd9Sstevel@tonic-gate * and the pagep, bndx, pgno (dpagep, dndx, dpgno) fields are set. 1115*7c478bd9Sstevel@tonic-gate * If the key is not found, the H_OK flag is not set. If the sought 1116*7c478bd9Sstevel@tonic-gate * field is non-0, the pagep, bndx, pgno (dpagep, dndx, dpgno) fields 1117*7c478bd9Sstevel@tonic-gate * are set indicating where an add might take place. If it is 0, 1118*7c478bd9Sstevel@tonic-gate * non of the cursor pointer field are valid. 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate static int 1121*7c478bd9Sstevel@tonic-gate __ham_lookup(dbc, key, sought, mode) 1122*7c478bd9Sstevel@tonic-gate DBC *dbc; 1123*7c478bd9Sstevel@tonic-gate const DBT *key; 1124*7c478bd9Sstevel@tonic-gate u_int32_t sought; 1125*7c478bd9Sstevel@tonic-gate db_lockmode_t mode; 1126*7c478bd9Sstevel@tonic-gate { 1127*7c478bd9Sstevel@tonic-gate DB *dbp; 1128*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 1129*7c478bd9Sstevel@tonic-gate db_pgno_t pgno; 1130*7c478bd9Sstevel@tonic-gate u_int32_t tlen; 1131*7c478bd9Sstevel@tonic-gate int match, ret, t_ret; 1132*7c478bd9Sstevel@tonic-gate u_int8_t *hk; 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 1135*7c478bd9Sstevel@tonic-gate hcp = (HASH_CURSOR *)dbc->internal; 1136*7c478bd9Sstevel@tonic-gate /* 1137*7c478bd9Sstevel@tonic-gate * Set up cursor so that we're looking for space to add an item 1138*7c478bd9Sstevel@tonic-gate * as we cycle through the pages looking for the key. 1139*7c478bd9Sstevel@tonic-gate */ 1140*7c478bd9Sstevel@tonic-gate if ((ret = __ham_item_reset(dbc)) != 0) 1141*7c478bd9Sstevel@tonic-gate return (ret); 1142*7c478bd9Sstevel@tonic-gate hcp->seek_size = sought; 1143*7c478bd9Sstevel@tonic-gate 1144*7c478bd9Sstevel@tonic-gate hcp->bucket = __ham_call_hash(hcp, (u_int8_t *)key->data, key->size); 1145*7c478bd9Sstevel@tonic-gate while (1) { 1146*7c478bd9Sstevel@tonic-gate if ((ret = __ham_item_next(dbc, mode)) != 0) 1147*7c478bd9Sstevel@tonic-gate return (ret); 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_NOMORE)) 1150*7c478bd9Sstevel@tonic-gate break; 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate hk = H_PAIRKEY(hcp->pagep, hcp->bndx); 1153*7c478bd9Sstevel@tonic-gate switch (HPAGE_PTYPE(hk)) { 1154*7c478bd9Sstevel@tonic-gate case H_OFFPAGE: 1155*7c478bd9Sstevel@tonic-gate memcpy(&tlen, HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); 1156*7c478bd9Sstevel@tonic-gate if (tlen == key->size) { 1157*7c478bd9Sstevel@tonic-gate memcpy(&pgno, 1158*7c478bd9Sstevel@tonic-gate HOFFPAGE_PGNO(hk), sizeof(db_pgno_t)); 1159*7c478bd9Sstevel@tonic-gate if ((ret = __db_moff(dbp, 1160*7c478bd9Sstevel@tonic-gate key, pgno, tlen, NULL, &match)) != 0) 1161*7c478bd9Sstevel@tonic-gate return (ret); 1162*7c478bd9Sstevel@tonic-gate if (match == 0) { 1163*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_OK); 1164*7c478bd9Sstevel@tonic-gate return (0); 1165*7c478bd9Sstevel@tonic-gate } 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate break; 1168*7c478bd9Sstevel@tonic-gate case H_KEYDATA: 1169*7c478bd9Sstevel@tonic-gate if (key->size == LEN_HKEY(hcp->pagep, 1170*7c478bd9Sstevel@tonic-gate hcp->hdr->pagesize, hcp->bndx) && 1171*7c478bd9Sstevel@tonic-gate memcmp(key->data, 1172*7c478bd9Sstevel@tonic-gate HKEYDATA_DATA(hk), key->size) == 0) { 1173*7c478bd9Sstevel@tonic-gate F_SET(hcp, H_OK); 1174*7c478bd9Sstevel@tonic-gate return (0); 1175*7c478bd9Sstevel@tonic-gate } 1176*7c478bd9Sstevel@tonic-gate break; 1177*7c478bd9Sstevel@tonic-gate case H_DUPLICATE: 1178*7c478bd9Sstevel@tonic-gate case H_OFFDUP: 1179*7c478bd9Sstevel@tonic-gate /* 1180*7c478bd9Sstevel@tonic-gate * These are errors because keys are never 1181*7c478bd9Sstevel@tonic-gate * duplicated, only data items are. 1182*7c478bd9Sstevel@tonic-gate */ 1183*7c478bd9Sstevel@tonic-gate return (__db_pgfmt(dbp, PGNO(hcp->pagep))); 1184*7c478bd9Sstevel@tonic-gate } 1185*7c478bd9Sstevel@tonic-gate hcp->stats.hash_collisions++; 1186*7c478bd9Sstevel@tonic-gate } 1187*7c478bd9Sstevel@tonic-gate 1188*7c478bd9Sstevel@tonic-gate /* 1189*7c478bd9Sstevel@tonic-gate * Item was not found, adjust cursor properly. 1190*7c478bd9Sstevel@tonic-gate */ 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate if (sought != 0) 1193*7c478bd9Sstevel@tonic-gate return (ret); 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate if ((t_ret = __ham_item_done(dbc, 0)) != 0 && ret == 0) 1196*7c478bd9Sstevel@tonic-gate ret = t_ret; 1197*7c478bd9Sstevel@tonic-gate return (ret); 1198*7c478bd9Sstevel@tonic-gate } 1199*7c478bd9Sstevel@tonic-gate 1200*7c478bd9Sstevel@tonic-gate /* 1201*7c478bd9Sstevel@tonic-gate * Initialize a dbt using some possibly already allocated storage 1202*7c478bd9Sstevel@tonic-gate * for items. 1203*7c478bd9Sstevel@tonic-gate * PUBLIC: int __ham_init_dbt __P((DBT *, u_int32_t, void **, u_int32_t *)); 1204*7c478bd9Sstevel@tonic-gate */ 1205*7c478bd9Sstevel@tonic-gate int 1206*7c478bd9Sstevel@tonic-gate __ham_init_dbt(dbt, size, bufp, sizep) 1207*7c478bd9Sstevel@tonic-gate DBT *dbt; 1208*7c478bd9Sstevel@tonic-gate u_int32_t size; 1209*7c478bd9Sstevel@tonic-gate void **bufp; 1210*7c478bd9Sstevel@tonic-gate u_int32_t *sizep; 1211*7c478bd9Sstevel@tonic-gate { 1212*7c478bd9Sstevel@tonic-gate int ret; 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate memset(dbt, 0, sizeof(*dbt)); 1215*7c478bd9Sstevel@tonic-gate if (*sizep < size) { 1216*7c478bd9Sstevel@tonic-gate if ((ret = __os_realloc(bufp, size)) != 0) { 1217*7c478bd9Sstevel@tonic-gate *sizep = 0; 1218*7c478bd9Sstevel@tonic-gate return (ret); 1219*7c478bd9Sstevel@tonic-gate } 1220*7c478bd9Sstevel@tonic-gate *sizep = size; 1221*7c478bd9Sstevel@tonic-gate } 1222*7c478bd9Sstevel@tonic-gate dbt->data = *bufp; 1223*7c478bd9Sstevel@tonic-gate dbt->size = size; 1224*7c478bd9Sstevel@tonic-gate return (0); 1225*7c478bd9Sstevel@tonic-gate } 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate /* 1228*7c478bd9Sstevel@tonic-gate * Adjust the cursor after an insert or delete. The cursor passed is 1229*7c478bd9Sstevel@tonic-gate * the one that was operated upon; we just need to check any of the 1230*7c478bd9Sstevel@tonic-gate * others. 1231*7c478bd9Sstevel@tonic-gate * 1232*7c478bd9Sstevel@tonic-gate * len indicates the length of the item added/deleted 1233*7c478bd9Sstevel@tonic-gate * add indicates if the item indicated by the cursor has just been 1234*7c478bd9Sstevel@tonic-gate * added (add == 1) or deleted (add == 0). 1235*7c478bd9Sstevel@tonic-gate * dup indicates if the addition occurred into a duplicate set. 1236*7c478bd9Sstevel@tonic-gate * 1237*7c478bd9Sstevel@tonic-gate * PUBLIC: void __ham_c_update 1238*7c478bd9Sstevel@tonic-gate * PUBLIC: __P((HASH_CURSOR *, db_pgno_t, u_int32_t, int, int)); 1239*7c478bd9Sstevel@tonic-gate */ 1240*7c478bd9Sstevel@tonic-gate void 1241*7c478bd9Sstevel@tonic-gate __ham_c_update(hcp, chg_pgno, len, add, is_dup) 1242*7c478bd9Sstevel@tonic-gate HASH_CURSOR *hcp; 1243*7c478bd9Sstevel@tonic-gate db_pgno_t chg_pgno; 1244*7c478bd9Sstevel@tonic-gate u_int32_t len; 1245*7c478bd9Sstevel@tonic-gate int add, is_dup; 1246*7c478bd9Sstevel@tonic-gate { 1247*7c478bd9Sstevel@tonic-gate DB *dbp; 1248*7c478bd9Sstevel@tonic-gate DBC *cp; 1249*7c478bd9Sstevel@tonic-gate HASH_CURSOR *lcp; 1250*7c478bd9Sstevel@tonic-gate int page_deleted; 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate /* 1253*7c478bd9Sstevel@tonic-gate * Regular adds are always at the end of a given page, so we never 1254*7c478bd9Sstevel@tonic-gate * have to adjust anyone's cursor after a regular add. 1255*7c478bd9Sstevel@tonic-gate */ 1256*7c478bd9Sstevel@tonic-gate if (!is_dup && add) 1257*7c478bd9Sstevel@tonic-gate return; 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate /* 1260*7c478bd9Sstevel@tonic-gate * Determine if a page was deleted. If this is a regular update 1261*7c478bd9Sstevel@tonic-gate * (i.e., not is_dup) then the deleted page's number will be that in 1262*7c478bd9Sstevel@tonic-gate * chg_pgno, and the pgno in the cursor will be different. If this 1263*7c478bd9Sstevel@tonic-gate * was an onpage-duplicate, then the same conditions apply. If this 1264*7c478bd9Sstevel@tonic-gate * was an off-page duplicate, then we need to verify if hcp->dpgno 1265*7c478bd9Sstevel@tonic-gate * is the same (no delete) or different (delete) than chg_pgno. 1266*7c478bd9Sstevel@tonic-gate */ 1267*7c478bd9Sstevel@tonic-gate if (!is_dup || hcp->dpgno == PGNO_INVALID) 1268*7c478bd9Sstevel@tonic-gate page_deleted = 1269*7c478bd9Sstevel@tonic-gate chg_pgno != PGNO_INVALID && chg_pgno != hcp->pgno; 1270*7c478bd9Sstevel@tonic-gate else 1271*7c478bd9Sstevel@tonic-gate page_deleted = 1272*7c478bd9Sstevel@tonic-gate chg_pgno != PGNO_INVALID && chg_pgno != hcp->dpgno; 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate dbp = hcp->dbc->dbp; 1275*7c478bd9Sstevel@tonic-gate DB_THREAD_LOCK(dbp); 1276*7c478bd9Sstevel@tonic-gate 1277*7c478bd9Sstevel@tonic-gate for (cp = TAILQ_FIRST(&dbp->active_queue); cp != NULL; 1278*7c478bd9Sstevel@tonic-gate cp = TAILQ_NEXT(cp, links)) { 1279*7c478bd9Sstevel@tonic-gate if (cp->internal == hcp) 1280*7c478bd9Sstevel@tonic-gate continue; 1281*7c478bd9Sstevel@tonic-gate 1282*7c478bd9Sstevel@tonic-gate lcp = (HASH_CURSOR *)cp->internal; 1283*7c478bd9Sstevel@tonic-gate 1284*7c478bd9Sstevel@tonic-gate if (!is_dup && lcp->pgno != chg_pgno) 1285*7c478bd9Sstevel@tonic-gate continue; 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate if (is_dup) { 1288*7c478bd9Sstevel@tonic-gate if (F_ISSET(hcp, H_DELETED) && lcp->pgno != chg_pgno) 1289*7c478bd9Sstevel@tonic-gate continue; 1290*7c478bd9Sstevel@tonic-gate if (!F_ISSET(hcp, H_DELETED) && lcp->dpgno != chg_pgno) 1291*7c478bd9Sstevel@tonic-gate continue; 1292*7c478bd9Sstevel@tonic-gate } 1293*7c478bd9Sstevel@tonic-gate 1294*7c478bd9Sstevel@tonic-gate if (page_deleted) { 1295*7c478bd9Sstevel@tonic-gate if (is_dup) { 1296*7c478bd9Sstevel@tonic-gate lcp->dpgno = hcp->dpgno; 1297*7c478bd9Sstevel@tonic-gate lcp->dndx = hcp->dndx; 1298*7c478bd9Sstevel@tonic-gate } else { 1299*7c478bd9Sstevel@tonic-gate lcp->pgno = hcp->pgno; 1300*7c478bd9Sstevel@tonic-gate lcp->bndx = hcp->bndx; 1301*7c478bd9Sstevel@tonic-gate lcp->bucket = hcp->bucket; 1302*7c478bd9Sstevel@tonic-gate } 1303*7c478bd9Sstevel@tonic-gate F_CLR(lcp, H_ISDUP); 1304*7c478bd9Sstevel@tonic-gate continue; 1305*7c478bd9Sstevel@tonic-gate } 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate if (!is_dup && lcp->bndx > hcp->bndx) 1308*7c478bd9Sstevel@tonic-gate lcp->bndx--; 1309*7c478bd9Sstevel@tonic-gate else if (!is_dup && lcp->bndx == hcp->bndx) 1310*7c478bd9Sstevel@tonic-gate F_SET(lcp, H_DELETED); 1311*7c478bd9Sstevel@tonic-gate else if (is_dup && lcp->bndx == hcp->bndx) { 1312*7c478bd9Sstevel@tonic-gate /* Assign dpgno in case there was page conversion. */ 1313*7c478bd9Sstevel@tonic-gate lcp->dpgno = hcp->dpgno; 1314*7c478bd9Sstevel@tonic-gate if (add && lcp->dndx >= hcp->dndx ) 1315*7c478bd9Sstevel@tonic-gate lcp->dndx++; 1316*7c478bd9Sstevel@tonic-gate else if (!add && lcp->dndx > hcp->dndx) 1317*7c478bd9Sstevel@tonic-gate lcp->dndx--; 1318*7c478bd9Sstevel@tonic-gate else if (!add && lcp->dndx == hcp->dndx) 1319*7c478bd9Sstevel@tonic-gate F_SET(lcp, H_DELETED); 1320*7c478bd9Sstevel@tonic-gate 1321*7c478bd9Sstevel@tonic-gate /* Now adjust on-page information. */ 1322*7c478bd9Sstevel@tonic-gate if (lcp->dpgno == PGNO_INVALID) 1323*7c478bd9Sstevel@tonic-gate if (add) { 1324*7c478bd9Sstevel@tonic-gate lcp->dup_tlen += len; 1325*7c478bd9Sstevel@tonic-gate if (lcp->dndx > hcp->dndx) 1326*7c478bd9Sstevel@tonic-gate lcp->dup_off += len; 1327*7c478bd9Sstevel@tonic-gate } else { 1328*7c478bd9Sstevel@tonic-gate lcp->dup_tlen -= len; 1329*7c478bd9Sstevel@tonic-gate if (lcp->dndx > hcp->dndx) 1330*7c478bd9Sstevel@tonic-gate lcp->dup_off -= len; 1331*7c478bd9Sstevel@tonic-gate } 1332*7c478bd9Sstevel@tonic-gate } 1333*7c478bd9Sstevel@tonic-gate } 1334*7c478bd9Sstevel@tonic-gate DB_THREAD_UNLOCK(dbp); 1335*7c478bd9Sstevel@tonic-gate } 1336*7c478bd9Sstevel@tonic-gate 1337