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) 1998 5*7c478bd9Sstevel@tonic-gate * Sleepycat Software. All rights reserved. 6*7c478bd9Sstevel@tonic-gate */ 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 9*7c478bd9Sstevel@tonic-gate 10*7c478bd9Sstevel@tonic-gate #include "config.h" 11*7c478bd9Sstevel@tonic-gate 12*7c478bd9Sstevel@tonic-gate #ifndef lint 13*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)db_am.c 10.15 (Sleepycat) 12/30/98"; 14*7c478bd9Sstevel@tonic-gate #endif /* not lint */ 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES 17*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 18*7c478bd9Sstevel@tonic-gate 19*7c478bd9Sstevel@tonic-gate #include <errno.h> 20*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 21*7c478bd9Sstevel@tonic-gate #include <string.h> 22*7c478bd9Sstevel@tonic-gate #endif 23*7c478bd9Sstevel@tonic-gate 24*7c478bd9Sstevel@tonic-gate #include "db_int.h" 25*7c478bd9Sstevel@tonic-gate #include "shqueue.h" 26*7c478bd9Sstevel@tonic-gate #include "db_page.h" 27*7c478bd9Sstevel@tonic-gate #include "db_shash.h" 28*7c478bd9Sstevel@tonic-gate #include "mp.h" 29*7c478bd9Sstevel@tonic-gate #include "btree.h" 30*7c478bd9Sstevel@tonic-gate #include "hash.h" 31*7c478bd9Sstevel@tonic-gate #include "db_am.h" 32*7c478bd9Sstevel@tonic-gate #include "db_ext.h" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate static int __db_c_close __P((DBC *)); 35*7c478bd9Sstevel@tonic-gate static int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t)); 36*7c478bd9Sstevel@tonic-gate static int __db_fd __P((DB *, int *)); 37*7c478bd9Sstevel@tonic-gate static int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); 38*7c478bd9Sstevel@tonic-gate static int __db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate /* 41*7c478bd9Sstevel@tonic-gate * __db_init_wrapper -- 42*7c478bd9Sstevel@tonic-gate * Wrapper layer to implement generic DB functions. 43*7c478bd9Sstevel@tonic-gate * 44*7c478bd9Sstevel@tonic-gate * PUBLIC: int __db_init_wrapper __P((DB *)); 45*7c478bd9Sstevel@tonic-gate */ 46*7c478bd9Sstevel@tonic-gate int 47*7c478bd9Sstevel@tonic-gate __db_init_wrapper(dbp) 48*7c478bd9Sstevel@tonic-gate DB *dbp; 49*7c478bd9Sstevel@tonic-gate { 50*7c478bd9Sstevel@tonic-gate dbp->close = __db_close; 51*7c478bd9Sstevel@tonic-gate dbp->cursor = __db_cursor; 52*7c478bd9Sstevel@tonic-gate dbp->del = NULL; /* !!! Must be set by access method. */ 53*7c478bd9Sstevel@tonic-gate dbp->fd = __db_fd; 54*7c478bd9Sstevel@tonic-gate dbp->get = __db_get; 55*7c478bd9Sstevel@tonic-gate dbp->join = __db_join; 56*7c478bd9Sstevel@tonic-gate dbp->put = __db_put; 57*7c478bd9Sstevel@tonic-gate dbp->stat = NULL; /* !!! Must be set by access method. */ 58*7c478bd9Sstevel@tonic-gate dbp->sync = __db_sync; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate return (0); 61*7c478bd9Sstevel@tonic-gate } 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* 64*7c478bd9Sstevel@tonic-gate * __db_cursor -- 65*7c478bd9Sstevel@tonic-gate * Allocate and return a cursor. 66*7c478bd9Sstevel@tonic-gate */ 67*7c478bd9Sstevel@tonic-gate static int 68*7c478bd9Sstevel@tonic-gate __db_cursor(dbp, txn, dbcp, flags) 69*7c478bd9Sstevel@tonic-gate DB *dbp; 70*7c478bd9Sstevel@tonic-gate DB_TXN *txn; 71*7c478bd9Sstevel@tonic-gate DBC **dbcp; 72*7c478bd9Sstevel@tonic-gate u_int32_t flags; 73*7c478bd9Sstevel@tonic-gate { 74*7c478bd9Sstevel@tonic-gate DBC *dbc, *adbc; 75*7c478bd9Sstevel@tonic-gate int ret; 76*7c478bd9Sstevel@tonic-gate db_lockmode_t mode; 77*7c478bd9Sstevel@tonic-gate u_int32_t op; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* Take one from the free list if it's available. */ 82*7c478bd9Sstevel@tonic-gate DB_THREAD_LOCK(dbp); 83*7c478bd9Sstevel@tonic-gate if ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL) 84*7c478bd9Sstevel@tonic-gate TAILQ_REMOVE(&dbp->free_queue, dbc, links); 85*7c478bd9Sstevel@tonic-gate else { 86*7c478bd9Sstevel@tonic-gate DB_THREAD_UNLOCK(dbp); 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate if ((ret = __os_calloc(1, sizeof(DBC), &dbc)) != 0) 89*7c478bd9Sstevel@tonic-gate return (ret); 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate dbc->dbp = dbp; 92*7c478bd9Sstevel@tonic-gate dbc->c_close = __db_c_close; 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate /* Set up locking information. */ 95*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_LOCKING | DB_AM_CDB)) { 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * If we are not threaded, then there is no need to 98*7c478bd9Sstevel@tonic-gate * create new locker ids. We know that no one else 99*7c478bd9Sstevel@tonic-gate * is running concurrently using this DB, so we can 100*7c478bd9Sstevel@tonic-gate * take a peek at any cursors on the active queue. 101*7c478bd9Sstevel@tonic-gate */ 102*7c478bd9Sstevel@tonic-gate if (!F_ISSET(dbp, DB_AM_THREAD) && 103*7c478bd9Sstevel@tonic-gate (adbc = TAILQ_FIRST(&dbp->active_queue)) != NULL) 104*7c478bd9Sstevel@tonic-gate dbc->lid = adbc->lid; 105*7c478bd9Sstevel@tonic-gate else 106*7c478bd9Sstevel@tonic-gate if ((ret = lock_id(dbp->dbenv->lk_info, 107*7c478bd9Sstevel@tonic-gate &dbc->lid)) != 0) 108*7c478bd9Sstevel@tonic-gate goto err; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate memcpy(dbc->lock.fileid, dbp->fileid, DB_FILE_ID_LEN); 111*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_CDB)) { 112*7c478bd9Sstevel@tonic-gate dbc->lock_dbt.size = DB_FILE_ID_LEN; 113*7c478bd9Sstevel@tonic-gate dbc->lock_dbt.data = dbc->lock.fileid; 114*7c478bd9Sstevel@tonic-gate } else { 115*7c478bd9Sstevel@tonic-gate dbc->lock_dbt.size = sizeof(dbc->lock); 116*7c478bd9Sstevel@tonic-gate dbc->lock_dbt.data = &dbc->lock; 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate switch (dbp->type) { 121*7c478bd9Sstevel@tonic-gate case DB_BTREE: 122*7c478bd9Sstevel@tonic-gate case DB_RECNO: 123*7c478bd9Sstevel@tonic-gate if ((ret = __bam_c_init(dbc)) != 0) 124*7c478bd9Sstevel@tonic-gate goto err; 125*7c478bd9Sstevel@tonic-gate break; 126*7c478bd9Sstevel@tonic-gate case DB_HASH: 127*7c478bd9Sstevel@tonic-gate if ((ret = __ham_c_init(dbc)) != 0) 128*7c478bd9Sstevel@tonic-gate goto err; 129*7c478bd9Sstevel@tonic-gate break; 130*7c478bd9Sstevel@tonic-gate default: 131*7c478bd9Sstevel@tonic-gate ret = EINVAL; 132*7c478bd9Sstevel@tonic-gate goto err; 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate DB_THREAD_LOCK(dbp); 136*7c478bd9Sstevel@tonic-gate } 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate if ((dbc->txn = txn) == NULL) 139*7c478bd9Sstevel@tonic-gate dbc->locker = dbc->lid; 140*7c478bd9Sstevel@tonic-gate else 141*7c478bd9Sstevel@tonic-gate dbc->locker = txn->txnid; 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links); 144*7c478bd9Sstevel@tonic-gate DB_THREAD_UNLOCK(dbp); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* 147*7c478bd9Sstevel@tonic-gate * If this is the concurrent DB product, then we do all locking 148*7c478bd9Sstevel@tonic-gate * in the interface, which is right here. 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_CDB)) { 151*7c478bd9Sstevel@tonic-gate op = LF_ISSET(DB_OPFLAGS_MASK); 152*7c478bd9Sstevel@tonic-gate mode = (op == DB_WRITELOCK) ? DB_LOCK_WRITE : 153*7c478bd9Sstevel@tonic-gate (LF_ISSET(DB_RMW) ? DB_LOCK_IWRITE : DB_LOCK_READ); 154*7c478bd9Sstevel@tonic-gate if ((ret = lock_get(dbp->dbenv->lk_info, dbc->locker, 0, 155*7c478bd9Sstevel@tonic-gate &dbc->lock_dbt, mode, &dbc->mylock)) != 0) { 156*7c478bd9Sstevel@tonic-gate (void)__db_c_close(dbc); 157*7c478bd9Sstevel@tonic-gate return (EAGAIN); 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate if (LF_ISSET(DB_RMW)) 160*7c478bd9Sstevel@tonic-gate F_SET(dbc, DBC_RMW); 161*7c478bd9Sstevel@tonic-gate if (op == DB_WRITELOCK) 162*7c478bd9Sstevel@tonic-gate F_SET(dbc, DBC_WRITER); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate *dbcp = dbc; 166*7c478bd9Sstevel@tonic-gate return (0); 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate err: __os_free(dbc, sizeof(*dbc)); 169*7c478bd9Sstevel@tonic-gate return (ret); 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * __db_c_close -- 174*7c478bd9Sstevel@tonic-gate * Close the cursor (recycle for later use). 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate static int 177*7c478bd9Sstevel@tonic-gate __db_c_close(dbc) 178*7c478bd9Sstevel@tonic-gate DBC *dbc; 179*7c478bd9Sstevel@tonic-gate { 180*7c478bd9Sstevel@tonic-gate DB *dbp; 181*7c478bd9Sstevel@tonic-gate int ret, t_ret; 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate ret = 0; 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate /* 190*7c478bd9Sstevel@tonic-gate * We cannot release the lock until after we've called the 191*7c478bd9Sstevel@tonic-gate * access method specific routine, since btrees may have pending 192*7c478bd9Sstevel@tonic-gate * deletes. 193*7c478bd9Sstevel@tonic-gate */ 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* Remove the cursor from the active queue. */ 196*7c478bd9Sstevel@tonic-gate DB_THREAD_LOCK(dbp); 197*7c478bd9Sstevel@tonic-gate TAILQ_REMOVE(&dbp->active_queue, dbc, links); 198*7c478bd9Sstevel@tonic-gate DB_THREAD_UNLOCK(dbp); 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate /* Call the access specific cursor close routine. */ 201*7c478bd9Sstevel@tonic-gate if ((t_ret = dbc->c_am_close(dbc)) != 0 && ret == 0) 202*7c478bd9Sstevel@tonic-gate t_ret = ret; 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate /* Release the lock. */ 205*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbc->dbp, DB_AM_CDB) && dbc->mylock != LOCK_INVALID) { 206*7c478bd9Sstevel@tonic-gate ret = lock_put(dbc->dbp->dbenv->lk_info, dbc->mylock); 207*7c478bd9Sstevel@tonic-gate dbc->mylock = LOCK_INVALID; 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate /* Clean up the cursor. */ 211*7c478bd9Sstevel@tonic-gate dbc->flags = 0; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 214*7c478bd9Sstevel@tonic-gate /* 215*7c478bd9Sstevel@tonic-gate * Check for leftover locks, unless we're running with transactions. 216*7c478bd9Sstevel@tonic-gate * 217*7c478bd9Sstevel@tonic-gate * If we're running tests, display any locks currently held. It's 218*7c478bd9Sstevel@tonic-gate * possible that some applications may hold locks for long periods, 219*7c478bd9Sstevel@tonic-gate * e.g., conference room locks, but the DB tests should never close 220*7c478bd9Sstevel@tonic-gate * holding locks. 221*7c478bd9Sstevel@tonic-gate */ 222*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_LOCKING) && dbc->lid == dbc->locker) { 223*7c478bd9Sstevel@tonic-gate DB_LOCKREQ request; 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate request.op = DB_LOCK_DUMP; 226*7c478bd9Sstevel@tonic-gate if ((t_ret = lock_vec(dbp->dbenv->lk_info, 227*7c478bd9Sstevel@tonic-gate dbc->locker, 0, &request, 1, NULL)) != 0 && ret == 0) 228*7c478bd9Sstevel@tonic-gate ret = EAGAIN; 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate #endif 231*7c478bd9Sstevel@tonic-gate /* Move the cursor to the free queue. */ 232*7c478bd9Sstevel@tonic-gate DB_THREAD_LOCK(dbp); 233*7c478bd9Sstevel@tonic-gate TAILQ_INSERT_TAIL(&dbp->free_queue, dbc, links); 234*7c478bd9Sstevel@tonic-gate DB_THREAD_UNLOCK(dbp); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate return (ret); 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 240*7c478bd9Sstevel@tonic-gate /* 241*7c478bd9Sstevel@tonic-gate * __db_cprint -- 242*7c478bd9Sstevel@tonic-gate * Display the current cursor list. 243*7c478bd9Sstevel@tonic-gate * 244*7c478bd9Sstevel@tonic-gate * PUBLIC: int __db_cprint __P((DB *)); 245*7c478bd9Sstevel@tonic-gate */ 246*7c478bd9Sstevel@tonic-gate int 247*7c478bd9Sstevel@tonic-gate __db_cprint(dbp) 248*7c478bd9Sstevel@tonic-gate DB *dbp; 249*7c478bd9Sstevel@tonic-gate { 250*7c478bd9Sstevel@tonic-gate static const FN fn[] = { 251*7c478bd9Sstevel@tonic-gate { DBC_RECOVER, "recover" }, 252*7c478bd9Sstevel@tonic-gate { DBC_RMW, "read-modify-write" }, 253*7c478bd9Sstevel@tonic-gate { 0 }, 254*7c478bd9Sstevel@tonic-gate }; 255*7c478bd9Sstevel@tonic-gate DBC *dbc; 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate DB_THREAD_LOCK(dbp); 258*7c478bd9Sstevel@tonic-gate for (dbc = TAILQ_FIRST(&dbp->active_queue); 259*7c478bd9Sstevel@tonic-gate dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { 260*7c478bd9Sstevel@tonic-gate fprintf(stderr, 261*7c478bd9Sstevel@tonic-gate "%#0x: dbp: %#0x txn: %#0x lid: %lu locker: %lu", 262*7c478bd9Sstevel@tonic-gate (u_int)dbc, (u_int)dbc->dbp, (u_int)dbc->txn, 263*7c478bd9Sstevel@tonic-gate (u_long)dbc->lid, (u_long)dbc->locker); 264*7c478bd9Sstevel@tonic-gate __db_prflags(dbc->flags, fn, stderr); 265*7c478bd9Sstevel@tonic-gate fprintf(stderr, "\n"); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate DB_THREAD_UNLOCK(dbp); 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate return (0); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate /* 274*7c478bd9Sstevel@tonic-gate * __db_c_destroy -- 275*7c478bd9Sstevel@tonic-gate * Destroy the cursor. 276*7c478bd9Sstevel@tonic-gate * 277*7c478bd9Sstevel@tonic-gate * PUBLIC: int __db_c_destroy __P((DBC *)); 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate int 280*7c478bd9Sstevel@tonic-gate __db_c_destroy(dbc) 281*7c478bd9Sstevel@tonic-gate DBC *dbc; 282*7c478bd9Sstevel@tonic-gate { 283*7c478bd9Sstevel@tonic-gate DB *dbp; 284*7c478bd9Sstevel@tonic-gate int ret; 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate dbp = dbc->dbp; 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate /* Remove the cursor from the free queue. */ 289*7c478bd9Sstevel@tonic-gate DB_THREAD_LOCK(dbp); 290*7c478bd9Sstevel@tonic-gate TAILQ_REMOVE(&dbp->free_queue, dbc, links); 291*7c478bd9Sstevel@tonic-gate DB_THREAD_UNLOCK(dbp); 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate /* Call the access specific cursor destroy routine. */ 294*7c478bd9Sstevel@tonic-gate ret = dbc->c_am_destroy == NULL ? 0 : dbc->c_am_destroy(dbc); 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate /* Free up allocated memory. */ 297*7c478bd9Sstevel@tonic-gate if (dbc->rkey.data != NULL) 298*7c478bd9Sstevel@tonic-gate __os_free(dbc->rkey.data, dbc->rkey.ulen); 299*7c478bd9Sstevel@tonic-gate if (dbc->rdata.data != NULL) 300*7c478bd9Sstevel@tonic-gate __os_free(dbc->rdata.data, dbc->rdata.ulen); 301*7c478bd9Sstevel@tonic-gate __os_free(dbc, sizeof(*dbc)); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate return (0); 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * db_fd -- 308*7c478bd9Sstevel@tonic-gate * Return a file descriptor for flock'ing. 309*7c478bd9Sstevel@tonic-gate */ 310*7c478bd9Sstevel@tonic-gate static int 311*7c478bd9Sstevel@tonic-gate __db_fd(dbp, fdp) 312*7c478bd9Sstevel@tonic-gate DB *dbp; 313*7c478bd9Sstevel@tonic-gate int *fdp; 314*7c478bd9Sstevel@tonic-gate { 315*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate /* 318*7c478bd9Sstevel@tonic-gate * XXX 319*7c478bd9Sstevel@tonic-gate * Truly spectacular layering violation. 320*7c478bd9Sstevel@tonic-gate */ 321*7c478bd9Sstevel@tonic-gate return (__mp_xxx_fd(dbp->mpf, fdp)); 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate /* 325*7c478bd9Sstevel@tonic-gate * __db_get -- 326*7c478bd9Sstevel@tonic-gate * Return a key/data pair. 327*7c478bd9Sstevel@tonic-gate */ 328*7c478bd9Sstevel@tonic-gate static int 329*7c478bd9Sstevel@tonic-gate __db_get(dbp, txn, key, data, flags) 330*7c478bd9Sstevel@tonic-gate DB *dbp; 331*7c478bd9Sstevel@tonic-gate DB_TXN *txn; 332*7c478bd9Sstevel@tonic-gate DBT *key, *data; 333*7c478bd9Sstevel@tonic-gate u_int32_t flags; 334*7c478bd9Sstevel@tonic-gate { 335*7c478bd9Sstevel@tonic-gate DBC *dbc; 336*7c478bd9Sstevel@tonic-gate int ret, t_ret; 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate if ((ret = __db_getchk(dbp, key, data, flags)) != 0) 341*7c478bd9Sstevel@tonic-gate return (ret); 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0) 344*7c478bd9Sstevel@tonic-gate return (ret); 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate DEBUG_LREAD(dbc, txn, "__db_get", key, NULL, flags); 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate ret = dbc->c_get(dbc, key, data, 349*7c478bd9Sstevel@tonic-gate flags == 0 || flags == DB_RMW ? flags | DB_SET : flags); 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0) 352*7c478bd9Sstevel@tonic-gate ret = t_ret; 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate return (ret); 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate /* 358*7c478bd9Sstevel@tonic-gate * __db_put -- 359*7c478bd9Sstevel@tonic-gate * Store a key/data pair. 360*7c478bd9Sstevel@tonic-gate */ 361*7c478bd9Sstevel@tonic-gate static int 362*7c478bd9Sstevel@tonic-gate __db_put(dbp, txn, key, data, flags) 363*7c478bd9Sstevel@tonic-gate DB *dbp; 364*7c478bd9Sstevel@tonic-gate DB_TXN *txn; 365*7c478bd9Sstevel@tonic-gate DBT *key, *data; 366*7c478bd9Sstevel@tonic-gate u_int32_t flags; 367*7c478bd9Sstevel@tonic-gate { 368*7c478bd9Sstevel@tonic-gate DBC *dbc; 369*7c478bd9Sstevel@tonic-gate DBT tdata; 370*7c478bd9Sstevel@tonic-gate int ret, t_ret; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate if ((ret = __db_putchk(dbp, key, data, 375*7c478bd9Sstevel@tonic-gate flags, F_ISSET(dbp, DB_AM_RDONLY), F_ISSET(dbp, DB_AM_DUP))) != 0) 376*7c478bd9Sstevel@tonic-gate return (ret); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) 379*7c478bd9Sstevel@tonic-gate return (ret); 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate DEBUG_LWRITE(dbc, txn, "__db_put", key, data, flags); 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate if (flags == DB_NOOVERWRITE) { 384*7c478bd9Sstevel@tonic-gate /* 385*7c478bd9Sstevel@tonic-gate * Set DB_DBT_USERMEM, this might be a threaded application and 386*7c478bd9Sstevel@tonic-gate * the flags checking will catch us. We don't want the actual 387*7c478bd9Sstevel@tonic-gate * data, so request a partial of length 0. 388*7c478bd9Sstevel@tonic-gate */ 389*7c478bd9Sstevel@tonic-gate memset(&tdata, 0, sizeof(tdata)); 390*7c478bd9Sstevel@tonic-gate F_SET(&tdata, DB_DBT_USERMEM | DB_DBT_PARTIAL); 391*7c478bd9Sstevel@tonic-gate if ((ret = dbc->c_get(dbc, key, &tdata, DB_SET | DB_RMW)) == 0) 392*7c478bd9Sstevel@tonic-gate ret = DB_KEYEXIST; 393*7c478bd9Sstevel@tonic-gate else if (ret == DB_NOTFOUND) 394*7c478bd9Sstevel@tonic-gate ret = 0; 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate if (ret == 0) 397*7c478bd9Sstevel@tonic-gate ret = dbc->c_put(dbc, key, data, DB_KEYLAST); 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0) 400*7c478bd9Sstevel@tonic-gate ret = t_ret; 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate return (ret); 403*7c478bd9Sstevel@tonic-gate } 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate /* 406*7c478bd9Sstevel@tonic-gate * __db_sync -- 407*7c478bd9Sstevel@tonic-gate * Flush the database cache. 408*7c478bd9Sstevel@tonic-gate * 409*7c478bd9Sstevel@tonic-gate * PUBLIC: int __db_sync __P((DB *, u_int32_t)); 410*7c478bd9Sstevel@tonic-gate */ 411*7c478bd9Sstevel@tonic-gate int 412*7c478bd9Sstevel@tonic-gate __db_sync(dbp, flags) 413*7c478bd9Sstevel@tonic-gate DB *dbp; 414*7c478bd9Sstevel@tonic-gate u_int32_t flags; 415*7c478bd9Sstevel@tonic-gate { 416*7c478bd9Sstevel@tonic-gate int ret; 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate if ((ret = __db_syncchk(dbp, flags)) != 0) 421*7c478bd9Sstevel@tonic-gate return (ret); 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate /* If it wasn't possible to modify the file, we're done. */ 424*7c478bd9Sstevel@tonic-gate if (F_ISSET(dbp, DB_AM_INMEM | DB_AM_RDONLY)) 425*7c478bd9Sstevel@tonic-gate return (0); 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* Flush any dirty pages from the cache to the backing file. */ 428*7c478bd9Sstevel@tonic-gate if ((ret = memp_fsync(dbp->mpf)) == DB_INCOMPLETE) 429*7c478bd9Sstevel@tonic-gate ret = 0; 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate return (ret); 432*7c478bd9Sstevel@tonic-gate } 433