db

log.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_8c-source.html,v 1.1 2008年06月08日 10:20:08 sebdiaz Exp $";
00011 #endif /* not lint */
00012 
00013 #ifndef NO_SYSTEM_INCLUDES
00014 #include <sys/types.h>
00015 
00016 #include <errno.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include <unistd.h>
00020 #endif
00021 
00022 #ifdef HAVE_RPC
00023 #include "db_server.h"
00024 #endif
00025 
00026 #include "db_int.h"
00027 #include "log.h"
00028 #include "db_dispatch.h"
00029 #include "txn.h"
00030 #include "txn_auto.h"
00031 
00032 #ifdef HAVE_RPC
00033 #include "gen_client_ext.h"
00034 #include "rpc_client_ext.h"
00035 #endif
00036 
00037 static int __log_init __P((DB_ENV *, DB_LOG *));
00038 static int __log_recover __P((DB_LOG *));
00039 
00040 /*
00041  * CDB___log_open --
00042  * Internal version of log_open: only called from DB_ENV->open.
00043  *
00044  * PUBLIC: int CDB___log_open __P((DB_ENV *));
00045  */
00046 int
00047 CDB___log_open(dbenv)
00048 DB_ENV *dbenv;
00049 {
00050 DB_LOG *dblp;
00051 LOG *lp;
00052 int ret;
00053 u_int8_t *readbufp;
00054 
00055 readbufp = NULL;
00056 
00057 /* Create/initialize the DB_LOG structure. */
00058 if ((ret = CDB___os_calloc(dbenv, 1, sizeof(DB_LOG), &dblp)) != 0)
00059 return (ret);
00060 if ((ret = CDB___os_calloc(dbenv, 1, dbenv->lg_bsize, &readbufp)) != 0)
00061 goto err;
00062 ZERO_LSN(dblp->c_lsn);
00063 dblp->dbenv = dbenv;
00064 
00065 /* Join/create the log region. */
00066 dblp->reginfo.id = REG_ID_LOG;
00067 dblp->reginfo.mode = dbenv->db_mode;
00068 if (F_ISSET(dbenv, DB_ENV_CREATE))
00069 F_SET(&dblp->reginfo, REGION_CREATE_OK);
00070 if ((ret = CDB___db_r_attach(
00071 dbenv, &dblp->reginfo, LG_BASE_REGION_SIZE + dbenv->lg_bsize)) != 0)
00072 goto err;
00073 
00074 dblp->readbufp = readbufp;
00075 
00076 /* If we created the region, initialize it. */
00077 if (F_ISSET(&dblp->reginfo, REGION_CREATE) &&
00078 (ret = __log_init(dbenv, dblp)) != 0)
00079 goto err;
00080 
00081 /* Set the local addresses. */
00082 lp = dblp->reginfo.primary =
00083 R_ADDR(&dblp->reginfo, dblp->reginfo.rp->primary);
00084 dblp->bufp = R_ADDR(&dblp->reginfo, lp->buffer_off);
00085 
00086 R_UNLOCK(dbenv, &dblp->reginfo);
00087 
00088 /*
00089  * If the region is threaded, then we have to lock both the handles
00090  * and the region, and we need to allocate a mutex for that purpose.
00091  */
00092 if (F_ISSET(dbenv, DB_ENV_THREAD)) {
00093 if ((ret = CDB___db_mutex_alloc(
00094 dbenv, &dblp->reginfo, &dblp->mutexp)) != 0)
00095 goto detach;
00096 if ((ret = __db_mutex_init(
00097 dbenv, dblp->mutexp, 0, MUTEX_THREAD)) != 0)
00098 goto detach;
00099 }
00100 
00101 dblp->r_file = 0;
00102 dblp->r_off = 0;
00103 dblp->r_size = 0;
00104 dbenv->lg_handle = dblp;
00105 return (0);
00106 
00107 err: if (dblp->reginfo.addr != NULL) {
00108 if (F_ISSET(&dblp->reginfo, REGION_CREATE))
00109 F_SET(dblp->reginfo.rp, REG_DEAD);
00110 R_UNLOCK(dbenv, &dblp->reginfo);
00111 
00112 detach: (void)CDB___db_r_detach(dbenv, &dblp->reginfo, 0);
00113 }
00114 
00115 if (readbufp != NULL)
00116 CDB___os_free(readbufp, sizeof(dbenv->lg_bsize));
00117 CDB___os_free(dblp, sizeof(*dblp));
00118 return (ret);
00119 }
00120 
00121 /*
00122  * __log_init --
00123  * Initialize a log region in shared memory.
00124  */
00125 static int
00126 __log_init(dbenv, dblp)
00127 DB_ENV *dbenv;
00128 DB_LOG *dblp;
00129 {
00130 LOG *region;
00131 int ret;
00132 void *p;
00133 
00134 if ((ret = CDB___db_shalloc(dblp->reginfo.addr,
00135 sizeof(*region), 0, &dblp->reginfo.primary)) != 0)
00136 goto mem_err;
00137 dblp->reginfo.rp->primary =
00138 R_OFFSET(&dblp->reginfo, dblp->reginfo.primary);
00139 region = dblp->reginfo.primary;
00140 memset(region, 0, sizeof(*region));
00141 
00142 region->persist.lg_max = dbenv->lg_max;
00143 region->persist.magic = DB_LOGMAGIC;
00144 region->persist.version = DB_LOGVERSION;
00145 region->persist.mode = dbenv->db_mode;
00146 SH_TAILQ_INIT(&region->fq);
00147 
00148 /* Initialize LOG LSNs. */
00149 region->lsn.file = 1;
00150 region->lsn.offset = 0;
00151 
00152 /* Initialize the buffer. */
00153 if ((ret =
00154 CDB___db_shalloc(dblp->reginfo.addr, dbenv->lg_bsize, 0, &p)) != 0) {
00155 mem_err: CDB___db_err(dbenv, "Unable to allocate memory for the log buffer");
00156 return (ret);
00157 }
00158 region->buffer_size = dbenv->lg_bsize;
00159 region->buffer_off = R_OFFSET(&dblp->reginfo, p);
00160 
00161 /*
00162  * XXX:
00163  * Initialize the log file size. This is a hack to push the log's
00164  * maximum size down into the Windows CDB___os_open routine, because it
00165  * wants to pre-allocate it.
00166  */
00167 dblp->lfh.log_size = dbenv->lg_max;
00168 
00169 /* Try and recover any previous log files before releasing the lock. */
00170 return (__log_recover(dblp));
00171 }
00172 
00173 /*
00174  * __log_recover --
00175  * Recover a log.
00176  */
00177 static int
00178 __log_recover(dblp)
00179 DB_LOG *dblp;
00180 {
00181 DBT dbt;
00182 DB_LSN lsn;
00183 LOG *lp;
00184 u_int32_t chk;
00185 int cnt, found_checkpoint, ret;
00186 
00187 lp = dblp->reginfo.primary;
00188 
00189 /*
00190  * Find a log file. If none exist, we simply return, leaving
00191  * everything initialized to a new log.
00192  */
00193 if ((ret = CDB___log_find(dblp, 0, &cnt)) != 0)
00194 return (ret);
00195 if (cnt == 0)
00196 return (0);
00197 
00198 /*
00199  * We have the last useful log file and we've loaded any persistent
00200  * information. Set the end point of the log past the end of the last
00201  * file. Read the last file, looking for the last checkpoint and
00202  * the log's end.
00203  */
00204 lp->lsn.file = cnt + 1;
00205 lp->lsn.offset = 0;
00206 lsn.file = cnt;
00207 lsn.offset = 0;
00208 
00209 /* Set the cursor. Shouldn't fail, leave error messages on. */
00210 memset(&dbt, 0, sizeof(dbt));
00211 if ((ret = CDB___log_get(dblp, &lsn, &dbt, DB_SET, 0)) != 0)
00212 return (ret);
00213 
00214 /*
00215  * Read to the end of the file, saving checkpoints. This will fail
00216  * at some point, so turn off error messages.
00217  */
00218 found_checkpoint = 0;
00219 while (CDB___log_get(dblp, &lsn, &dbt, DB_NEXT, 1) == 0) {
00220 if (dbt.size < sizeof(u_int32_t))
00221 continue;
00222 memcpy(&chk, dbt.data, sizeof(u_int32_t));
00223 if (chk == DB_txn_ckp) {
00224 lp->chkpt_lsn = lsn;
00225 found_checkpoint = 1;
00226 }
00227 }
00228 
00229 /*
00230  * We now know where the end of the log is. Set the first LSN that
00231  * we want to return to an application and the LSN of the last known
00232  * record on disk.
00233  */
00234 lp->lsn = lp->s_lsn = lsn;
00235 lp->lsn.offset += dblp->c_len;
00236 
00237 /* Set up the current buffer information, too. */
00238 lp->len = dblp->c_len;
00239 lp->b_off = 0;
00240 lp->w_off = lp->lsn.offset;
00241 
00242 /*
00243  * It's possible that we didn't find a checkpoint because there wasn't
00244  * one in the last log file. Start searching.
00245  */
00246 if (!found_checkpoint && cnt > 1) {
00247 lsn.file = cnt;
00248 lsn.offset = 0;
00249 
00250 /* Set the cursor. Shouldn't fail, leave error messages on. */
00251 if ((ret = CDB___log_get(dblp, &lsn, &dbt, DB_SET, 0)) != 0)
00252 return (ret);
00253 
00254 /*
00255  * Read to the end of the file, saving checkpoints. Again,
00256  * this can fail if there are no checkpoints in any log file,
00257  * so turn error messages off.
00258  */
00259 while (CDB___log_get(dblp, &lsn, &dbt, DB_PREV, 1) == 0) {
00260 if (dbt.size < sizeof(u_int32_t))
00261 continue;
00262 memcpy(&chk, dbt.data, sizeof(u_int32_t));
00263 if (chk == DB_txn_ckp) {
00264 lp->chkpt_lsn = lsn;
00265 found_checkpoint = 1;
00266 break;
00267 }
00268 }
00269 }
00270 
00271 /* If we never find a checkpoint, that's okay, just 0 it out. */
00272 if (!found_checkpoint)
00273 ZERO_LSN(lp->chkpt_lsn);
00274 
00275 /*
00276  * Reset the cursor lsn to the beginning of the log, so that an
00277  * initial call to DB_NEXT does the right thing.
00278  */
00279 ZERO_LSN(dblp->c_lsn);
00280 
00281 if (FLD_ISSET(dblp->dbenv->verbose, DB_VERB_RECOVERY))
00282 CDB___db_err(dblp->dbenv,
00283 "Finding last valid log LSN: file: %lu offset %lu",
00284 (u_long)lp->lsn.file, (u_long)lp->lsn.offset);
00285 
00286 return (0);
00287 }
00288 
00289 /*
00290  * CDB___log_find --
00291  * Try to find a log file. If find_first is set, valp will contain
00292  * the number of the first log file, else it will contain the number of
00293  * the last log file.
00294  *
00295  * PUBLIC: int CDB___log_find __P((DB_LOG *, int, int *));
00296  */
00297 int
00298 CDB___log_find(dblp, find_first, valp)
00299 DB_LOG *dblp;
00300 int find_first, *valp;
00301 {
00302 u_int32_t clv, logval;
00303 int cnt, fcnt, ret;
00304 const char *dir;
00305 char **names, *p, *q;
00306 
00307 /* Return a value of 0 as the log file number on failure. */
00308 *valp = 0;
00309 
00310 /* Find the directory name. */
00311 if ((ret = CDB___log_name(dblp, 1, &p, NULL, 0)) != 0)
00312 return (ret);
00313 if ((q = CDB___db_rpath(p)) == NULL)
00314 dir = PATH_DOT;
00315 else {
00316 *q = '0円';
00317 dir = p;
00318 }
00319 
00320 /* Get the list of file names. */
00321 ret = CDB___os_dirlist(dblp->dbenv, dir, &names, &fcnt);
00322 
00323 /*
00324  * !!!
00325  * We overwrote a byte in the string with a nul. We have to restore
00326  * the string so that the diagnostic checks in the memory allocation
00327  * code work.
00328  */
00329 if (q != NULL)
00330 *q = 'a';
00331 
00332 if (ret != 0) {
00333 CDB___db_err(dblp->dbenv, "%s: %s", dir, CDB_db_strerror(ret));
00334 CDB___os_freestr(p);
00335 return (ret);
00336 }
00337 
00338 /*
00339  * Search for a valid log file name.
00340  *
00341  * XXX
00342  * Assumes that atoi(3) returns a 32-bit number.
00343  */
00344 for (cnt = fcnt, clv = logval = 0; --cnt >= 0;) {
00345 if (strncmp(names[cnt], LFPREFIX, sizeof(LFPREFIX) - 1) != 0)
00346 continue;
00347 
00348 clv = atoi(names[cnt] + (sizeof(LFPREFIX) - 1));
00349 if (find_first) {
00350 if (logval != 0 && clv > logval)
00351 continue;
00352 } else
00353 if (logval != 0 && clv < logval)
00354 continue;
00355 
00356 if (CDB___log_valid(dblp, clv, 1) == 0)
00357 logval = clv;
00358 }
00359 
00360 *valp = logval;
00361 
00362 CDB___os_dirfree(names, fcnt);
00363 CDB___os_freestr(p);
00364 
00365 return (0);
00366 }
00367 
00368 /*
00369  * log_valid --
00370  * Validate a log file.
00371  *
00372  * PUBLIC: int CDB___log_valid __P((DB_LOG *, u_int32_t, int));
00373  */
00374 int
00375 CDB___log_valid(dblp, number, set_persist)
00376 DB_LOG *dblp;
00377 u_int32_t number;
00378 int set_persist;
00379 {
00380 DB_FH fh;
00381 LOG *region;
00382 LOGP persist;
00383 size_t nw;
00384 int ret;
00385 char *fname;
00386 
00387 /* Try to open the log file. */
00388 if ((ret = CDB___log_name(dblp,
00389 number, &fname, &fh, DB_OSO_RDONLY | DB_OSO_SEQ)) != 0) {
00390 CDB___os_freestr(fname);
00391 return (ret);
00392 }
00393 
00394 /* Try to read the header. */
00395 if ((ret =
00396 CDB___os_seek(dblp->dbenv,
00397 &fh, 0, 0, sizeof(HDR), 0, DB_OS_SEEK_SET)) != 0 ||
00398 (ret =
00399 CDB___os_read(dblp->dbenv, &fh, &persist, sizeof(LOGP), &nw)) != 0 ||
00400 nw != sizeof(LOGP)) {
00401 if (ret == 0)
00402 ret = EIO;
00403 
00404 (void)CDB___os_closehandle(&fh);
00405 
00406 CDB___db_err(dblp->dbenv,
00407 "Ignoring log file: %s: %s", fname, CDB_db_strerror(ret));
00408 goto err;
00409 }
00410 (void)CDB___os_closehandle(&fh);
00411 
00412 /* Validate the header. */
00413 if (persist.magic != DB_LOGMAGIC) {
00414 CDB___db_err(dblp->dbenv,
00415 "Ignoring log file: %s: magic number %lx, not %lx",
00416 fname, (u_long)persist.magic, (u_long)DB_LOGMAGIC);
00417 ret = EINVAL;
00418 goto err;
00419 }
00420 if (persist.version < DB_LOGOLDVER || persist.version > DB_LOGVERSION) {
00421 CDB___db_err(dblp->dbenv,
00422 "Ignoring log file: %s: unsupported log version %lu",
00423 fname, (u_long)persist.version);
00424 ret = EINVAL;
00425 goto err;
00426 }
00427 
00428 /*
00429  * If we're going to use this log file, set the region's persistent
00430  * information based on the headers.
00431  */
00432 if (set_persist) {
00433 region = dblp->reginfo.primary;
00434 region->persist.lg_max = persist.lg_max;
00435 region->persist.mode = persist.mode;
00436 }
00437 ret = 0;
00438 
00439 err: CDB___os_freestr(fname);
00440 return (ret);
00441 }
00442 
00443 /*
00444  * CDB___log_close --
00445  * Internal version of log_close: only called from dbenv_refresh.
00446  *
00447  * PUBLIC: int CDB___log_close __P((DB_ENV *));
00448  */
00449 int
00450 CDB___log_close(dbenv)
00451 DB_ENV *dbenv;
00452 {
00453 DB_LOG *dblp;
00454 int ret, t_ret;
00455 
00456 ret = 0;
00457 dblp = dbenv->lg_handle;
00458 
00459 /* We may have opened files as part of XA; if so, close them. */
00460 F_SET(dblp, DBLOG_RECOVER);
00461 CDB___log_close_files(dbenv);
00462 
00463 /* Discard the per-thread lock. */
00464 if (dblp->mutexp != NULL)
00465 CDB___db_mutex_free(dbenv, &dblp->reginfo, dblp->mutexp);
00466 
00467 /* Detach from the region. */
00468 ret = CDB___db_r_detach(dbenv, &dblp->reginfo, 0);
00469 
00470 /* Close open files, release allocated memory. */
00471 if (F_ISSET(&dblp->lfh, DB_FH_VALID) &&
00472 (t_ret = CDB___os_closehandle(&dblp->lfh)) != 0 && ret == 0)
00473 ret = t_ret;
00474 if (dblp->c_dbt.data != NULL)
00475 CDB___os_free(dblp->c_dbt.data, dblp->c_dbt.ulen);
00476 if (F_ISSET(&dblp->c_fh, DB_FH_VALID) &&
00477 (t_ret = CDB___os_closehandle(&dblp->c_fh)) != 0 && ret == 0)
00478 ret = t_ret;
00479 if (dblp->dbentry != NULL)
00480 CDB___os_free(dblp->dbentry,
00481 (dblp->dbentry_cnt * sizeof(DB_ENTRY)));
00482 if (dblp->readbufp != NULL)
00483 CDB___os_free(dblp->readbufp, dbenv->lg_bsize);
00484 
00485 CDB___os_free(dblp, sizeof(*dblp));
00486 
00487 dbenv->lg_handle = NULL;
00488 return (ret);
00489 }
00490 
00491 /*
00492  * CDB_log_stat --
00493  * Return LOG statistics.
00494  */
00495 int
00496 CDB_log_stat(dbenv, statp, db_malloc)
00497 DB_ENV *dbenv;
00498 DB_LOG_STAT **statp;
00499 void *(*db_malloc) __P((size_t));
00500 {
00501 DB_LOG *dblp;
00502 DB_LOG_STAT *stats;
00503 LOG *region;
00504 int ret;
00505 
00506 #ifdef HAVE_RPC
00507 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00508 return (__dbcl_log_stat(dbenv, statp, db_malloc));
00509 #endif
00510 
00511 PANIC_CHECK(dbenv);
00512 ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG);
00513 
00514 *statp = NULL;
00515 
00516 dblp = dbenv->lg_handle;
00517 region = dblp->reginfo.primary;
00518 
00519 if ((ret = CDB___os_malloc(dbenv,
00520 sizeof(DB_LOG_STAT), db_malloc, &stats)) != 0)
00521 return (ret);
00522 
00523 /* Copy out the global statistics. */
00524 R_LOCK(dbenv, &dblp->reginfo);
00525 *stats = region->stat;
00526 
00527 stats->st_magic = region->persist.magic;
00528 stats->st_version = region->persist.version;
00529 stats->st_mode = region->persist.mode;
00530 stats->st_lg_bsize = region->buffer_size;
00531 stats->st_lg_max = region->persist.lg_max;
00532 
00533 stats->st_region_wait = dblp->reginfo.rp->mutex.mutex_set_wait;
00534 stats->st_region_nowait = dblp->reginfo.rp->mutex.mutex_set_nowait;
00535 stats->st_regsize = dblp->reginfo.rp->size;
00536 
00537 stats->st_cur_file = region->lsn.file;
00538 stats->st_cur_offset = region->lsn.offset;
00539 
00540 R_UNLOCK(dbenv, &dblp->reginfo);
00541 
00542 *statp = stats;
00543 return (0);
00544 }

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

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