1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996, 1997, 1998 5 * Sleepycat Software. All rights reserved. 6 */ 7 #include "config.h" 8 9 #ifndef lint 10 static const char sccsid[] = "@(#)mp_open.c 10.27 (Sleepycat) 10/1/98"; 11 #endif /* not lint */ 12 13 #ifndef NO_SYSTEM_INCLUDES 14 #include <sys/types.h> 15 16 #include <errno.h> 17 #include <string.h> 18 #endif 19 20 #include "db_int.h" 21 #include "shqueue.h" 22 #include "db_shash.h" 23 #include "mp.h" 24 #include "common_ext.h" 25 26 /* 27 * memp_open -- 28 * Initialize and/or join a memory pool. 29 */ 30 int 31 memp_open(path, flags, mode, dbenv, retp) 32 const char *path; 33 u_int32_t flags; 34 int mode; 35 DB_ENV *dbenv; 36 DB_MPOOL **retp; 37 { 38 DB_MPOOL *dbmp; 39 size_t cachesize; 40 int is_private, ret; 41 42 /* Validate arguments. */ 43 #ifdef HAVE_SPINLOCKS 44 #define OKFLAGS (DB_CREATE | DB_MPOOL_PRIVATE | DB_NOMMAP | DB_THREAD) 45 #else 46 #define OKFLAGS (DB_CREATE | DB_MPOOL_PRIVATE | DB_NOMMAP) 47 #endif 48 if ((ret = __db_fchk(dbenv, "memp_open", flags, OKFLAGS)) != 0) 49 return (ret); 50 51 /* Extract fields from DB_ENV structure. */ 52 cachesize = dbenv == NULL ? 0 : dbenv->mp_size; 53 54 /* Create and initialize the DB_MPOOL structure. */ 55 if ((ret = __os_calloc(1, sizeof(DB_MPOOL), &dbmp)) != 0) 56 return (ret); 57 LIST_INIT(&dbmp->dbregq); 58 TAILQ_INIT(&dbmp->dbmfq); 59 60 dbmp->dbenv = dbenv; 61 62 /* Decide if it's possible for anyone else to access the pool. */ 63 is_private = 64 (dbenv == NULL && path == NULL) || LF_ISSET(DB_MPOOL_PRIVATE); 65 66 /* 67 * Map in the region. We do locking regardless, as portions of it are 68 * implemented in common code (if we put the region in a file, that is). 69 */ 70 F_SET(dbmp, MP_LOCKREGION); 71 if ((ret = __memp_ropen(dbmp, 72 path, cachesize, mode, is_private, LF_ISSET(DB_CREATE))) != 0) 73 goto err; 74 F_CLR(dbmp, MP_LOCKREGION); 75 76 /* 77 * If there's concurrent access, then we have to lock the region. 78 * If it's threaded, then we have to lock both the handles and the 79 * region, and we need to allocate a mutex for that purpose. 80 */ 81 if (!is_private) 82 F_SET(dbmp, MP_LOCKREGION); 83 if (LF_ISSET(DB_THREAD)) { 84 F_SET(dbmp, MP_LOCKHANDLE | MP_LOCKREGION); 85 LOCKREGION(dbmp); 86 ret = __memp_alloc(dbmp, 87 sizeof(db_mutex_t), NULL, &dbmp->mutexp); 88 UNLOCKREGION(dbmp); 89 if (ret != 0) { 90 (void)memp_close(dbmp); 91 goto err; 92 } 93 LOCKINIT(dbmp, dbmp->mutexp); 94 } 95 96 *retp = dbmp; 97 return (0); 98 99 err: if (dbmp != NULL) 100 __os_free(dbmp, sizeof(DB_MPOOL)); 101 return (ret); 102 } 103 104 /* 105 * memp_close -- 106 * Close a memory pool. 107 */ 108 int 109 memp_close(dbmp) 110 DB_MPOOL *dbmp; 111 { 112 DB_MPOOLFILE *dbmfp; 113 DB_MPREG *mpreg; 114 int ret, t_ret; 115 116 ret = 0; 117 118 MP_PANIC_CHECK(dbmp); 119 120 /* Discard DB_MPREGs. */ 121 while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) { 122 LIST_REMOVE(mpreg, q); 123 __os_free(mpreg, sizeof(DB_MPREG)); 124 } 125 126 /* Discard DB_MPOOLFILEs. */ 127 while ((dbmfp = TAILQ_FIRST(&dbmp->dbmfq)) != NULL) 128 if ((t_ret = memp_fclose(dbmfp)) != 0 && ret == 0) 129 ret = t_ret; 130 131 /* Discard thread mutex. */ 132 if (F_ISSET(dbmp, MP_LOCKHANDLE)) { 133 LOCKREGION(dbmp); 134 __db_shalloc_free(dbmp->addr, dbmp->mutexp); 135 UNLOCKREGION(dbmp); 136 } 137 138 /* Close the region. */ 139 if ((t_ret = __db_rdetach(&dbmp->reginfo)) != 0 && ret == 0) 140 ret = t_ret; 141 142 if (dbmp->reginfo.path != NULL) 143 __os_freestr(dbmp->reginfo.path); 144 __os_free(dbmp, sizeof(DB_MPOOL)); 145 146 return (ret); 147 } 148 149 /* 150 * __memp_panic -- 151 * Panic a memory pool. 152 * 153 * PUBLIC: void __memp_panic __P((DB_ENV *)); 154 */ 155 void 156 __memp_panic(dbenv) 157 DB_ENV *dbenv; 158 { 159 if (dbenv->mp_info != NULL) 160 dbenv->mp_info->mp->rlayout.panic = 1; 161 } 162 163 /* 164 * memp_unlink -- 165 * Exit a memory pool. 166 */ 167 int 168 memp_unlink(path, force, dbenv) 169 const char *path; 170 int force; 171 DB_ENV *dbenv; 172 { 173 REGINFO reginfo; 174 int ret; 175 176 memset(®info, 0, sizeof(reginfo)); 177 reginfo.dbenv = dbenv; 178 reginfo.appname = DB_APP_NONE; 179 if (path != NULL && (ret = __os_strdup(path, ®info.path)) != 0) 180 return (ret); 181 reginfo.file = DB_DEFAULT_MPOOL_FILE; 182 ret = __db_runlink(®info, force); 183 if (reginfo.path != NULL) 184 __os_freestr(reginfo.path); 185 return (ret); 186 } 187 188 /* 189 * memp_register -- 190 * Register a file type's pgin, pgout routines. 191 */ 192 int 193 memp_register(dbmp, ftype, pgin, pgout) 194 DB_MPOOL *dbmp; 195 int ftype; 196 int (*pgin) __P((db_pgno_t, void *, DBT *)); 197 int (*pgout) __P((db_pgno_t, void *, DBT *)); 198 { 199 DB_MPREG *mpr; 200 int ret; 201 202 MP_PANIC_CHECK(dbmp); 203 204 if ((ret = __os_malloc(sizeof(DB_MPREG), NULL, &mpr)) != 0) 205 return (ret); 206 207 mpr->ftype = ftype; 208 mpr->pgin = pgin; 209 mpr->pgout = pgout; 210 211 /* 212 * Insert at the head. Because we do a linear walk, we'll find 213 * the most recent registry in the case of multiple entries, so 214 * we don't have to check for multiple registries. 215 */ 216 LOCKHANDLE(dbmp, dbmp->mutexp); 217 LIST_INSERT_HEAD(&dbmp->dbregq, mpr, q); 218 UNLOCKHANDLE(dbmp, dbmp->mutexp); 219 220 return (0); 221 } 222