00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 #include "config.h" 00008 00009 #ifndef lint 00010 static const char revid[] = "$Id: mp__region_8c-source.html,v 1.1 2008年06月08日 10:20:49 sebdiaz Exp $"; 00011 #endif /* not lint */ 00012 00013 #ifndef NO_SYSTEM_INCLUDES 00014 #include <sys/types.h> 00015 00016 #include <errno.h> 00017 #include <string.h> 00018 #endif 00019 00020 #include "db_int.h" 00021 #include "db_shash.h" 00022 #include "mp.h" 00023 00024 static int __mpool_init __P((DB_ENV *, DB_MPOOL *, int, int)); 00025 00026 /* 00027 * CDB___memp_open -- 00028 * Internal version of memp_open: only called from DB_ENV->open. 00029 * 00030 * PUBLIC: int CDB___memp_open __P((DB_ENV *)); 00031 */ 00032 int 00033 CDB___memp_open(dbenv) 00034 DB_ENV *dbenv; 00035 { 00036 DB_MPOOL *dbmp; 00037 MPOOL *mp; 00038 REGINFO reginfo; 00039 roff_t reg_size, *regids; 00040 u_int32_t i; 00041 int htab_buckets, ret; 00042 00043 /* Figure out how big each cache region is. */ 00044 reg_size = dbenv->mp_gbytes / dbenv->mp_ncache; 00045 reg_size += (dbenv->mp_gbytes % dbenv->mp_ncache) / dbenv->mp_ncache; 00046 reg_size += dbenv->mp_bytes / dbenv->mp_ncache; 00047 00048 /* 00049 * Figure out how many hash buckets each region will have. Assume we 00050 * want to keep the hash chains with under 10 pages on each chain. We 00051 * don't know the pagesize in advance, and it may differ for different 00052 * files. Use a pagesize of 1K for the calculation -- we walk these 00053 * chains a lot, they must be kept short. 00054 */ 00055 htab_buckets = CDB___db_tablesize((reg_size / (1 * 1024)) / 10); 00056 00057 /* Create and initialize the DB_MPOOL structure. */ 00058 if ((ret = CDB___os_calloc(dbenv, 1, sizeof(*dbmp), &dbmp)) != 0) 00059 return (ret); 00060 LIST_INIT(&dbmp->dbregq); 00061 TAILQ_INIT(&dbmp->dbmfq); 00062 dbmp->dbenv = dbenv; 00063 00064 /* Join/create the first mpool region. */ 00065 reginfo.id = REG_ID_MPOOL; 00066 reginfo.mode = dbenv->db_mode; 00067 if (F_ISSET(dbenv, DB_ENV_CREATE)) 00068 F_SET(®info, REGION_CREATE_OK); 00069 if ((ret = CDB___db_r_attach(dbenv, ®info, reg_size)) != 0) 00070 goto err; 00071 00072 /* 00073 * If we created the region, initialize it. Create or join any 00074 * additional regions. 00075 */ 00076 if (F_ISSET(®info, REGION_CREATE)) { 00077 /* 00078 * We define how many regions there are going to be, allocate 00079 * the REGINFO structures and create them. Make sure we don't 00080 * clear the wrong entries on error. 00081 */ 00082 dbmp->nreg = dbenv->mp_ncache; 00083 if ((ret = CDB___os_calloc(dbenv, 00084 dbmp->nreg, sizeof(REGINFO), &dbmp->reginfo)) != 0) 00085 goto err; 00086 for (i = 0; i < dbmp->nreg; ++i) 00087 dbmp->reginfo[i].id = REG_ID_INVALID; 00088 dbmp->reginfo[0] = reginfo; 00089 00090 /* Initialize the first region. */ 00091 if ((ret = __mpool_init(dbenv, dbmp, 0, htab_buckets)) != 0) 00092 goto err; 00093 00094 /* 00095 * Create/initialize remaining regions and copy their IDs into 00096 * the first region. 00097 */ 00098 mp = R_ADDR(dbmp->reginfo, dbmp->reginfo[0].rp->primary); 00099 regids = R_ADDR(dbmp->reginfo, mp->regids); 00100 for (i = 1; i < dbmp->nreg; ++i) { 00101 dbmp->reginfo[i].id = REG_ID_INVALID; 00102 dbmp->reginfo[i].mode = dbenv->db_mode; 00103 F_SET(&dbmp->reginfo[i], REGION_CREATE_OK); 00104 if ((ret = CDB___db_r_attach( 00105 dbenv, &dbmp->reginfo[i], reg_size)) != 0) 00106 goto err; 00107 if ((ret = 00108 __mpool_init(dbenv, dbmp, i, htab_buckets)) != 0) 00109 goto err; 00110 R_UNLOCK(dbenv, &dbmp->reginfo[i]); 00111 00112 regids[i] = dbmp->reginfo[i].id; 00113 } 00114 } else { 00115 /* 00116 * Determine how many regions there are going to be, allocate 00117 * the REGINFO structures and fill in local copies of that 00118 * information. Make sure we don't clear the wrong entries on 00119 * error. 00120 */ 00121 mp = R_ADDR(®info, reginfo.rp->primary); 00122 dbmp->nreg = mp->nreg; 00123 if ((ret = CDB___os_calloc(dbenv, 00124 dbmp->nreg, sizeof(REGINFO), &dbmp->reginfo)) != 0) 00125 goto err; 00126 for (i = 0; i < dbmp->nreg; ++i) 00127 dbmp->reginfo[i].id = REG_ID_INVALID; 00128 dbmp->reginfo[0] = reginfo; 00129 00130 /* Join/initialize remaining regions. */ 00131 regids = R_ADDR(dbmp->reginfo, mp->regids); 00132 for (i = 1; i < dbmp->nreg; ++i) { 00133 dbmp->reginfo[i].id = regids[i]; 00134 dbmp->reginfo[i].mode = 0; 00135 if ((ret = CDB___db_r_attach( 00136 dbenv, &dbmp->reginfo[i], 0)) != 0) 00137 goto err; 00138 R_UNLOCK(dbenv, &dbmp->reginfo[i]); 00139 } 00140 } 00141 00142 /* Set the local addresses for the regions. */ 00143 for (i = 0; i < dbmp->nreg; ++i) 00144 dbmp->reginfo[i].primary = 00145 R_ADDR(&dbmp->reginfo[i], dbmp->reginfo[i].rp->primary); 00146 00147 R_UNLOCK(dbenv, dbmp->reginfo); 00148 00149 /* If the region is threaded, allocate a mutex to lock the handles. */ 00150 if (F_ISSET(dbenv, DB_ENV_THREAD)) { 00151 if ((ret = CDB___db_mutex_alloc( 00152 dbenv, dbmp->reginfo, &dbmp->mutexp)) != 0) { 00153 goto err; 00154 } 00155 if ((ret = 00156 __db_mutex_init(dbenv, dbmp->mutexp, 0, MUTEX_THREAD)) != 0) 00157 goto err; 00158 } 00159 00160 dbenv->mp_handle = dbmp; 00161 return (0); 00162 00163 err: if (dbmp->reginfo[0].addr != NULL) { 00164 if (F_ISSET(dbmp->reginfo, REGION_CREATE)) 00165 for (i = 0; i < dbmp->nreg; ++i) 00166 if (dbmp->reginfo[i].id != REG_ID_INVALID) 00167 F_SET(dbmp->reginfo[i].rp, REG_DEAD); 00168 00169 R_UNLOCK(dbenv, dbmp->reginfo); 00170 00171 for (i = 0; i < dbmp->nreg; ++i) 00172 if (dbmp->reginfo[i].id != REG_ID_INVALID) 00173 (void)CDB___db_r_detach( 00174 dbenv, &dbmp->reginfo[i], 0); 00175 CDB___os_free(dbmp->reginfo, 00176 dbmp->nreg * sizeof(*dbmp->reginfo)); 00177 } 00178 CDB___os_free(dbmp, sizeof(*dbmp)); 00179 return (ret); 00180 } 00181 00182 /* 00183 * __mpool_init -- 00184 * Initialize a MPOOL structure in shared memory. 00185 */ 00186 static int 00187 __mpool_init(dbenv, dbmp, reginfo_off, htab_buckets) 00188 DB_ENV *dbenv; 00189 DB_MPOOL *dbmp; 00190 int reginfo_off, htab_buckets; 00191 { 00192 DB_HASHTAB *htab; 00193 MPOOL *mp; 00194 REGINFO *reginfo; 00195 int ret; 00196 void *p; 00197 00198 mp = NULL; 00199 00200 reginfo = &dbmp->reginfo[reginfo_off]; 00201 if ((ret = CDB___db_shalloc(reginfo->addr, 00202 sizeof(MPOOL), MUTEX_ALIGN, ®info->primary)) != 0) 00203 goto mem_err; 00204 reginfo->rp->primary = R_OFFSET(reginfo, reginfo->primary); 00205 mp = reginfo->primary; 00206 memset(mp, 0, sizeof(*mp)); 00207 00208 if (reginfo_off == 0) { 00209 SH_TAILQ_INIT(&mp->mpfq); 00210 00211 if ((ret = __db_mutex_init(dbenv, &mp->sync_mutex, 00212 R_OFFSET(dbmp->reginfo, 00213 &mp->sync_mutex) + DB_FCNTL_OFF_MPOOL, 0)) != 0) 00214 goto err; 00215 00216 ZERO_LSN(mp->lsn); 00217 mp->lsn_cnt = 0; 00218 00219 mp->nreg = dbmp->nreg; 00220 if ((ret = CDB___db_shalloc(dbmp->reginfo[0].addr, 00221 dbmp->nreg * sizeof(int), 0, &p)) != 0) 00222 goto mem_err; 00223 mp->regids = R_OFFSET(dbmp->reginfo, p); 00224 } 00225 00226 SH_TAILQ_INIT(&mp->bhq); 00227 00228 /* Allocate hash table space and initialize it. */ 00229 if ((ret = CDB___db_shalloc(reginfo->addr, 00230 htab_buckets * sizeof(DB_HASHTAB), 0, &htab)) != 0) 00231 goto mem_err; 00232 CDB___db_hashinit(htab, htab_buckets); 00233 mp->htab = R_OFFSET(reginfo, htab); 00234 mp->htab_buckets = htab_buckets; 00235 00236 return (0); 00237 00238 mem_err:CDB___db_err(dbenv, "Unable to allocate memory for mpool region"); 00239 err: if (reginfo->primary != NULL) 00240 CDB___db_shalloc_free(reginfo->addr, reginfo->primary); 00241 return (ret); 00242 } 00243 00244 /* 00245 * CDB___memp_close -- 00246 * Internal version of memp_close: only called from DB_ENV->close. 00247 * 00248 * PUBLIC: int CDB___memp_close __P((DB_ENV *)); 00249 */ 00250 int 00251 CDB___memp_close(dbenv) 00252 DB_ENV *dbenv; 00253 { 00254 DB_MPOOL *dbmp; 00255 DB_MPOOLFILE *dbmfp; 00256 DB_MPREG *mpreg; 00257 u_int32_t i; 00258 int ret, t_ret; 00259 00260 ret = 0; 00261 dbmp = dbenv->mp_handle; 00262 00263 /* Discard DB_MPREGs. */ 00264 while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) { 00265 LIST_REMOVE(mpreg, q); 00266 CDB___os_free(mpreg, sizeof(DB_MPREG)); 00267 } 00268 00269 /* Discard DB_MPOOLFILEs. */ 00270 while ((dbmfp = TAILQ_FIRST(&dbmp->dbmfq)) != NULL) { 00271 if ((t_ret = CDB_memp_fclose(dbmfp)) != 0 && ret == 0) 00272 ret = t_ret; 00273 } 00274 00275 /* Discard the thread mutex. */ 00276 if (dbmp->mutexp != NULL) 00277 CDB___db_mutex_free(dbenv, dbmp->reginfo, dbmp->mutexp); 00278 00279 /* Detach from the region(s). */ 00280 for (i = 0; i < dbmp->nreg; ++i) 00281 if ((t_ret = CDB___db_r_detach( 00282 dbenv, &dbmp->reginfo[i], 0)) != 0 && ret == 0) 00283 ret = t_ret; 00284 00285 CDB___os_free(dbmp->reginfo, dbmp->nreg * sizeof(*dbmp->reginfo)); 00286 CDB___os_free(dbmp, sizeof(*dbmp)); 00287 00288 dbenv->mp_handle = NULL; 00289 return (ret); 00290 }