db

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

AltStyle によって変換されたページ (->オリジナル) /