mp_region.c

Go to the documentation of this file.
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(&reginfo, REGION_CREATE_OK);
00069         if ((ret = CDB___db_r_attach(dbenv, &reginfo, 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(&reginfo, 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(&reginfo, 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, &reginfo->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 }

Generated on Sun Jun 8 10:56:38 2008 for GNUmifluz by  doxygen 1.5.5