00001
00002
00003
00004
00005
00006
00007
00008 #include "config.h"
00009
00010 #ifndef lint
00011 static const char copyright[] =
00012 "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n";
00013 static const char revid[] =
00014 "$Id: env__recover_8c-source.html,v 1.1 2008/06/08 10:18:45 sebdiaz Exp $";
00015 #endif
00016
00017 #ifndef NO_SYSTEM_INCLUDES
00018 #include <sys/types.h>
00019
00020 #if TIME_WITH_SYS_TIME
00021 #include <sys/time.h>
00022 #include <time.h>
00023 #else
00024 #if HAVE_SYS_TIME_H
00025 #include <sys/time.h>
00026 #else
00027 #include <time.h>
00028 #endif
00029 #endif
00030
00031 #include <errno.h>
00032 #include <string.h>
00033 #endif
00034
00035 #include "db_int.h"
00036 #include "db_page.h"
00037 #include "db_dispatch.h"
00038 #include "db_am.h"
00039 #include "log.h"
00040 #include "txn.h"
00041
00042 static float __lsn_diff __P((DB_LSN *, DB_LSN *, DB_LSN *, u_int32_t, int));
00043 static int __log_earliest __P((DB_ENV *, int32_t *, DB_LSN *));
00044
00045
00046
00047
00048
00049
00050
00051 int
00052 CDB___db_apprec(dbenv, flags)
00053 DB_ENV *dbenv;
00054 u_int32_t flags;
00055 {
00056 DBT data;
00057 DB_LSN ckp_lsn, first_lsn, last_lsn, lowlsn, lsn, open_lsn;
00058 DB_TXNREGION *region;
00059 __txn_ckp_args *ckp_args;
00060 time_t now, tlow;
00061 float nfiles;
00062 int32_t low;
00063 int is_thread, progress, ret;
00064 void *txninfo;
00065
00066 COMPQUIET(nfiles, (float)0);
00067
00068
00069 if ((ret = CDB___db_txnlist_init(dbenv, &txninfo)) != 0)
00070 return (ret);
00071
00072
00073
00074
00075
00076 is_thread = F_ISSET(dbenv, DB_ENV_THREAD) ? 1 : 0;
00077 F_CLR(dbenv, DB_ENV_THREAD);
00078 F_SET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);
00079
00080
00081
00082
00083
00084 ZERO_LSN(lowlsn);
00085 if (dbenv->tx_timestamp != 0) {
00086 if ((ret = __log_earliest(dbenv, &low, &lowlsn)) != 0)
00087 return (ret);
00088 if ((int32_t)dbenv->tx_timestamp < low) {
00089 tlow = (time_t)low;
00090 CDB___db_err(dbenv, "%s (%s, %s).\n",
00091 "Invalid recovery timestamp specified",
00092 ctime(&tlow));
00093 return (EINVAL);
00094 }
00095 }
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 if (dbenv->db_feedback != NULL &&
00145 (ret = CDB_log_get(dbenv, &last_lsn, &data, DB_LAST)) != 0)
00146 goto out;
00147
00148
00149
00150
00151
00152
00153 memset(&data, 0, sizeof(data));
00154 ckp_args = NULL;
00155
00156 if (LF_ISSET(DB_RECOVER_FATAL)) {
00157 if ((ret = CDB_log_get(dbenv, &ckp_lsn, &data, DB_FIRST)) != 0) {
00158 if (ret == DB_NOTFOUND)
00159 ret = 0;
00160 else
00161 CDB___db_err(dbenv, "First log record not found");
00162 goto out;
00163 }
00164 open_lsn = ckp_lsn;
00165 } else if ((ret =
00166 CDB_log_get(dbenv, &ckp_lsn, &data, DB_CHECKPOINT)) != 0) {
00167
00168
00169
00170
00171
00172 first: if ((ret = CDB_log_get(dbenv, &ckp_lsn, &data, DB_FIRST)) != 0) {
00173 if (ret == DB_NOTFOUND)
00174 ret = 0;
00175 else
00176 CDB___db_err(dbenv, "First log record not found");
00177 goto out;
00178 }
00179 open_lsn = ckp_lsn;
00180 } else if ((ret = CDB___txn_ckp_read(dbenv, data.data, &ckp_args)) != 0) {
00181 CDB___db_err(dbenv, "Invalid checkpoint record at [%ld][%ld]\n",
00182 (u_long)ckp_lsn.file, (u_long)ckp_lsn.offset);
00183 goto out;
00184 } else if (IS_ZERO_LSN(ckp_args->last_ckp) ||
00185 (ret = CDB_log_get(dbenv, &ckp_args->last_ckp, &data, DB_SET)) != 0)
00186 goto first;
00187 else
00188 open_lsn = ckp_args->last_ckp;
00189
00190 if (dbenv->db_feedback != NULL) {
00191 if (last_lsn.file == open_lsn.file)
00192 nfiles = (float)(last_lsn.offset - open_lsn.offset) /
00193 dbenv->lg_max;
00194 else
00195 nfiles = (float)(last_lsn.file - open_lsn.file) +
00196 (float)(dbenv->lg_max - open_lsn.offset +
00197 last_lsn.offset) / dbenv->lg_max;
00198
00199 if (nfiles == 0)
00200 nfiles = (float)0.001;
00201 }
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 lsn = open_lsn;
00212 for (;;) {
00213 if (dbenv->db_feedback != NULL) {
00214 progress = (int)(33 * (__lsn_diff(&open_lsn,
00215 &last_lsn, &lsn, dbenv->lg_max, 1) / nfiles));
00216 dbenv->db_feedback(dbenv, DB_RECOVER, progress);
00217 }
00218 if (dbenv->tx_recover != NULL)
00219 ret = dbenv->tx_recover(dbenv,
00220 &data, &lsn, DB_TXN_OPENFILES, txninfo);
00221 else
00222 ret = CDB___db_dispatch(dbenv,
00223 &data, &lsn, DB_TXN_OPENFILES, txninfo);
00224 if (ret != 0 && ret != DB_TXN_CKP)
00225 goto msgerr;
00226 if ((ret = CDB_log_get(dbenv, &lsn, &data, DB_NEXT)) != 0) {
00227 if (ret == DB_NOTFOUND)
00228 break;
00229 goto out;
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 if (LF_ISSET(DB_RECOVER_FATAL)) {
00246 ZERO_LSN(first_lsn);
00247 } else if (dbenv->tx_timestamp != 0)
00248 first_lsn = lowlsn;
00249 else
00250 if ((ret = CDB___log_findckp(dbenv, &first_lsn)) == DB_NOTFOUND) {
00251
00252
00253
00254
00255 ret = 0;
00256 goto out;
00257 }
00258
00259 if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY))
00260 CDB___db_err(dbenv, "Recovery starting from [%lu][%lu]",
00261 (u_long)first_lsn.file, (u_long)first_lsn.offset);
00262
00263 for (ret = CDB_log_get(dbenv, &lsn, &data, DB_LAST);
00264 ret == 0 && CDB_log_compare(&lsn, &first_lsn) > 0;
00265 ret = CDB_log_get(dbenv, &lsn, &data, DB_PREV)) {
00266 if (dbenv->db_feedback != NULL) {
00267 progress = 34 + (int)(33 * (__lsn_diff(&open_lsn,
00268 &last_lsn, &lsn, dbenv->lg_max, 0) / nfiles));
00269 dbenv->db_feedback(dbenv, DB_RECOVER, progress);
00270 }
00271 if (dbenv->tx_recover != NULL)
00272 ret = dbenv->tx_recover(dbenv,
00273 &data, &lsn, DB_TXN_BACKWARD_ROLL, txninfo);
00274 else
00275 ret = CDB___db_dispatch(dbenv,
00276 &data, &lsn, DB_TXN_BACKWARD_ROLL, txninfo);
00277 if (ret != 0) {
00278 if (ret != DB_TXN_CKP)
00279 goto msgerr;
00280 else
00281 ret = 0;
00282 }
00283 }
00284 if (ret != 0 && ret != DB_NOTFOUND)
00285 goto out;
00286
00287
00288
00289
00290 for (ret = CDB_log_get(dbenv, &lsn, &data, DB_NEXT);
00291 ret == 0; ret = CDB_log_get(dbenv, &lsn, &data, DB_NEXT)) {
00292 if (dbenv->db_feedback != NULL) {
00293 progress = 67 + (int)(33 * (__lsn_diff(&open_lsn,
00294 &last_lsn, &lsn, dbenv->lg_max, 1) / nfiles));
00295 dbenv->db_feedback(dbenv, DB_RECOVER, progress);
00296 }
00297 if (dbenv->tx_recover != NULL)
00298 ret = dbenv->tx_recover(dbenv,
00299 &data, &lsn, DB_TXN_FORWARD_ROLL, txninfo);
00300 else
00301 ret = CDB___db_dispatch(dbenv,
00302 &data, &lsn, DB_TXN_FORWARD_ROLL, txninfo);
00303 if (ret != 0) {
00304 if (ret != DB_TXN_CKP)
00305 goto msgerr;
00306 else
00307 ret = 0;
00308 }
00309 }
00310 if (ret != DB_NOTFOUND)
00311 goto out;
00312
00313
00314
00315
00316
00317 (void)time(&now);
00318 region = ((DB_TXNMGR *)dbenv->tx_handle)->reginfo.primary;
00319 region->last_ckp = ckp_lsn;
00320 region->time_ckp = (u_int32_t)now;
00321
00322
00323
00324
00325
00326 if ((ret = CDB_txn_checkpoint(dbenv, 0, 0, DB_FORCE)) != 0)
00327 goto out;
00328
00329
00330 CDB___log_close_files(dbenv);
00331
00332 if ((ret = CDB_txn_checkpoint(dbenv, 0, 0, DB_FORCE)) != 0)
00333 goto out;
00334 region->last_txnid = TXN_MINIMUM;
00335
00336 if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY)) {
00337 CDB___db_err(dbenv, "Recovery complete at %.24s", ctime(&now));
00338 CDB___db_err(dbenv, "%s %lx %s [%lu][%lu]",
00339 "Maximum transaction ID",
00340 ((DB_TXNHEAD *)txninfo)->maxid,
00341 "Recovery checkpoint",
00342 (u_long)region->last_ckp.file,
00343 (u_long)region->last_ckp.offset);
00344 }
00345
00346 if (0) {
00347 msgerr: CDB___db_err(dbenv, "Recovery function for LSN %lu %lu failed",
00348 (u_long)lsn.file, (u_long)lsn.offset);
00349 }
00350
00351 out: if (is_thread)
00352 F_SET(dbenv, DB_ENV_THREAD);
00353 CDB___db_txnlist_end(dbenv, txninfo);
00354 if (ckp_args != NULL)
00355 CDB___os_free(ckp_args, sizeof(*ckp_args));
00356 F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);
00357
00358 dbenv->tx_timestamp = 0;
00359 return (ret);
00360 }
00361
00362
00363
00364
00365
00366
00367
00368 static float
00369 __lsn_diff(low, high, current, max, is_forward)
00370 DB_LSN *low, *high, *current;
00371 u_int32_t max;
00372 int is_forward;
00373 {
00374 float nf;
00375
00376
00377
00378
00379
00380
00381
00382
00383 if (is_forward) {
00384 if (current->file == low->file)
00385 nf = (float)(current->offset - low->offset) / max;
00386 else if (current->offset < low->offset)
00387 nf = (float)(current->file - low->file - 1) +
00388 (float)(max - low->offset + current->offset) / max;
00389 else
00390 nf = (float)(current->file - low->file) +
00391 (float)(current->offset - low->offset) / max;
00392 } else {
00393 if (current->file == high->file)
00394 nf = (float)(high->offset - current->offset) / max;
00395 else if (current->offset > high->offset)
00396 nf = (float)(high->file - current->file - 1) +
00397 (float)(max - current->offset + high->offset) / max;
00398 else
00399 nf = (float)(high->file - current->file) +
00400 (float)(high->offset - current->offset) / max;
00401 }
00402 return (nf);
00403 }
00404
00405
00406
00407
00408
00409
00410
00411
00412 static int
00413 __log_earliest(dbenv, lowtime, lowlsn)
00414 DB_ENV *dbenv;
00415 int32_t *lowtime;
00416 DB_LSN *lowlsn;
00417 {
00418 DB_LSN first_lsn, lsn;
00419 DBT data;
00420 __txn_ckp_args *ckpargs;
00421 u_int32_t rectype;
00422 int cmp, ret;
00423
00424 memset(&data, 0, sizeof(data));
00425
00426
00427
00428
00429
00430 for (ret = CDB_log_get(dbenv, &first_lsn, &data, DB_FIRST);
00431 ret == 0; ret = CDB_log_get(dbenv, &lsn, &data, DB_NEXT)) {
00432 if (ret != 0)
00433 break;
00434 memcpy(&rectype, data.data, sizeof(rectype));
00435 if (rectype != DB_txn_ckp)
00436 continue;
00437 if ((ret = CDB___txn_ckp_read(dbenv, data.data, &ckpargs)) == 0) {
00438 cmp = CDB_log_compare(&ckpargs->ckp_lsn, &first_lsn);
00439 *lowlsn = ckpargs->ckp_lsn;
00440 *lowtime = ckpargs->timestamp;
00441
00442 CDB___os_free(ckpargs, 0);
00443 if (cmp >= 0)
00444 break;
00445 }
00446 }
00447
00448 return (ret);
00449 }