00001
00002
00003
00004
00005
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
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
00042
00043
00044
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
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
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
00077 if (F_ISSET(&dblp->reginfo, REGION_CREATE) &&
00078 (ret = __log_init(dbenv, dblp)) != 0)
00079 goto err;
00080
00081
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
00090
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
00123
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(®ion->fq);
00147
00148
00149 region->lsn.file = 1;
00150 region->lsn.offset = 0;
00151
00152
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
00163
00164
00165
00166
00167 dblp->lfh.log_size = dbenv->lg_max;
00168
00169
00170 return (__log_recover(dblp));
00171 }
00172
00173
00174
00175
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
00191
00192
00193 if ((ret = CDB___log_find(dblp, 0, &cnt)) != 0)
00194 return (ret);
00195 if (cnt == 0)
00196 return (0);
00197
00198
00199
00200
00201
00202
00203
00204 lp->lsn.file = cnt + 1;
00205 lp->lsn.offset = 0;
00206 lsn.file = cnt;
00207 lsn.offset = 0;
00208
00209
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
00216
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
00231
00232
00233
00234 lp->lsn = lp->s_lsn = lsn;
00235 lp->lsn.offset += dblp->c_len;
00236
00237
00238 lp->len = dblp->c_len;
00239 lp->b_off = 0;
00240 lp->w_off = lp->lsn.offset;
00241
00242
00243
00244
00245
00246 if (!found_checkpoint && cnt > 1) {
00247 lsn.file = cnt;
00248 lsn.offset = 0;
00249
00250
00251 if ((ret = CDB___log_get(dblp, &lsn, &dbt, DB_SET, 0)) != 0)
00252 return (ret);
00253
00254
00255
00256
00257
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
00272 if (!found_checkpoint)
00273 ZERO_LSN(lp->chkpt_lsn);
00274
00275
00276
00277
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
00291
00292
00293
00294
00295
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
00308 *valp = 0;
00309
00310
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
00321 ret = CDB___os_dirlist(dblp->dbenv, dir, &names, &fcnt);
00322
00323
00324
00325
00326
00327
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
00340
00341
00342
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
00370
00371
00372
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
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
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
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
00430
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
00445
00446
00447
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
00460 F_SET(dblp, DBLOG_RECOVER);
00461 CDB___log_close_files(dbenv);
00462
00463
00464 if (dblp->mutexp != NULL)
00465 CDB___db_mutex_free(dbenv, &dblp->reginfo, dblp->mutexp);
00466
00467
00468 ret = CDB___db_r_detach(dbenv, &dblp->reginfo, 0);
00469
00470
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
00493
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
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 }