log_register.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: log__register_8c-source.html,v 1.1 2008/06/08 10:20:30 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 #ifdef  HAVE_RPC
00021 #include "db_server.h"
00022 #endif
00023 
00024 #include "db_int.h"
00025 #include "log.h"
00026 
00027 #ifdef HAVE_RPC
00028 #include "gen_client_ext.h"
00029 #include "rpc_client_ext.h"
00030 #endif
00031 
00032 /*
00033  * CDB_log_register --
00034  *      Register a file name.
00035  */
00036 int
00037 CDB_log_register(dbenv, dbp, name)
00038         DB_ENV *dbenv;
00039         DB *dbp;
00040         const char *name;
00041 {
00042         DBT fid_dbt, r_name;
00043         DB_LOG *dblp;
00044         DB_LSN r_unused;
00045         FNAME *found, *fnp, *recover_fnp, *reuse_fnp;
00046         LOG *lp;
00047         size_t len;
00048         int32_t maxid;
00049         int inserted, ok, ret;
00050         void *namep;
00051 
00052 #ifdef HAVE_RPC
00053         if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00054                 return (__dbcl_log_register(dbenv, dbp, name));
00055 #endif
00056 
00057         PANIC_CHECK(dbenv);
00058         ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG);
00059 
00060         dblp = dbenv->lg_handle;
00061         lp = dblp->reginfo.primary;
00062         fnp = reuse_fnp = NULL;
00063         inserted = ret = 0;
00064         namep = NULL;
00065 
00066         /* Check the arguments. */
00067         if (dbp->type != DB_BTREE && dbp->type != DB_QUEUE &&
00068             dbp->type != DB_HASH && dbp->type != DB_RECNO) {
00069                 CDB___db_err(dbenv, "CDB_log_register: unknown DB file type");
00070                 return (EINVAL);
00071         }
00072 
00073         R_LOCK(dbenv, &dblp->reginfo);
00074 
00075         /*
00076          * See if we've already got this file in the log, finding the
00077          * (maximum+1) in-use file id and some available file id (if we
00078          * find an available fid, we'll use it, else we'll have to allocate
00079          * one after the maximum that we found).
00080          */
00081         ok = 0;
00082         found = NULL;
00083         recover_fnp = NULL;
00084         for (maxid = 0, fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
00085             fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
00086                 if (F_ISSET(dblp, DBLOG_RECOVER) && fnp->id == dbp->log_fileid)
00087                         recover_fnp = fnp;
00088                 if (fnp->ref == 0) {            /* Entry is not in use. */
00089                         if (reuse_fnp == NULL)
00090                                 reuse_fnp = fnp;
00091                         continue;
00092                 }
00093                 if (memcmp(dbp->fileid, fnp->ufid, DB_FILE_ID_LEN) == 0) {
00094                         if (fnp->meta_pgno == 0) {
00095                                 if (fnp->locked == 1) {
00096                                         CDB___db_err(dbenv, "File is locked");
00097                                         return (EINVAL);
00098                                 }
00099                                 if (found != NULL)
00100                                         goto found;
00101                                 ok = 1;
00102                         }
00103                         if (dbp->meta_pgno == fnp->meta_pgno) {
00104                                 if (F_ISSET(dblp, DBLOG_RECOVER)) {
00105                                         if (fnp->id != dbp->log_fileid) {
00106                                                 /*
00107                                                  * If we are in recovery, there
00108                                                  * is only one dbp on the list.
00109                                                  * If the refcount goes to 0,
00110                                                  * we will clear the list.  If
00111                                                  * it doesn't, we want to leave
00112                                                  * the dbp where it is, so
00113                                                  * passing a NULL to rem_logid
00114                                                  * is correct.
00115                                                  */
00116                                                 CDB___log_rem_logid(dblp,
00117                                                     NULL, fnp->id);
00118                                                 if (recover_fnp != NULL)
00119                                                         break;
00120                                                 continue;
00121                                         }
00122                                         fnp->ref = 1;
00123                                         goto found;
00124                                 }
00125                                 ++fnp->ref;
00126                                 if (ok)
00127                                         goto found;
00128                                 found = fnp;
00129                         }
00130                 }
00131                 if (maxid <= fnp->id)
00132                         maxid = fnp->id + 1;
00133         }
00134         if ((fnp = found) != NULL)
00135                 goto found;
00136 
00137         /* Fill in fnp structure. */
00138         if (recover_fnp != NULL)        /* This has the right number */
00139                 fnp = recover_fnp;
00140         else if (reuse_fnp != NULL)     /* Reuse existing one. */
00141                 fnp = reuse_fnp;
00142         else {                          /* Allocate a new one. */
00143                 if ((ret = CDB___db_shalloc(dblp->reginfo.addr,
00144                     sizeof(FNAME), 0, &fnp)) != 0)
00145                         goto mem_err;
00146                 fnp->id = maxid;
00147         }
00148 
00149         if (F_ISSET(dblp, DBLOG_RECOVER))
00150                 fnp->id = dbp->log_fileid;
00151 
00152         fnp->ref = 1;
00153         fnp->locked = 0;
00154         fnp->s_type = dbp->type;
00155         memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN);
00156         fnp->meta_pgno = dbp->meta_pgno;
00157 
00158         if (name != NULL) {
00159                 len = strlen(name) + 1;
00160                 if ((ret =
00161                     CDB___db_shalloc(dblp->reginfo.addr, len, 0, &namep)) != 0) {
00162 mem_err:                CDB___db_err(dbenv,
00163                             "Unable to allocate memory to register %s", namep);
00164                         goto err;
00165         }
00166                 fnp->name_off = R_OFFSET(&dblp->reginfo, namep);
00167                 memcpy(namep, name, len);
00168         } else
00169                 fnp->name_off = INVALID_ROFF;
00170 
00171         /* Only do the insert if we allocated a new fnp. */
00172         if (reuse_fnp == NULL && recover_fnp == NULL)
00173                 SH_TAILQ_INSERT_HEAD(&lp->fq, fnp, q, __fname);
00174         inserted = 1;
00175 
00176         /* Log the registry. */
00177         if (!F_ISSET(dblp, DBLOG_RECOVER)) {
00178                 /*
00179                  * We allow logging on in-memory databases, so the name here
00180                  * could be NULL.
00181                  */
00182                 if (name != NULL) {
00183                         r_name.data = (void *)name;
00184                         r_name.size = strlen(name) + 1;
00185                 }
00186                 memset(&fid_dbt, 0, sizeof(fid_dbt));
00187                 fid_dbt.data = dbp->fileid;
00188                 fid_dbt.size = DB_FILE_ID_LEN;
00189                 if ((ret = CDB___log_register_log(dbenv, NULL, &r_unused,
00190                     0, LOG_OPEN, name == NULL ? NULL : &r_name,
00191                     &fid_dbt, fnp->id, dbp->type, dbp->meta_pgno)) != 0)
00192                         goto err;
00193         }
00194 
00195 found:  /*
00196          * If we found the entry in the shared area, then the file is
00197          * already open, so there is no need to log the open.  We only
00198          * log the open and closes on the first open and last close.
00199          */
00200         if (!F_ISSET(dblp, DBLOG_RECOVER) &&
00201             (ret = CDB___log_add_logid(dbenv, dblp, dbp, fnp->id)) != 0)
00202                         goto err;
00203 
00204         if (!F_ISSET(dblp, DBLOG_RECOVER))
00205                 dbp->log_fileid = fnp->id;
00206 
00207         if (0) {
00208 err:            if (inserted)
00209                         SH_TAILQ_REMOVE(&lp->fq, fnp, q, __fname);
00210                 if (namep != NULL)
00211                         CDB___db_shalloc_free(dblp->reginfo.addr, namep);
00212                 if (fnp != NULL)
00213                         CDB___db_shalloc_free(dblp->reginfo.addr, fnp);
00214         }
00215 
00216         R_UNLOCK(dbenv, &dblp->reginfo);
00217 
00218         return (ret);
00219 }
00220 
00221 /*
00222  * CDB_log_unregister --
00223  *      Discard a registered file name.
00224  */
00225 int
00226 CDB_log_unregister(dbenv, dbp)
00227         DB_ENV *dbenv;
00228         DB *dbp;
00229 {
00230         int ret;
00231 
00232 #ifdef HAVE_RPC
00233         if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00234                 return (__dbcl_log_unregister(dbenv, dbp));
00235 #endif
00236 
00237         PANIC_CHECK(dbenv);
00238         ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG);
00239 
00240         ret = CDB___log_filelist_update(dbenv, dbp, dbp->log_fileid, NULL, NULL);
00241         dbp->log_fileid = DB_LOGFILEID_INVALID;
00242         return (ret);
00243 }
00244 
00245 /*
00246  * PUBLIC: int CDB___log_filelist_update
00247  * PUBLIC:    __P((DB_ENV *, DB *, int32_t, const char *, int *));
00248  *
00249  *  Utility player for updating and logging the file list.  Called
00250  *      for 3 reasons:
00251  *              1) mark file closed: newname == NULL.
00252  *              2) change filename: newname != NULL.
00253  *              3) from recovery to verify and change filename if
00254  *                      neessary, set != NULL.
00255  */
00256 int CDB___log_filelist_update(dbenv, dbp, fid, newname, set)
00257         DB_ENV *dbenv;
00258         DB *dbp;
00259         int32_t fid;
00260         const char *newname;
00261         int *set;
00262 {
00263         DBT fid_dbt, r_name;
00264         DB_LOG *dblp;
00265         DB_LSN r_unused;
00266         FNAME *fnp;
00267         LOG *lp;
00268         u_int32_t len, newlen;
00269         int ret;
00270         void *namep;
00271 
00272         ret = 0;
00273         dblp = dbenv->lg_handle;
00274         lp = dblp->reginfo.primary;
00275 
00276         R_LOCK(dbenv, &dblp->reginfo);
00277 
00278         /* Find the entry in the log. */
00279         for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
00280             fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname))
00281                 if (fid == fnp->id)
00282                         break;
00283         if (fnp == NULL) {
00284                 CDB___db_err(dbenv, "CDB_log_unregister: non-existent file id");
00285                 ret = EINVAL;
00286                 goto ret1;
00287         }
00288 
00289         /*
00290          * Log the unregistry only if this is the last one and we are
00291          * really closing the file or if this is an abort of a created
00292          * file and we need to make sure that there is a record in the
00293          * log.
00294          */
00295         namep = NULL;
00296         len = 0;
00297         if (fnp->name_off != INVALID_ROFF) {
00298                 namep = R_ADDR(&dblp->reginfo, fnp->name_off);
00299                 len = strlen(namep) + 1;
00300         }
00301         if (!F_ISSET(dblp, DBLOG_RECOVER) && fnp->ref == 1) {
00302                 if (namep != NULL) {
00303                         memset(&r_name, 0, sizeof(r_name));
00304                         r_name.data = namep;
00305                         r_name.size = len;
00306                 }
00307                 memset(&fid_dbt, 0, sizeof(fid_dbt));
00308                 fid_dbt.data = fnp->ufid;
00309                 fid_dbt.size = DB_FILE_ID_LEN;
00310                 if ((ret = CDB___log_register_log(dbenv, NULL, &r_unused,
00311                     0, LOG_CLOSE,
00312                     fnp->name_off == INVALID_ROFF ? NULL : &r_name,
00313                     &fid_dbt, fid, fnp->s_type, fnp->meta_pgno))
00314                     != 0)
00315                         goto ret1;
00316         }
00317 
00318         /*
00319          * If we are changing the name we must log this fact.
00320          */
00321         if (newname != NULL) {
00322                 DB_ASSERT(fnp->ref == 1);
00323                 newlen = strlen(newname) + 1;
00324                 if (!F_ISSET(dblp, DBLOG_RECOVER)) {
00325                         r_name.data = (void *) newname;
00326                         r_name.size = newlen;
00327                         if ((ret = CDB___log_register_log(dbenv,
00328                             NULL, &r_unused, 0, LOG_OPEN, &r_name, &fid_dbt,
00329                             fnp->id, fnp->s_type, fnp->meta_pgno)) != 0)
00330                                 goto ret1;
00331                 }
00332 
00333                 /*
00334                  * Check to see if the name is already correct.
00335                  */
00336                 if (set != NULL) {
00337                         if (len != newlen || memcmp(namep, newname, len) != 0)
00338                                 *set = 1;
00339                         else {
00340                                 *set = 0;
00341                                 goto ret1;
00342                         }
00343                 }
00344 
00345                 /*
00346                  * Change the name, realloc memory if necessary
00347                  */
00348                 if (len < newlen) {
00349                         CDB___db_shalloc_free(dblp->reginfo.addr,
00350                             R_ADDR(&dblp->reginfo, fnp->name_off));
00351                         if ((ret = CDB___db_shalloc(
00352                             dblp->reginfo.addr, newlen, 0, &namep)) != 0) {
00353                                 CDB___db_err(dbenv,
00354                                     "Unable to allocate memory to register %s",
00355                                     namep);
00356                                 goto ret1;
00357                         }
00358                         fnp->name_off = R_OFFSET(&dblp->reginfo, namep);
00359                 } else
00360                         namep = R_ADDR(&dblp->reginfo, fnp->name_off);
00361                 memcpy(namep, newname, newlen);
00362         } else {
00363 
00364                 /*
00365                  * If more than 1 reference, just decrement the reference
00366                  * and return.  Otherwise, free the name if one exists.
00367                  */
00368                 DB_ASSERT(fnp->ref >= 1);
00369                 --fnp->ref;
00370                 if (fnp->ref == 0) {
00371                         if (fnp->name_off != INVALID_ROFF)
00372                                 CDB___db_shalloc_free(dblp->reginfo.addr,
00373                                     R_ADDR(&dblp->reginfo, fnp->name_off));
00374                         fnp->name_off = INVALID_ROFF;
00375                 }
00376 
00377                 /*
00378                  * Remove from the process local table.  If this
00379                  * operation is taking place during recovery, then
00380                  * the logid was never added to the table, so do not remove it.
00381                  */
00382                 if (!F_ISSET(dblp, DBLOG_RECOVER))
00383                         CDB___log_rem_logid(dblp, dbp, fid);
00384         }
00385 
00386 ret1:   R_UNLOCK(dbenv, &dblp->reginfo);
00387         return (ret);
00388 }
00389 
00390 /*
00391  * CDB___log_file_lock -- lock a file for single access
00392  *      This only works if logging is on.
00393  *
00394  * PUBLIC: int CDB___log_file_lock __P((DB *));
00395  */
00396 int
00397 CDB___log_file_lock(dbp)
00398         DB *dbp;
00399 {
00400         DB_ENV *dbenv;
00401         DB_LOG *dblp;
00402         FNAME *found, *fnp;
00403         LOG *lp;
00404         int ret;
00405 
00406         dbenv = dbp->dbenv;
00407         dblp = dbenv->lg_handle;
00408         lp = dblp->reginfo.primary;
00409 
00410         found = NULL;
00411         ret = 0;
00412         R_LOCK(dbenv, &dblp->reginfo);
00413 
00414         for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
00415             fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
00416                 if (fnp->ref == 0)
00417                         continue;
00418 
00419                 if (!memcmp(dbp->fileid, fnp->ufid, DB_FILE_ID_LEN)) {
00420                         if (fnp->meta_pgno == 0) {
00421                                 if (fnp->ref != 1)
00422                                         goto err;
00423 
00424                                 fnp->locked = 1;
00425                                 found = fnp;
00426                         } else {
00427 err:                            CDB___db_err(dbp->dbenv, "File is open");
00428                                 ret = EINVAL;
00429                                 goto done;
00430                         }
00431 
00432                 }
00433         }
00434 done:   R_UNLOCK(dbenv, &dblp->reginfo);
00435         return (ret);
00436 }

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