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 #include "config.h" 8*7c478bd9Sstevel@tonic-gate 9*7c478bd9Sstevel@tonic-gate #ifndef lint 10*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)mp_region.c 10.35 (Sleepycat) 12/11/98"; 11*7c478bd9Sstevel@tonic-gate #endif /* not lint */ 12*7c478bd9Sstevel@tonic-gate 13*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES 14*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #include <errno.h> 17*7c478bd9Sstevel@tonic-gate #include <string.h> 18*7c478bd9Sstevel@tonic-gate #endif 19*7c478bd9Sstevel@tonic-gate 20*7c478bd9Sstevel@tonic-gate #include "db_int.h" 21*7c478bd9Sstevel@tonic-gate #include "shqueue.h" 22*7c478bd9Sstevel@tonic-gate #include "db_shash.h" 23*7c478bd9Sstevel@tonic-gate #include "mp.h" 24*7c478bd9Sstevel@tonic-gate #include "common_ext.h" 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate * __memp_reg_alloc -- 28*7c478bd9Sstevel@tonic-gate * Allocate some space in the mpool region, with locking. 29*7c478bd9Sstevel@tonic-gate * 30*7c478bd9Sstevel@tonic-gate * PUBLIC: int __memp_reg_alloc __P((DB_MPOOL *, size_t, size_t *, void *)); 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate int 33*7c478bd9Sstevel@tonic-gate __memp_reg_alloc(dbmp, len, offsetp, retp) 34*7c478bd9Sstevel@tonic-gate DB_MPOOL *dbmp; 35*7c478bd9Sstevel@tonic-gate size_t len, *offsetp; 36*7c478bd9Sstevel@tonic-gate void *retp; 37*7c478bd9Sstevel@tonic-gate { 38*7c478bd9Sstevel@tonic-gate int ret; 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate LOCKREGION(dbmp); 41*7c478bd9Sstevel@tonic-gate ret = __memp_alloc(dbmp, len, offsetp, retp); 42*7c478bd9Sstevel@tonic-gate UNLOCKREGION(dbmp); 43*7c478bd9Sstevel@tonic-gate return (ret); 44*7c478bd9Sstevel@tonic-gate } 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate /* 47*7c478bd9Sstevel@tonic-gate * __memp_alloc -- 48*7c478bd9Sstevel@tonic-gate * Allocate some space in the mpool region. 49*7c478bd9Sstevel@tonic-gate * 50*7c478bd9Sstevel@tonic-gate * PUBLIC: int __memp_alloc __P((DB_MPOOL *, size_t, size_t *, void *)); 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate int 53*7c478bd9Sstevel@tonic-gate __memp_alloc(dbmp, len, offsetp, retp) 54*7c478bd9Sstevel@tonic-gate DB_MPOOL *dbmp; 55*7c478bd9Sstevel@tonic-gate size_t len, *offsetp; 56*7c478bd9Sstevel@tonic-gate void *retp; 57*7c478bd9Sstevel@tonic-gate { 58*7c478bd9Sstevel@tonic-gate BH *bhp, *nbhp; 59*7c478bd9Sstevel@tonic-gate MPOOL *mp; 60*7c478bd9Sstevel@tonic-gate MPOOLFILE *mfp; 61*7c478bd9Sstevel@tonic-gate size_t fsize, total; 62*7c478bd9Sstevel@tonic-gate int nomore, restart, ret, wrote; 63*7c478bd9Sstevel@tonic-gate void *p; 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate mp = dbmp->mp; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate nomore = 0; 68*7c478bd9Sstevel@tonic-gate alloc: if ((ret = __db_shalloc(dbmp->addr, len, MUTEX_ALIGNMENT, &p)) == 0) { 69*7c478bd9Sstevel@tonic-gate if (offsetp != NULL) 70*7c478bd9Sstevel@tonic-gate *offsetp = R_OFFSET(dbmp, p); 71*7c478bd9Sstevel@tonic-gate *(void **)retp = p; 72*7c478bd9Sstevel@tonic-gate return (0); 73*7c478bd9Sstevel@tonic-gate } 74*7c478bd9Sstevel@tonic-gate if (nomore) { 75*7c478bd9Sstevel@tonic-gate __db_err(dbmp->dbenv, 76*7c478bd9Sstevel@tonic-gate "Unable to allocate %lu bytes from mpool shared region: %s\n", 77*7c478bd9Sstevel@tonic-gate (u_long)len, strerror(ret)); 78*7c478bd9Sstevel@tonic-gate return (ret); 79*7c478bd9Sstevel@tonic-gate } 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* Look for a buffer on the free list that's the right size. */ 82*7c478bd9Sstevel@tonic-gate for (bhp = 83*7c478bd9Sstevel@tonic-gate SH_TAILQ_FIRST(&mp->bhfq, __bh); bhp != NULL; bhp = nbhp) { 84*7c478bd9Sstevel@tonic-gate nbhp = SH_TAILQ_NEXT(bhp, q, __bh); 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate if (__db_shsizeof(bhp) == len) { 87*7c478bd9Sstevel@tonic-gate SH_TAILQ_REMOVE(&mp->bhfq, bhp, q, __bh); 88*7c478bd9Sstevel@tonic-gate if (offsetp != NULL) 89*7c478bd9Sstevel@tonic-gate *offsetp = R_OFFSET(dbmp, bhp); 90*7c478bd9Sstevel@tonic-gate *(void **)retp = bhp; 91*7c478bd9Sstevel@tonic-gate return (0); 92*7c478bd9Sstevel@tonic-gate } 93*7c478bd9Sstevel@tonic-gate } 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* Discard from the free list until we've freed enough memory. */ 96*7c478bd9Sstevel@tonic-gate total = 0; 97*7c478bd9Sstevel@tonic-gate for (bhp = 98*7c478bd9Sstevel@tonic-gate SH_TAILQ_FIRST(&mp->bhfq, __bh); bhp != NULL; bhp = nbhp) { 99*7c478bd9Sstevel@tonic-gate nbhp = SH_TAILQ_NEXT(bhp, q, __bh); 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate SH_TAILQ_REMOVE(&mp->bhfq, bhp, q, __bh); 102*7c478bd9Sstevel@tonic-gate __db_shalloc_free(dbmp->addr, bhp); 103*7c478bd9Sstevel@tonic-gate --mp->stat.st_page_clean; 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate /* 106*7c478bd9Sstevel@tonic-gate * Retry as soon as we've freed up sufficient space. If we 107*7c478bd9Sstevel@tonic-gate * will have to coalesce memory to satisfy the request, don't 108*7c478bd9Sstevel@tonic-gate * try until it's likely (possible?) that we'll succeed. 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate total += fsize = __db_shsizeof(bhp); 111*7c478bd9Sstevel@tonic-gate if (fsize >= len || total >= 3 * len) 112*7c478bd9Sstevel@tonic-gate goto alloc; 113*7c478bd9Sstevel@tonic-gate } 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate retry: /* Find a buffer we can flush; pure LRU. */ 116*7c478bd9Sstevel@tonic-gate restart = total = 0; 117*7c478bd9Sstevel@tonic-gate for (bhp = 118*7c478bd9Sstevel@tonic-gate SH_TAILQ_FIRST(&mp->bhq, __bh); bhp != NULL; bhp = nbhp) { 119*7c478bd9Sstevel@tonic-gate nbhp = SH_TAILQ_NEXT(bhp, q, __bh); 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate /* Ignore pinned or locked (I/O in progress) buffers. */ 122*7c478bd9Sstevel@tonic-gate if (bhp->ref != 0 || F_ISSET(bhp, BH_LOCKED)) 123*7c478bd9Sstevel@tonic-gate continue; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* Find the associated MPOOLFILE. */ 126*7c478bd9Sstevel@tonic-gate mfp = R_ADDR(dbmp, bhp->mf_offset); 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate /* 129*7c478bd9Sstevel@tonic-gate * Write the page if it's dirty. 130*7c478bd9Sstevel@tonic-gate * 131*7c478bd9Sstevel@tonic-gate * If we wrote the page, fall through and free the buffer. We 132*7c478bd9Sstevel@tonic-gate * don't have to rewalk the list to acquire the buffer because 133*7c478bd9Sstevel@tonic-gate * it was never available for any other process to modify it. 134*7c478bd9Sstevel@tonic-gate * If we didn't write the page, but we discarded and reacquired 135*7c478bd9Sstevel@tonic-gate * the region lock, restart the buffer list walk. If we neither 136*7c478bd9Sstevel@tonic-gate * wrote the buffer nor discarded the region lock, continue down 137*7c478bd9Sstevel@tonic-gate * the buffer list. 138*7c478bd9Sstevel@tonic-gate */ 139*7c478bd9Sstevel@tonic-gate if (F_ISSET(bhp, BH_DIRTY)) { 140*7c478bd9Sstevel@tonic-gate ++bhp->ref; 141*7c478bd9Sstevel@tonic-gate if ((ret = __memp_bhwrite(dbmp, 142*7c478bd9Sstevel@tonic-gate mfp, bhp, &restart, &wrote)) != 0) 143*7c478bd9Sstevel@tonic-gate return (ret); 144*7c478bd9Sstevel@tonic-gate --bhp->ref; 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* 147*7c478bd9Sstevel@tonic-gate * It's possible that another process wants this buffer 148*7c478bd9Sstevel@tonic-gate * and incremented the ref count while we were writing 149*7c478bd9Sstevel@tonic-gate * it. 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate if (bhp->ref != 0) 152*7c478bd9Sstevel@tonic-gate goto retry; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate if (wrote) 155*7c478bd9Sstevel@tonic-gate ++mp->stat.st_rw_evict; 156*7c478bd9Sstevel@tonic-gate else { 157*7c478bd9Sstevel@tonic-gate if (restart) 158*7c478bd9Sstevel@tonic-gate goto retry; 159*7c478bd9Sstevel@tonic-gate continue; 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate } else 162*7c478bd9Sstevel@tonic-gate ++mp->stat.st_ro_evict; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate /* 165*7c478bd9Sstevel@tonic-gate * Check to see if the buffer is the size we're looking for. 166*7c478bd9Sstevel@tonic-gate * If it is, simply reuse it. 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate total += fsize = __db_shsizeof(bhp); 169*7c478bd9Sstevel@tonic-gate if (fsize == len) { 170*7c478bd9Sstevel@tonic-gate __memp_bhfree(dbmp, mfp, bhp, 0); 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate if (offsetp != NULL) 173*7c478bd9Sstevel@tonic-gate *offsetp = R_OFFSET(dbmp, bhp); 174*7c478bd9Sstevel@tonic-gate *(void **)retp = bhp; 175*7c478bd9Sstevel@tonic-gate return (0); 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /* Free the buffer. */ 179*7c478bd9Sstevel@tonic-gate __memp_bhfree(dbmp, mfp, bhp, 1); 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate /* 182*7c478bd9Sstevel@tonic-gate * Retry as soon as we've freed up sufficient space. If we 183*7c478bd9Sstevel@tonic-gate * have to coalesce of memory to satisfy the request, don't 184*7c478bd9Sstevel@tonic-gate * try until it's likely (possible?) that we'll succeed. 185*7c478bd9Sstevel@tonic-gate */ 186*7c478bd9Sstevel@tonic-gate if (fsize >= len || total >= 3 * len) 187*7c478bd9Sstevel@tonic-gate goto alloc; 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate /* Restart the walk if we discarded the region lock. */ 190*7c478bd9Sstevel@tonic-gate if (restart) 191*7c478bd9Sstevel@tonic-gate goto retry; 192*7c478bd9Sstevel@tonic-gate } 193*7c478bd9Sstevel@tonic-gate nomore = 1; 194*7c478bd9Sstevel@tonic-gate goto alloc; 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /* 198*7c478bd9Sstevel@tonic-gate * __memp_ropen -- 199*7c478bd9Sstevel@tonic-gate * Attach to, and optionally create, the mpool region. 200*7c478bd9Sstevel@tonic-gate * 201*7c478bd9Sstevel@tonic-gate * PUBLIC: int __memp_ropen 202*7c478bd9Sstevel@tonic-gate * PUBLIC: __P((DB_MPOOL *, const char *, size_t, int, int, u_int32_t)); 203*7c478bd9Sstevel@tonic-gate */ 204*7c478bd9Sstevel@tonic-gate int 205*7c478bd9Sstevel@tonic-gate __memp_ropen(dbmp, path, cachesize, mode, is_private, flags) 206*7c478bd9Sstevel@tonic-gate DB_MPOOL *dbmp; 207*7c478bd9Sstevel@tonic-gate const char *path; 208*7c478bd9Sstevel@tonic-gate size_t cachesize; 209*7c478bd9Sstevel@tonic-gate int mode, is_private; 210*7c478bd9Sstevel@tonic-gate u_int32_t flags; 211*7c478bd9Sstevel@tonic-gate { 212*7c478bd9Sstevel@tonic-gate MPOOL *mp; 213*7c478bd9Sstevel@tonic-gate size_t rlen; 214*7c478bd9Sstevel@tonic-gate int defcache, ret; 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * Unlike other DB subsystems, mpool can't simply grow the region 218*7c478bd9Sstevel@tonic-gate * because it returns pointers into the region to its clients. To 219*7c478bd9Sstevel@tonic-gate * "grow" the region, we'd have to allocate a new region and then 220*7c478bd9Sstevel@tonic-gate * store a region number in the structures that reference regional 221*7c478bd9Sstevel@tonic-gate * objects. It's reasonable that we fail regardless, as clients 222*7c478bd9Sstevel@tonic-gate * shouldn't have every page in the region pinned, so the only 223*7c478bd9Sstevel@tonic-gate * "failure" mode should be a performance penalty because we don't 224*7c478bd9Sstevel@tonic-gate * find a page in the cache that we'd like to have found. 225*7c478bd9Sstevel@tonic-gate * 226*7c478bd9Sstevel@tonic-gate * Up the user's cachesize by 25% to account for our overhead. 227*7c478bd9Sstevel@tonic-gate */ 228*7c478bd9Sstevel@tonic-gate defcache = 0; 229*7c478bd9Sstevel@tonic-gate if (cachesize < DB_CACHESIZE_MIN) 230*7c478bd9Sstevel@tonic-gate if (cachesize == 0) { 231*7c478bd9Sstevel@tonic-gate defcache = 1; 232*7c478bd9Sstevel@tonic-gate cachesize = DB_CACHESIZE_DEF; 233*7c478bd9Sstevel@tonic-gate } else 234*7c478bd9Sstevel@tonic-gate cachesize = DB_CACHESIZE_MIN; 235*7c478bd9Sstevel@tonic-gate rlen = cachesize + cachesize / 4; 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * Map in the region. 239*7c478bd9Sstevel@tonic-gate * 240*7c478bd9Sstevel@tonic-gate * If it's a private mpool, use malloc, it's a lot faster than 241*7c478bd9Sstevel@tonic-gate * instantiating a region. 242*7c478bd9Sstevel@tonic-gate */ 243*7c478bd9Sstevel@tonic-gate dbmp->reginfo.dbenv = dbmp->dbenv; 244*7c478bd9Sstevel@tonic-gate dbmp->reginfo.appname = DB_APP_NONE; 245*7c478bd9Sstevel@tonic-gate if (path == NULL) 246*7c478bd9Sstevel@tonic-gate dbmp->reginfo.path = NULL; 247*7c478bd9Sstevel@tonic-gate else 248*7c478bd9Sstevel@tonic-gate if ((ret = __os_strdup(path, &dbmp->reginfo.path)) != 0) 249*7c478bd9Sstevel@tonic-gate return (ret); 250*7c478bd9Sstevel@tonic-gate dbmp->reginfo.file = DB_DEFAULT_MPOOL_FILE; 251*7c478bd9Sstevel@tonic-gate dbmp->reginfo.mode = mode; 252*7c478bd9Sstevel@tonic-gate dbmp->reginfo.size = rlen; 253*7c478bd9Sstevel@tonic-gate dbmp->reginfo.dbflags = flags; 254*7c478bd9Sstevel@tonic-gate dbmp->reginfo.flags = 0; 255*7c478bd9Sstevel@tonic-gate if (defcache) 256*7c478bd9Sstevel@tonic-gate F_SET(&dbmp->reginfo, REGION_SIZEDEF); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* 259*7c478bd9Sstevel@tonic-gate * If we're creating a temporary region, don't use any standard 260*7c478bd9Sstevel@tonic-gate * naming. 261*7c478bd9Sstevel@tonic-gate */ 262*7c478bd9Sstevel@tonic-gate if (is_private) { 263*7c478bd9Sstevel@tonic-gate dbmp->reginfo.appname = DB_APP_TMP; 264*7c478bd9Sstevel@tonic-gate dbmp->reginfo.file = NULL; 265*7c478bd9Sstevel@tonic-gate F_SET(&dbmp->reginfo, REGION_PRIVATE); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate if ((ret = __db_rattach(&dbmp->reginfo)) != 0) { 269*7c478bd9Sstevel@tonic-gate if (dbmp->reginfo.path != NULL) 270*7c478bd9Sstevel@tonic-gate __os_freestr(dbmp->reginfo.path); 271*7c478bd9Sstevel@tonic-gate return (ret); 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate /* 275*7c478bd9Sstevel@tonic-gate * The MPOOL structure is first in the region, the rest of the region 276*7c478bd9Sstevel@tonic-gate * is free space. 277*7c478bd9Sstevel@tonic-gate */ 278*7c478bd9Sstevel@tonic-gate dbmp->mp = dbmp->reginfo.addr; 279*7c478bd9Sstevel@tonic-gate dbmp->addr = (u_int8_t *)dbmp->mp + sizeof(MPOOL); 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate /* Initialize a created region. */ 282*7c478bd9Sstevel@tonic-gate if (F_ISSET(&dbmp->reginfo, REGION_CREATED)) { 283*7c478bd9Sstevel@tonic-gate mp = dbmp->mp; 284*7c478bd9Sstevel@tonic-gate SH_TAILQ_INIT(&mp->bhq); 285*7c478bd9Sstevel@tonic-gate SH_TAILQ_INIT(&mp->bhfq); 286*7c478bd9Sstevel@tonic-gate SH_TAILQ_INIT(&mp->mpfq); 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate __db_shalloc_init(dbmp->addr, rlen - sizeof(MPOOL)); 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * Assume we want to keep the hash chains with under 10 pages 292*7c478bd9Sstevel@tonic-gate * on each chain. We don't know the pagesize in advance, and 293*7c478bd9Sstevel@tonic-gate * it may differ for different files. Use a pagesize of 1K for 294*7c478bd9Sstevel@tonic-gate * the calculation -- we walk these chains a lot, they should 295*7c478bd9Sstevel@tonic-gate * be short. 296*7c478bd9Sstevel@tonic-gate */ 297*7c478bd9Sstevel@tonic-gate mp->htab_buckets = 298*7c478bd9Sstevel@tonic-gate __db_tablesize((cachesize / (1 * 1024)) / 10); 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate /* Allocate hash table space and initialize it. */ 301*7c478bd9Sstevel@tonic-gate if ((ret = __db_shalloc(dbmp->addr, 302*7c478bd9Sstevel@tonic-gate mp->htab_buckets * sizeof(DB_HASHTAB), 303*7c478bd9Sstevel@tonic-gate 0, &dbmp->htab)) != 0) 304*7c478bd9Sstevel@tonic-gate goto err; 305*7c478bd9Sstevel@tonic-gate __db_hashinit(dbmp->htab, mp->htab_buckets); 306*7c478bd9Sstevel@tonic-gate mp->htab = R_OFFSET(dbmp, dbmp->htab); 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate ZERO_LSN(mp->lsn); 309*7c478bd9Sstevel@tonic-gate mp->lsn_cnt = 0; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate memset(&mp->stat, 0, sizeof(mp->stat)); 312*7c478bd9Sstevel@tonic-gate mp->stat.st_cachesize = cachesize; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate mp->flags = 0; 315*7c478bd9Sstevel@tonic-gate } 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate /* Get the local hash table address. */ 318*7c478bd9Sstevel@tonic-gate dbmp->htab = R_ADDR(dbmp, dbmp->mp->htab); 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate UNLOCKREGION(dbmp); 321*7c478bd9Sstevel@tonic-gate return (0); 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate err: UNLOCKREGION(dbmp); 324*7c478bd9Sstevel@tonic-gate (void)__db_rdetach(&dbmp->reginfo); 325*7c478bd9Sstevel@tonic-gate if (F_ISSET(&dbmp->reginfo, REGION_CREATED)) 326*7c478bd9Sstevel@tonic-gate (void)memp_unlink(path, 1, dbmp->dbenv); 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate if (dbmp->reginfo.path != NULL) 329*7c478bd9Sstevel@tonic-gate __os_freestr(dbmp->reginfo.path); 330*7c478bd9Sstevel@tonic-gate return (ret); 331*7c478bd9Sstevel@tonic-gate } 332