Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

qam_open.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1999-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: qam_open.c,v 12.4 2005/10/15 00:56:55 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/crypto.h"
00020 #include "dbinc/db_page.h"
00021 #include "dbinc/db_shash.h"
00022 #include "dbinc/db_swap.h"
00023 #include "dbinc/db_am.h"
00024 #include "dbinc/lock.h"
00025 #include "dbinc/mp.h"
00026 #include "dbinc/qam.h"
00027 #include "dbinc/fop.h"
00028 
00029 static int __qam_init_meta __P((DB *, QMETA *));
00030 
00031 /*
00032  * __qam_open
00033  *
00034  * PUBLIC: int __qam_open __P((DB *,
00035  * PUBLIC:     DB_TXN *, const char *, db_pgno_t, int, u_int32_t));
00036  */
00037 int
00038 __qam_open(dbp, txn, name, base_pgno, mode, flags)
00039         DB *dbp;
00040         DB_TXN *txn;
00041         const char *name;
00042         db_pgno_t base_pgno;
00043         int mode;
00044         u_int32_t flags;
00045 {
00046         DBC *dbc;
00047         DB_ENV *dbenv;
00048         DB_LOCK metalock;
00049         DB_MPOOLFILE *mpf;
00050         QMETA *qmeta;
00051         QUEUE *t;
00052         int ret, t_ret;
00053 
00054         dbenv = dbp->dbenv;
00055         mpf = dbp->mpf;
00056         t = dbp->q_internal;
00057         ret = 0;
00058         qmeta = NULL;
00059 
00060         if (name == NULL && t->page_ext != 0) {
00061                 __db_err(dbenv,
00062         "Extent size may not be specified for in-memory queue database");
00063                 return (EINVAL);
00064         }
00065 
00066         /* Initialize the remaining fields/methods of the DB. */
00067         dbp->db_am_remove = __qam_remove;
00068         dbp->db_am_rename = __qam_rename;
00069 
00070         /*
00071          * Get a cursor.  If DB_CREATE is specified, we may be creating
00072          * pages, and to do that safely in CDB we need a write cursor.
00073          * In STD_LOCKING mode, we'll synchronize using the meta page
00074          * lock instead.
00075          */
00076         if ((ret = __db_cursor(dbp, txn, &dbc,
00077             LF_ISSET(DB_CREATE) && CDB_LOCKING(dbenv) ?
00078             DB_WRITECURSOR : 0)) != 0)
00079                 return (ret);
00080 
00081         /*
00082          * Get the meta data page.  It must exist, because creates of
00083          * files/databases come in through the __qam_new_file interface
00084          * and queue doesn't support subdatabases.
00085          */
00086         if ((ret =
00087             __db_lget(dbc, 0, base_pgno, DB_LOCK_READ, 0, &metalock)) != 0)
00088                 goto err;
00089         if ((ret = __memp_fget(mpf, &base_pgno, 0, &qmeta)) != 0)
00090                 goto err;
00091 
00092         /* If the magic number is incorrect, that's a fatal error. */
00093         if (qmeta->dbmeta.magic != DB_QAMMAGIC) {
00094                 __db_err(dbenv, "%s: unexpected file type or format", name);
00095                 ret = EINVAL;
00096                 goto err;
00097         }
00098 
00099         /* Setup information needed to open extents. */
00100         t->page_ext = qmeta->page_ext;
00101 
00102         if (t->page_ext != 0 && (ret = __qam_set_ext_data(dbp, name)) != 0)
00103                 goto err;
00104 
00105         if (mode == 0)
00106                 mode = __db_omode("rw-rw----");
00107         t->mode = mode;
00108         t->re_pad = qmeta->re_pad;
00109         t->re_len = qmeta->re_len;
00110         t->rec_page = qmeta->rec_page;
00111 
00112         t->q_meta = base_pgno;
00113         t->q_root = base_pgno + 1;
00114 
00115 err:    if (qmeta != NULL &&
00116             (t_ret = __memp_fput(mpf, qmeta, 0)) != 0 && ret == 0)
00117                 ret = t_ret;
00118 
00119         /* Don't hold the meta page long term. */
00120         if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
00121                 ret = t_ret;
00122 
00123         if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
00124                 ret = t_ret;
00125 
00126         return (ret);
00127 }
00128 
00129 /*
00130  * __qam_set_ext_data --
00131  *      Setup DBP data for opening queue extents.
00132  *
00133  * PUBLIC: int __qam_set_ext_data __P((DB*, const char *));
00134  */
00135 int
00136 __qam_set_ext_data(dbp, name)
00137         DB *dbp;
00138         const char *name;
00139 {
00140         QUEUE *t;
00141         int ret;
00142 
00143         t = dbp->q_internal;
00144         t->pginfo.db_pagesize = dbp->pgsize;
00145         t->pginfo.flags =
00146             F_ISSET(dbp, (DB_AM_CHKSUM | DB_AM_ENCRYPT | DB_AM_SWAP));
00147         t->pginfo.type = dbp->type;
00148         t->pgcookie.data = &t->pginfo;
00149         t->pgcookie.size = sizeof(DB_PGINFO);
00150 
00151         if ((ret = __os_strdup(dbp->dbenv, name,  &t->path)) != 0)
00152                 return (ret);
00153         t->dir = t->path;
00154         if ((t->name = __db_rpath(t->path)) == NULL) {
00155                 t->name = t->path;
00156                 t->dir = PATH_DOT;
00157         } else
00158                 *t->name++ = '\0';
00159 
00160         return (0);
00161 }
00162 
00163 /*
00164  * __qam_metachk --
00165  *
00166  * PUBLIC: int __qam_metachk __P((DB *, const char *, QMETA *));
00167  */
00168 int
00169 __qam_metachk(dbp, name, qmeta)
00170         DB *dbp;
00171         const char *name;
00172         QMETA *qmeta;
00173 {
00174         DB_ENV *dbenv;
00175         u_int32_t vers;
00176         int ret;
00177 
00178         dbenv = dbp->dbenv;
00179         ret = 0;
00180 
00181         /*
00182          * At this point, all we know is that the magic number is for a Queue.
00183          * Check the version, the database may be out of date.
00184          */
00185         vers = qmeta->dbmeta.version;
00186         if (F_ISSET(dbp, DB_AM_SWAP))
00187                 M_32_SWAP(vers);
00188         switch (vers) {
00189         case 1:
00190         case 2:
00191                 __db_err(dbenv,
00192                     "%s: queue version %lu requires a version upgrade",
00193                     name, (u_long)vers);
00194                 return (DB_OLD_VERSION);
00195         case 3:
00196         case 4:
00197                 break;
00198         default:
00199                 __db_err(dbenv,
00200                     "%s: unsupported qam version: %lu", name, (u_long)vers);
00201                 return (EINVAL);
00202         }
00203 
00204         /* Swap the page if we need to. */
00205         if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __qam_mswap((PAGE *)qmeta)) != 0)
00206                 return (ret);
00207 
00208         /* Check the type. */
00209         if (dbp->type != DB_QUEUE && dbp->type != DB_UNKNOWN)
00210                 return (EINVAL);
00211         dbp->type = DB_QUEUE;
00212         DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE);
00213 
00214         /* Set the page size. */
00215         dbp->pgsize = qmeta->dbmeta.pagesize;
00216 
00217         /* Copy the file's ID. */
00218         memcpy(dbp->fileid, qmeta->dbmeta.uid, DB_FILE_ID_LEN);
00219 
00220         /* Set up AM-specific methods that do not require an open. */
00221         dbp->db_am_rename = __qam_rename;
00222         dbp->db_am_remove = __qam_remove;
00223 
00224         return (ret);
00225 }
00226 
00227 /*
00228  * __qam_init_meta --
00229  *      Initialize the meta-data for a Queue database.
00230  */
00231 static int
00232 __qam_init_meta(dbp, meta)
00233         DB *dbp;
00234         QMETA *meta;
00235 {
00236         QUEUE *t;
00237 
00238         t = dbp->q_internal;
00239 
00240         memset(meta, 0, sizeof(QMETA));
00241         LSN_NOT_LOGGED(meta->dbmeta.lsn);
00242         meta->dbmeta.pgno = PGNO_BASE_MD;
00243         meta->dbmeta.last_pgno = 0;
00244         meta->dbmeta.magic = DB_QAMMAGIC;
00245         meta->dbmeta.version = DB_QAMVERSION;
00246         meta->dbmeta.pagesize = dbp->pgsize;
00247         if (F_ISSET(dbp, DB_AM_CHKSUM))
00248                 FLD_SET(meta->dbmeta.metaflags, DBMETA_CHKSUM);
00249         if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
00250                 meta->dbmeta.encrypt_alg =
00251                    ((DB_CIPHER *)dbp->dbenv->crypto_handle)->alg;
00252                 DB_ASSERT(meta->dbmeta.encrypt_alg != 0);
00253                 meta->crypto_magic = meta->dbmeta.magic;
00254         }
00255         meta->dbmeta.type = P_QAMMETA;
00256         meta->re_pad = t->re_pad;
00257         meta->re_len = t->re_len;
00258         meta->rec_page = CALC_QAM_RECNO_PER_PAGE(dbp);
00259         meta->cur_recno = 1;
00260         meta->first_recno = 1;
00261         meta->page_ext = t->page_ext;
00262         t->rec_page = meta->rec_page;
00263         memcpy(meta->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN);
00264 
00265         /* Verify that we can fit at least one record per page. */
00266         if (QAM_RECNO_PER_PAGE(dbp) < 1) {
00267                 __db_err(dbp->dbenv,
00268                     "Record size of %lu too large for page size of %lu",
00269                     (u_long)t->re_len, (u_long)dbp->pgsize);
00270                 return (EINVAL);
00271         }
00272 
00273         return (0);
00274 }
00275 
00276 /*
00277  * __qam_new_file --
00278  * Create the necessary pages to begin a new queue database file.
00279  *
00280  * This code appears more complex than it is because of the two cases (named
00281  * and unnamed).  The way to read the code is that for each page being created,
00282  * there are three parts: 1) a "get page" chunk (which either uses malloc'd
00283  * memory or calls __memp_fget), 2) the initialization, and 3) the "put page"
00284  * chunk which either does a fop write or an __memp_fput.
00285  *
00286  * PUBLIC: int __qam_new_file __P((DB *, DB_TXN *, DB_FH *, const char *));
00287  */
00288 int
00289 __qam_new_file(dbp, txn, fhp, name)
00290         DB *dbp;
00291         DB_TXN *txn;
00292         DB_FH *fhp;
00293         const char *name;
00294 {
00295         QMETA *meta;
00296         DB_ENV *dbenv;
00297         DB_MPOOLFILE *mpf;
00298         DB_PGINFO pginfo;
00299         DBT pdbt;
00300         db_pgno_t pgno;
00301         int ret;
00302         void *buf;
00303 
00304         dbenv = dbp->dbenv;
00305         mpf = dbp->mpf;
00306         buf = NULL;
00307         meta = NULL;
00308 
00309         /* Build meta-data page. */
00310 
00311         if (F_ISSET(dbp, DB_AM_INMEM)) {
00312                 pgno = PGNO_BASE_MD;
00313                 ret = __memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &meta);
00314         } else {
00315                 ret = __os_calloc(dbenv, 1, dbp->pgsize, &buf);
00316                 meta = (QMETA *)buf;
00317         }
00318         if (ret != 0)
00319                 return (ret);
00320 
00321         if ((ret = __qam_init_meta(dbp, meta)) != 0)
00322                 goto err;
00323 
00324         if (F_ISSET(dbp, DB_AM_INMEM)) {
00325                 if ((ret = __db_log_page(dbp,
00326                     txn, &meta->dbmeta.lsn, pgno, (PAGE *)meta)) != 0)
00327                         goto err;
00328                 ret = __memp_fput(mpf, meta, DB_MPOOL_DIRTY);
00329         } else {
00330                 pginfo.db_pagesize = dbp->pgsize;
00331                 pginfo.flags =
00332                     F_ISSET(dbp, (DB_AM_CHKSUM | DB_AM_ENCRYPT | DB_AM_SWAP));
00333                 pginfo.type = DB_QUEUE;
00334                 pdbt.data = &pginfo;
00335                 pdbt.size = sizeof(pginfo);
00336                 if ((ret = __db_pgout(dbenv, PGNO_BASE_MD, meta, &pdbt)) != 0)
00337                         goto err;
00338                 ret = __fop_write(dbenv, txn, name,
00339                     DB_APP_DATA, fhp, dbp->pgsize, 0, 0, buf, dbp->pgsize, 1,
00340                     F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0);
00341         }
00342         if (ret != 0)
00343                 goto err;
00344         meta = NULL;
00345 
00346 err:    if (name != NULL)
00347                 __os_free(dbenv, buf);
00348         else if (meta != NULL)
00349                 (void)__memp_fput(mpf, meta, 0);
00350         return (ret);
00351 }

Generated on Sun Dec 25 12:14:44 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2