2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved.
10 * This file contains helper functions like data structure and in-memory db
11 * management, which are used to store various log verification information.
13 #include "db_config.h"
16 #include "dbinc/crypto.h"
17 #include "dbinc/db_page.h"
18 #include "dbinc/db_am.h"
19 #include "dbinc/btree.h"
20 #include "dbinc/hash.h"
21 #include "dbinc/qam.h"
23 #include "dbinc/txn.h"
24 #include "dbinc/fop.h"
26 #include "dbinc/log_verify.h"
28 #define BDBOP(op) do { \
31 __lv_on_bdbop_err(ret); \
36 #define BDBOP2(dbenv, op, funct) do { \
39 __lv_on_bdbop_err(ret); \
40 __db_err(dbenv->env, ret, "\n%s", funct); \
45 #define BDBOP3(dbenv, op, excpt, funct) do { \
48 __lv_on_bdbop_err(ret); \
50 __db_err(dbenv->env, ret, "\n%s", funct); \
56 typedef int (*btcmp_funct)(DB *, const DBT *, const DBT *);
57 typedef int (*dupcmp_funct)(DB *, const DBT *, const DBT *);
59 static int __lv_add_recycle_handler __P((
60 DB_LOG_VRFY_INFO *, VRFY_TXN_INFO *, void *));
61 static int __lv_add_recycle_lsn __P((VRFY_TXN_INFO *, const DB_LSN *));
62 static size_t __lv_dbt_arrsz __P((const DBT *, u_int32_t));
63 static int __lv_fidpgno_cmp __P((DB *, const DBT *, const DBT *));
64 static int __lv_i32_cmp __P((DB *, const DBT *, const DBT *));
65 static int __lv_lsn_cmp __P((DB *, const DBT *, const DBT *));
66 static void __lv_on_bdbop_err __P((int));
67 static int __lv_open_db __P((DB_ENV *, DB **, DB_THREAD_INFO *,
68 const char *, int, btcmp_funct, u_int32_t, dupcmp_funct));
69 static int __lv_pack_filereg __P((const VRFY_FILEREG_INFO *, DBT *));
70 static int __lv_pack_txn_vrfy_info __P((
71 const VRFY_TXN_INFO *, DBT *, DBT *data));
72 static int __lv_seccbk_fname __P((DB *, const DBT *, const DBT *, DBT *));
73 static int __lv_seccbk_lsn __P((DB *, const DBT *, const DBT *, DBT *));
74 static int __lv_seccbk_txnpg __P((DB *, const DBT *, const DBT *, DBT *));
75 static void __lv_setup_logtype_names __P((DB_LOG_VRFY_INFO *lvinfo));
76 static int __lv_txnrgns_lsn_cmp __P((DB *, const DBT *, const DBT *));
77 static int __lv_ui32_cmp __P((DB *, const DBT *, const DBT *));
78 static int __lv_unpack_txn_vrfy_info __P((VRFY_TXN_INFO **, const DBT *));
79 static int __lv_unpack_filereg __P((const DBT *, VRFY_FILEREG_INFO **));
81 static void __lv_on_bdbop_err(ret)
84 /* Pass lint checks. We need the ret and this function for debugging. */
89 * __create_log_vrfy_info --
90 * Initialize and return a log verification handle to be used throughout
91 * a verification process.
93 * PUBLIC: int __create_log_vrfy_info __P((const DB_LOG_VERIFY_CONFIG *,
94 * PUBLIC: DB_LOG_VRFY_INFO **, DB_THREAD_INFO *));
97 __create_log_vrfy_info(cfg, lvinfopp, ip)
98 const DB_LOG_VERIFY_CONFIG *cfg;
99 DB_LOG_VRFY_INFO **lvinfopp;
104 u_int32_t cachesz, envflags;
105 const char *dbf1, *dbf2, *dbf3, *dbf4, *dbf5, *dbf6, *dbf7, *dbf8,
106 *dbf9, *dbf10, *dbf11;
107 DB_LOG_VRFY_INFO *lvinfop;
109 dbf1 = "__db_log_vrfy_txninfo.db";
110 dbf2 = "__db_log_vrfy_fileregs.db";
111 dbf3 = "__db_log_vrfy_pgtxn.db";
112 dbf4 = "__db_log_vrfy_lsntime.db";
113 dbf5 = "__db_log_vrfy_timelsn.db";
114 dbf6 = "__db_log_vrfy_ckps.db";
115 dbf7 = "__db_log_vrfy_dbregids.db";
116 dbf8 = "__db_log_vrfy_fnameuid.db";
117 dbf9 = "__db_log_vrfy_timerange.db";
118 dbf10 = "__db_log_vrfy_txnaborts.db";
119 dbf11 = "__db_log_vrfy_txnpg.db";
121 envhome = cfg->temp_envhome;
123 cachesz = cfg->cachesize;
125 cachesz = 1024 * 1024 * 256;
127 BDBOP(__os_malloc(NULL, sizeof(DB_LOG_VRFY_INFO), &lvinfop));
128 memset(lvinfop, 0, sizeof(DB_LOG_VRFY_INFO));
130 __lv_setup_logtype_names(lvinfop);
131 /* Avoid the VERIFY_PARTIAL bit being cleared if no ckp_lsn exists. */
132 lvinfop->valid_lsn.file = lvinfop->valid_lsn.offset = (u_int32_t)-1;
135 * The envhome parameter determines if we will use an in-memory
136 * environment and databases.
138 if (envhome == NULL) {
139 envflags = DB_PRIVATE;
146 /* Create log verify internal database environment. */
147 BDBOP(db_env_create(&lvinfop->dbenv, 0));
148 BDBOP(__memp_set_cachesize(lvinfop->dbenv, 0, cachesz, 1));
150 * Log verification internal db environment should be accessed
151 * single-threaded. No transaction semantics needed.
153 BDBOP(__env_open(lvinfop->dbenv, envhome,
154 envflags | DB_CREATE | DB_INIT_MPOOL, 0666));
156 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->txninfo, ip, dbf1,
157 inmem, __lv_ui32_cmp, 0, NULL));
158 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->fileregs, ip, dbf2,
159 inmem, NULL, 0, NULL));
161 /* No dup allowed, always overwrite data with same key. */
162 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->dbregids, ip, dbf7,
163 inmem, __lv_i32_cmp, 0, NULL));
164 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->pgtxn, ip, dbf3,
165 inmem, __lv_fidpgno_cmp, 0, NULL));
166 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->txnpg, ip, dbf11,
167 inmem, __lv_ui32_cmp, DB_DUP | DB_DUPSORT, __lv_fidpgno_cmp));
168 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->lsntime, ip, dbf4,
169 inmem, __lv_lsn_cmp, 0, NULL));
170 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->timelsn, ip, dbf5,
171 inmem, __lv_i32_cmp, DB_DUP | DB_DUPSORT, __lv_lsn_cmp));
172 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->txnaborts, ip, dbf10,
173 inmem, __lv_lsn_cmp, 0, NULL));
174 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->ckps, ip, dbf6,
175 inmem, __lv_lsn_cmp, 0, NULL));
176 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->fnameuid, ip, dbf8,
177 inmem, NULL, 0, NULL));
178 BDBOP(__lv_open_db(lvinfop->dbenv, &lvinfop->txnrngs, ip, dbf9,
179 inmem, __lv_ui32_cmp, DB_DUP | DB_DUPSORT, __lv_txnrgns_lsn_cmp));
181 BDBOP(__db_associate(lvinfop->lsntime, ip, NULL,
182 lvinfop->timelsn, __lv_seccbk_lsn, DB_CREATE));
183 BDBOP(__db_associate(lvinfop->fileregs, ip, NULL,
184 lvinfop->fnameuid, __lv_seccbk_fname, DB_CREATE));
185 BDBOP(__db_associate(lvinfop->pgtxn, ip, NULL,
186 lvinfop->txnpg, __lv_seccbk_txnpg, DB_CREATE));
192 if (lvinfop->dbenv && ret != 0)
193 __db_err(lvinfop->dbenv->env, ret, "__create_log_vrfy_info");
194 (void)__destroy_log_vrfy_info(lvinfop);
200 * __destroy_log_vrfy_info --
201 * Destroy and free a log verification handle.
203 * PUBLIC: int __destroy_log_vrfy_info __P((DB_LOG_VRFY_INFO *));
206 __destroy_log_vrfy_info(lvinfop)
207 DB_LOG_VRFY_INFO *lvinfop;
215 if (lvinfop->txnaborts != NULL &&
216 (ret = __db_close(lvinfop->txnaborts, NULL, 0)) != 0)
218 if (lvinfop->txninfo != NULL &&
219 (ret = __db_close(lvinfop->txninfo, NULL, 0)) != 0)
221 if (lvinfop->dbregids != NULL &&
222 (ret = __db_close(lvinfop->dbregids, NULL, 0)) != 0)
224 if (lvinfop->fileregs != NULL &&
225 (ret = __db_close(lvinfop->fileregs, NULL, 0)) != 0)
227 if (lvinfop->pgtxn != NULL &&
228 (ret = __db_close(lvinfop->pgtxn, NULL, 0)) != 0)
230 if (lvinfop->lsntime != NULL &&
231 (ret = __db_close(lvinfop->lsntime, NULL, 0)) != 0)
233 if (lvinfop->ckps != NULL &&
234 (ret = __db_close(lvinfop->ckps, NULL, 0)) != 0)
236 if (lvinfop->txnrngs != NULL &&
237 (ret = __db_close(lvinfop->txnrngs, NULL, 0)) != 0)
239 if (lvinfop->fnameuid != NULL &&
240 (ret = __db_close(lvinfop->fnameuid, NULL, 0)) != 0)
242 if (lvinfop->timelsn != NULL &&
243 (ret = __db_close(lvinfop->timelsn, NULL, 0)) != 0)
245 if (lvinfop->txnpg != NULL &&
246 (ret = __db_close(lvinfop->txnpg, NULL, 0)) != 0)
248 if (lvinfop->dbenv != NULL &&
249 (ret = __env_close(lvinfop->dbenv, 0)) != 0)
252 __os_free(NULL, lvinfop);
257 /* Secondary index callback function for DB_LOG_VRFY_INFO->timelsn. */
259 __lv_seccbk_fname(secdb, key, data, result)
266 VRFY_FILEREG_INFO *freg;
271 COMPQUIET(key, NULL);
272 if ((ret = __lv_unpack_filereg(data, &freg)) != 0)
274 if (freg->fname == NULL || (slen = strlen(freg->fname)) == 0) {
279 buflen = (slen + 1) * sizeof(char);
280 if ((ret = __os_umalloc(secdb->dbenv->env, buflen, &buf)) != 0)
282 (void)strcpy(buf, freg->fname);
283 result->size = (u_int32_t)buflen;
284 result->flags |= DB_DBT_APPMALLOC;
287 if (freg != NULL && (tret = __free_filereg_info(freg)) != 0 && ret == 0)
292 /* Secondary index callback function for DB_LOG_VRFY_INFO->txnpg. */
294 __lv_seccbk_txnpg(secdb, key, data, result)
300 COMPQUIET(key, NULL);
301 COMPQUIET(secdb, NULL);
302 /* Txnid is the secondary key, and it's all the data dbt has. */
303 result->data = data->data;
304 result->size = data->size;
309 /* Secondary index callback function for DB_LOG_VRFY_INFO->timelsn. */
311 __lv_seccbk_lsn(secdb, key, data, result)
317 VRFY_TIMESTAMP_INFO *lvti;
319 COMPQUIET(key, NULL);
320 COMPQUIET(secdb, NULL);
322 lvti = (VRFY_TIMESTAMP_INFO *)data->data;
323 result->data = &(lvti->timestamp);
324 result->size = sizeof(lvti->timestamp);
330 * Open a BTREE database handle, optionally set the btree compare function
334 __lv_open_db(dbenv, dbpp, ip, name, inmem, cmpf, sflags, dupcmpf)
341 dupcmp_funct dupcmpf;
345 const char *dbfname, *dbname;
358 BDBOP(db_create(&dbp, dbenv, 0));
361 BDBOP(__bam_set_bt_compare(dbp, cmpf));
363 dbp->dup_compare = dupcmpf;
365 BDBOP(__db_set_flags(dbp, sflags));
366 /* No concurrency needed, a big page size reduces overflow pages. */
367 BDBOP(__db_set_pagesize(dbp, 16 * 1024));
369 BDBOP(__db_open(dbp, ip, NULL, dbfname, dbname, DB_BTREE, DB_CREATE,
370 0666, PGNO_BASE_MD));
376 if (dbenv != NULL && ret != 0)
377 __db_err(dbenv->env, ret, "__lv_open_db");
379 (void)__db_close(dbp, NULL, 0);
384 /* Btree compare function for a [fileid, pgno] key. */
386 __lv_fidpgno_cmp(db, dbt1, dbt2)
391 db_pgno_t pgno1, pgno2;
396 len = DB_FILE_ID_LEN;
397 ret = memcmp(dbt1->data, dbt2->data, len);
399 memcpy(&pgno1, (u_int8_t *)dbt1->data + len,
401 memcpy(&pgno2, (u_int8_t *)dbt2->data + len,
403 ret = NUMCMP(pgno1, pgno2);
409 /* Btree compare function for a int32_t type of key. */
411 __lv_i32_cmp(db, dbt1, dbt2)
419 memcpy(&k1, dbt1->data, sizeof(k1));
420 memcpy(&k2, dbt2->data, sizeof(k2));
422 return (NUMCMP(k1, k2));
425 /* Btree compare function for a u_int32_t type of key. */
427 __lv_ui32_cmp(db, dbt1, dbt2)
435 memcpy(&k1, dbt1->data, sizeof(k1));
436 memcpy(&k2, dbt2->data, sizeof(k2));
438 return (NUMCMP(k1, k2));
441 /* Btree compare function for a DB_LSN type of key. */
443 __lv_lsn_cmp(db, dbt1, dbt2)
450 DB_ASSERT(db->env, dbt1->size == sizeof(DB_LSN));
451 DB_ASSERT(db->env, dbt2->size == sizeof(DB_LSN));
452 memcpy(&lsn1, dbt1->data, sizeof(DB_LSN));
453 memcpy(&lsn2, dbt2->data, sizeof(DB_LSN));
455 return (LOG_COMPARE(&lsn1, &lsn2));
459 * Structure management routines. We keep each structure on a
460 * consecutive memory chunk.
462 * The get functions will allocate memory via __os_malloc, and callers
463 * should free the memory after use. The update functions for VRFY_TXN_INFO
464 * and VRFY_FILEREG_INFO may realloc the structure.
468 * PUBLIC: int __put_txn_vrfy_info __P((const DB_LOG_VRFY_INFO *,
469 * PUBLIC: const VRFY_TXN_INFO *));
472 __put_txn_vrfy_info (lvinfo, txninfop)
473 const DB_LOG_VRFY_INFO *lvinfo;
474 const VRFY_TXN_INFO *txninfop;
479 ret = __lv_pack_txn_vrfy_info(txninfop, &key, &data);
480 DB_ASSERT(lvinfo->dbenv->env, ret == 0);
482 BDBOP2(lvinfo->dbenv, __db_put(lvinfo->txninfo, lvinfo->ip, NULL,
483 &key, &data, 0), "__put_txn_vrfy_info");
484 __os_free(lvinfo->dbenv->env, data.data);
489 /* Construct a key and data DBT from the structure. */
491 __lv_pack_txn_vrfy_info(txninfop, key, data)
492 const VRFY_TXN_INFO *txninfop;
501 memset(key, 0, sizeof(DBT));
502 memset(data, 0, sizeof(DBT));
504 bufsz = TXN_VERIFY_INFO_TOTSIZE(*txninfop);
506 if ((ret = __os_malloc(NULL, bufsz, &buf)) != 0)
508 memset(buf, 0, bufsz);
509 memcpy(buf, txninfop, TXN_VERIFY_INFO_FIXSIZE);
510 p = buf + TXN_VERIFY_INFO_FIXSIZE;
511 memcpy(p, txninfop->recycle_lsns, len = sizeof(DB_LSN) *
512 txninfop->num_recycle);
515 for (i = 0; i < txninfop->filenum; i++) {
517 pdbt = &(txninfop->fileups[i]);
518 memcpy(p, &(pdbt->size), sizeof(pdbt->size));
519 p += sizeof(pdbt->size);
520 memcpy(p, pdbt->data, pdbt->size);
524 key->data = (void *)&txninfop->txnid;
525 key->size = sizeof(txninfop->txnid);
527 data->size = (u_int32_t)bufsz;
528 data->flags |= DB_DBT_MALLOC;
533 /* Calculate a DBT array's total number of bytes to store. */
535 __lv_dbt_arrsz(arr, arrlen)
544 /* For each DBT object, store its size and its data bytes. */
545 for (i = 0; i < arrlen; i++)
546 sz += arr[i].size + sizeof(arr[i].size);
552 * __get_txn_vrfy_info --
553 * Get a VRFY_TXN_INFO object from db by txnid. Callers should free the
554 * object by calling __free_txninfo.
556 * PUBLIC: int __get_txn_vrfy_info __P((const DB_LOG_VRFY_INFO *, u_int32_t,
557 * PUBLIC: VRFY_TXN_INFO **));
560 __get_txn_vrfy_info (lvinfo, txnid, txninfopp)
561 const DB_LOG_VRFY_INFO *lvinfo;
563 VRFY_TXN_INFO **txninfopp;
568 memset(&key, 0, sizeof(DBT));
569 memset(&data, 0, sizeof(DBT));
571 key.size = sizeof(txnid);
573 BDBOP3(lvinfo->dbenv, __db_get(lvinfo->txninfo, lvinfo->ip, NULL,
574 &key, &data, 0), DB_NOTFOUND, "__get_txn_vrfy_info");
576 if (ret != DB_NOTFOUND)
577 ret = __lv_unpack_txn_vrfy_info(txninfopp, &data);
582 /* Construct a structure from a DBT. */
584 __lv_unpack_txn_vrfy_info(txninfopp, data)
585 VRFY_TXN_INFO **txninfopp;
589 VRFY_TXN_INFO *buf, *txninfop;
599 txninfop = (VRFY_TXN_INFO *)data->data;
600 lsns = (DB_LSN *)((char *)data->data + TXN_VERIFY_INFO_FIXSIZE);
601 pb = (char *)lsns + txninfop->num_recycle * sizeof(DB_LSN);
603 if ((ret = __os_malloc(NULL, bufsz = sizeof(VRFY_TXN_INFO), &buf)) != 0)
605 memset(buf, 0, bufsz);
606 memcpy(buf, data->data, TXN_VERIFY_INFO_FIXSIZE);
608 if (txninfop->num_recycle != 0) {
609 if ((ret = __os_malloc(NULL,
610 txninfop->num_recycle * sizeof(DB_LSN), &p)) != 0)
612 memcpy(p, lsns, txninfop->num_recycle * sizeof(DB_LSN));
613 buf->recycle_lsns = p;
616 if (txninfop->filenum != 0) {
617 if ((ret = __os_malloc(NULL,
618 txninfop->filenum * sizeof(DBT), &q)) != 0)
620 memset(q, 0, txninfop->filenum * sizeof(DBT));
621 buf->fileups = (DBT *)q;
622 for (i = 0; i < txninfop->filenum; i++) {
623 memcpy(&sz, pb, sizeof(sz));
625 if ((ret = __os_malloc(NULL, sz, &q)) != 0)
630 buf->fileups[i].data = q;
631 buf->fileups[i].size = sz;
641 __lv_add_recycle_lsn (txninfop, lsn)
642 VRFY_TXN_INFO *txninfop;
648 txninfop->num_recycle++;
649 if ((ret = __os_realloc(NULL, txninfop->num_recycle * sizeof(DB_LSN),
650 &(txninfop->recycle_lsns))) != 0)
652 txninfop->recycle_lsns[txninfop->num_recycle - 1] = *lsn;
658 * __add_recycle_lsn_range --
659 * Add recycle info for each txn within the recycled txnid range.
661 * PUBLIC: int __add_recycle_lsn_range __P((DB_LOG_VRFY_INFO *,
662 * PUBLIC: const DB_LSN *, u_int32_t, u_int32_t));
665 __add_recycle_lsn_range(lvinfo, lsn, min, max)
666 DB_LOG_VRFY_INFO *lvinfo;
674 struct __add_recycle_params param;
678 memset(&key2, 0, sizeof(DBT));
679 memset(&data2, 0, sizeof(DBT));
680 memset(¶m, 0, sizeof(param));
682 if ((ret = __os_malloc(lvinfo->dbenv->env, sizeof(VRFY_TXN_INFO *) *
683 (param.ti2ul = 1024), &(param.ti2u))) != 0)
686 param.recycle_lsn = *lsn;
690 /* Iterate the specified range and process each transaction. */
691 if ((ret = __iterate_txninfo(lvinfo, min, max, __lv_add_recycle_handler,
696 * Save updated txninfo structures. We can't do so in the above
697 * iteration, so we have to save them here.
699 BDBOP(__db_cursor(lvinfo->txninfo, lvinfo->ip, NULL, &csr, DBC_BULK));
701 for (i = 0; i < param.ti2ui; i++) {
702 ret = __lv_pack_txn_vrfy_info(param.ti2u[i], &key2, &data2);
703 DB_ASSERT(lvinfo->dbenv->env, ret == 0);
704 BDBOP(__dbc_put(csr, &key2, &data2, DB_KEYLAST));
706 * key2.data refers to param.ti2u[i]'s memory, data2.data is
707 * freed by DB since we set DB_DBT_MALLOC.
709 if ((ret = __free_txninfo(param.ti2u[i])) != 0)
714 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
716 __os_free(lvinfo->dbenv->env, param.ti2u);
718 __db_err(lvinfo->dbenv->env, ret,
719 "__add_recycle_lsn_range");
725 * __iterate_txninfo --
726 * Iterate throught the transaction info database as fast as possible,
727 * and process each key/data pair using a callback handler. Break the
728 * iteration if the handler returns non-zero values.
730 * PUBLIC: int __iterate_txninfo __P((DB_LOG_VRFY_INFO *, u_int32_t,
731 * PUBLIC: u_int32_t, TXNINFO_HANDLER, void *));
734 __iterate_txninfo(lvinfo, min, max, handler, param)
735 DB_LOG_VRFY_INFO *lvinfo;
737 TXNINFO_HANDLER handler;
741 VRFY_TXN_INFO *txninfop;
743 u_int32_t bufsz, pgsz, txnid;
746 u_int8_t *retk, *retd;
747 DBT key, data, data2;
752 env = lvinfo->dbenv->env;
761 memset(&key, 0, sizeof(DBT));
762 memset(&data, 0, sizeof(DBT));
763 memset(&data2, 0, sizeof(DBT));
765 pgsz = lvinfo->txninfo->pgsize;
766 DB_ASSERT(env, ret == 0);
768 if (bufsz % pgsz != 0)
769 bufsz = pgsz * (bufsz / pgsz);
771 if ((ret = __os_malloc(env, bufsz, &btbuf)) != 0)
774 BDBOP(__db_cursor(lvinfo->txninfo, lvinfo->ip, NULL, &csr, DBC_BULK));
777 * Use bulk retrieval to scan the database as fast as possible.
781 data.flags |= DB_DBT_USERMEM;
783 for (ret = __dbc_get(csr, &key, &data, DB_FIRST | DB_MULTIPLE_KEY) ;;
784 ret = __dbc_get(csr, &key, &data, DB_NEXT | DB_MULTIPLE_KEY)) {
790 /* No break statement allowed by lint here. */
791 case DB_BUFFER_SMALL:
792 if ((ret = __os_realloc(lvinfo->dbenv->env,
793 bufsz *= 2, &btbuf)) != 0)
797 continue;/* Continue the for-loop. */
798 /* No break statement allowed by lint here. */
804 * Do bulk get. Some txninfo objects may be updated by the
805 * handler, but we can't store them immediately in the same
806 * loop because we wouldn't be able to continue the bulk get
807 * using the same cursor; and we can't use another cursor
808 * otherwise we may self-block. In the handler we need to
809 * store the updated objects and store them to db when we get
812 DB_MULTIPLE_INIT(p, &data);
814 DB_MULTIPLE_KEY_NEXT(p, &data,
815 retk, retkl, retd, retdl);
818 DB_ASSERT(env, retkl == sizeof(txnid) && retk != NULL);
819 memcpy(&txnid, retk, retkl);
821 * Process it if txnid in range or no range specified.
822 * The range must be a closed one.
824 if ((min != 0 && txnid >= min && max != 0 &&
825 txnid <= max) || (min == 0 && max == 0)) {
827 data2.size = (u_int32_t)retdl;
829 if ((ret = __lv_unpack_txn_vrfy_info(
830 &txninfop, &data2)) != 0)
832 if ((ret = handler(lvinfo, txninfop,
834 /* Stop the iteration on error. */
841 if (ret == DB_NOTFOUND)
844 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
846 __os_free(lvinfo->dbenv->env, btbuf);
850 /* Txninfo iteration handler to add recycle info for affected txns. */
852 __lv_add_recycle_handler(lvinfo, txninfop, params)
853 DB_LOG_VRFY_INFO *lvinfo;
854 VRFY_TXN_INFO *txninfop;
858 struct __add_recycle_params *param;
861 param = (struct __add_recycle_params *)params;
864 * If the txnid is reused, update its recycle info and note it for
865 * later update, otherwise free the txninfop structure.
867 if (txninfop->txnid < param->min && txninfop->txnid > param->max) {
868 ret = __free_txninfo(txninfop);
872 ret = __lv_add_recycle_lsn(txninfop, &(param->recycle_lsn));
877 * Below is one way to tell if a txn is aborted without doing another
878 * backward pass of the log. However if the txn id is not in the
879 * chosen recycled txn id range, we can't tell, until all the log
880 * records are passed --- the remaining active txns are the aborted
882 * No longer needed since we did another backward pass of the log
883 * and have all the txn lifetimes.
884 if (txninfop->status == TXN_STAT_ACTIVE)
885 __on_txn_abort(lvinfo, txninfop);
887 if (txninfop->status == TXN_STAT_PREPARE) {
888 __db_errx(lvinfo->dbenv->env,
889 "[ERROR] Transaction with ID %u is prepared and not "
890 "committed, but its ID is recycled by log record [%u, %u].",
891 txninfop->txnid, param->recycle_lsn.file,
892 param->recycle_lsn.offset);
894 /* Note down to store later. */
895 param->ti2u[(param->ti2ui)++] = txninfop;
896 if (param->ti2ui == param->ti2ul)
897 BDBOP(__os_realloc(lvinfo->dbenv->env,
898 sizeof(VRFY_TXN_INFO *) * (param->ti2ul *= 2),
905 * PUBLIC: int __rem_last_recycle_lsn __P((VRFY_TXN_INFO *));
908 __rem_last_recycle_lsn(txninfop)
909 VRFY_TXN_INFO *txninfop;
914 if (txninfop->num_recycle == 0)
916 txninfop->num_recycle--;
917 if (txninfop->num_recycle > 0)
918 BDBOP(__os_realloc(NULL, txninfop->num_recycle * sizeof(DB_LSN),
919 &(txninfop->recycle_lsns)));
921 __os_free(NULL, txninfop->recycle_lsns);
922 txninfop->recycle_lsns = NULL;
930 * __add_file_updated --
931 * Add a file's dbregid and uid to the updating txn if it's not yet
934 * PUBLIC: int __add_file_updated __P((VRFY_TXN_INFO *, const DBT *, int32_t));
937 __add_file_updated (txninfop, fileid, dbregid)
938 VRFY_TXN_INFO *txninfop;
949 for (found = 0, i = 0; i < txninfop->filenum; i++) {
950 p = &(txninfop->fileups[i]);
951 if (p->size == fileid->size &&
952 memcmp(p->data, fileid->data, p->size) == 0) {
961 /* Add file's uid into the array, deep copy from fileid. */
963 if ((ret = __os_realloc(NULL, txninfop->filenum *
964 sizeof(DBT), &(txninfop->fileups))) != 0)
967 pdbt = &(txninfop->fileups[txninfop->filenum - 1]);
968 memset(pdbt, 0, sizeof(DBT));
969 if ((ret = __os_malloc(NULL,
970 pdbt->size = fileid->size, &(pdbt->data))) != 0)
972 memcpy(pdbt->data, fileid->data, fileid->size);
974 /* Add file dbregid into the array. */
975 BDBOP(__os_realloc(NULL, txninfop->filenum *
976 sizeof(int32_t), &(txninfop->dbregid)));
977 txninfop->dbregid[txninfop->filenum - 1] = dbregid;
983 * PUBLIC: int __del_file_updated __P((VRFY_TXN_INFO *, const DBT *));
986 __del_file_updated (txninfop, fileid)
987 VRFY_TXN_INFO *txninfop;
997 if (txninfop->filenum == 0)
1001 * If the array has an element identical to fileid, remove it. fileid
1002 * itself is intact after this function call.
1004 for (found = 0, i = 0, pdbtdata = NULL; i < txninfop->filenum; i++) {
1005 p = &(txninfop->fileups[i]);
1006 if (p->size == fileid->size &&
1007 memcmp(p->data, fileid->data, p->size) == 0) {
1009 if (txninfop->filenum > 1) {
1010 memmove(txninfop->fileups + i, txninfop->
1011 fileups + i + 1, sizeof(DBT) * (txninfop->
1012 filenum - (i + 1)));
1013 memmove(txninfop->dbregid + i, txninfop->
1014 dbregid + i + 1, sizeof(int32_t) *
1015 (txninfop->filenum - (i + 1)));
1017 __os_free(NULL, txninfop->fileups);
1018 __os_free(NULL, txninfop->dbregid);
1019 txninfop->fileups = NULL;
1020 txninfop->dbregid = NULL;
1028 txninfop->filenum--;
1029 if (txninfop->filenum) {
1030 BDBOP(__os_realloc(NULL, sizeof(DBT) *
1031 txninfop->filenum, &(txninfop->fileups)));
1032 BDBOP(__os_realloc(NULL, sizeof(int32_t) *
1033 txninfop->filenum, &(txninfop->dbregid)));
1035 __os_free(NULL, pdbtdata);
1042 * PUBLIC: int __clear_fileups __P((VRFY_TXN_INFO *));
1045 __clear_fileups(txninfop)
1046 VRFY_TXN_INFO *txninfop;
1050 for (i = 0; i < txninfop->filenum; i++)
1051 __os_free(NULL, txninfop->fileups[i].data);
1053 __os_free(NULL, txninfop->fileups);
1054 __os_free(NULL, txninfop->dbregid);
1055 txninfop->fileups = NULL;
1056 txninfop->dbregid = NULL;
1057 txninfop->filenum = 0;
1063 * __free_txninfo_stack --
1064 * The object is on stack, only free its internal memory, not itself.
1065 * PUBLIC: int __free_txninfo_stack __P((VRFY_TXN_INFO *));
1068 __free_txninfo_stack (p)
1076 if (p->fileups != NULL) {
1077 for (i = 0; i < p->filenum; i++)
1078 __os_free(NULL, p->fileups[i].data);
1079 __os_free(NULL, p->fileups);
1082 if (p->dbregid != NULL)
1083 __os_free(NULL, p->dbregid);
1085 if (p->recycle_lsns != NULL)
1086 __os_free(NULL, p->recycle_lsns);
1091 * PUBLIC: int __free_txninfo __P((VRFY_TXN_INFO *));
1097 (void)__free_txninfo_stack(p);
1103 /* Construct a key and data DBT from the structure. */
1105 __lv_pack_filereg(freginfo, data)
1106 const VRFY_FILEREG_INFO *freginfo;
1110 size_t bufsz, offset;
1114 if ((ret = __os_malloc(NULL,
1115 bufsz = FILE_REG_INFO_TOTSIZE(*freginfo), &buf)) != 0)
1117 memset(buf, 0, bufsz);
1119 memcpy(buf, freginfo, FILE_REG_INFO_FIXSIZE);
1120 p = buf + FILE_REG_INFO_FIXSIZE;
1122 offset = sizeof(int32_t) * freginfo->regcnt;
1123 memcpy(p, freginfo->dbregids, offset);
1126 memcpy(p, &(freginfo->fileid.size), sizeof(freginfo->fileid.size));
1127 p += sizeof(freginfo->fileid.size);
1128 memcpy(p, freginfo->fileid.data, freginfo->fileid.size);
1129 p += freginfo->fileid.size;
1130 (void)strcpy(p, freginfo->fname);
1133 data->size = (u_int32_t)bufsz;
1139 * PUBLIC: int __put_filereg_info __P((const DB_LOG_VRFY_INFO *,
1140 * PUBLIC: const VRFY_FILEREG_INFO *));
1142 int __put_filereg_info (lvinfo, freginfo)
1143 const DB_LOG_VRFY_INFO *lvinfo;
1144 const VRFY_FILEREG_INFO *freginfo;
1150 memset(&data, 0, sizeof(DBT));
1152 if ((ret = __lv_pack_filereg(freginfo, &data)) != 0)
1156 * We store dbregid-filereg map into dbregids.db, but we can't make
1157 * dbregids.db the sec db of fileregs.db, because dbregid is only
1158 * valid when a db file is open, we want to delete data with same
1159 * key in dbregids.db, but we want to keep all filereg_info data in
1160 * fileregs.db to track all db file lifetime and status.
1162 * Consequently we will store dbregid-file_uid in dbregs.db, so that we
1163 * can delete dbregid when the db handle is closed, and we can
1164 * use the dbregid to get the currently open db file's uid.
1167 BDBOP2(lvinfo->dbenv, __db_put(lvinfo->fileregs, lvinfo->ip, NULL,
1168 (DBT *)&(freginfo->fileid), &data, 0), "__put_filereg_info");
1171 if (data.data != NULL)
1172 __os_free(lvinfo->dbenv->env, data.data);
1178 * PUBLIC: int __del_filelife __P((const DB_LOG_VRFY_INFO *, int32_t));
1181 __del_filelife(lvinfo, dbregid)
1182 const DB_LOG_VRFY_INFO *lvinfo;
1188 memset(&key, 0, sizeof(DBT));
1189 key.data = &(dbregid);
1190 key.size = sizeof(dbregid);
1192 if ((ret = __db_del(lvinfo->dbregids, lvinfo->ip, NULL,
1201 * PUBLIC: int __put_filelife __P((const DB_LOG_VRFY_INFO *, VRFY_FILELIFE *));
1204 __put_filelife (lvinfo, pflife)
1205 const DB_LOG_VRFY_INFO *lvinfo;
1206 VRFY_FILELIFE *pflife;
1211 memset(&key, 0, sizeof(DBT));
1212 memset(&data, 0, sizeof(DBT));
1213 key.data = &(pflife->dbregid);
1214 key.size = sizeof(pflife->dbregid);
1216 data.size = sizeof(VRFY_FILELIFE);
1218 if ((ret = __db_put(lvinfo->dbregids, lvinfo->ip, NULL,
1219 &key, &data, 0)) != 0)
1227 * PUBLIC: int __get_filelife __P((const DB_LOG_VRFY_INFO *,
1228 * PUBLIC: int32_t, VRFY_FILELIFE **));
1231 __get_filelife (lvinfo, dbregid, flifepp)
1232 const DB_LOG_VRFY_INFO *lvinfo;
1234 VRFY_FILELIFE **flifepp;
1238 VRFY_FILELIFE *flifep;
1242 memset(&key, 0, sizeof(DBT));
1243 memset(&data, 0, sizeof(DBT));
1245 key.data = &dbregid;
1246 key.size = sizeof(dbregid);
1247 if ((ret = __db_get(lvinfo->dbregids, lvinfo->ip, NULL,
1248 &key, &data, 0)) != 0)
1250 if ((ret = __os_malloc(lvinfo->dbenv->env,
1251 sizeof(VRFY_FILELIFE), &flifep)) != 0)
1253 DB_ASSERT(lvinfo->dbenv->env, flifep != NULL);
1254 memcpy(flifep, data.data, sizeof(VRFY_FILELIFE));
1261 * PUBLIC: int __get_filereg_by_dbregid __P((const DB_LOG_VRFY_INFO *,
1262 * PUBLIC: int32_t, VRFY_FILEREG_INFO **));
1265 __get_filereg_by_dbregid(lvinfo, dbregid, freginfopp)
1266 const DB_LOG_VRFY_INFO *lvinfo;
1268 VRFY_FILEREG_INFO **freginfopp;
1272 char uid[DB_FILE_ID_LEN];
1273 VRFY_FILELIFE *pflife;
1275 memset(&data, 0, sizeof(DBT));
1276 memset(&key, 0, sizeof(DBT));
1277 key.data = &dbregid;
1278 key.size = sizeof(dbregid);
1280 BDBOP3(lvinfo->dbenv, __db_get(lvinfo->dbregids, lvinfo->ip, NULL,
1281 &key, &data, 0), DB_NOTFOUND, "__get_filereg_by_dbregid");
1282 if (ret == DB_NOTFOUND)
1285 /* Use the file-uid as key to retrieve from fileregs.db. */
1286 pflife = (VRFY_FILELIFE *)data.data;
1287 memcpy((void *)uid, (void *)pflife->fileid, key.size = DB_FILE_ID_LEN);
1289 key.data = (void *)uid;
1290 memset(&data, 0, sizeof(DBT));
1292 BDBOP3(lvinfo->dbenv, __db_get(lvinfo->fileregs, lvinfo->ip, NULL,
1293 &key, &data, 0), DB_NOTFOUND, "__get_filereg_by_dbregid");
1294 if (ret == DB_NOTFOUND)
1296 if ((ret = __lv_unpack_filereg(&data, freginfopp)) != 0)
1304 * PUBLIC: int __add_dbregid __P((DB_LOG_VRFY_INFO *, VRFY_FILEREG_INFO *,
1305 * PUBLIC: int32_t, u_int32_t, DB_LSN, DBTYPE, db_pgno_t, int *));
1308 __add_dbregid(lvh, freg, dbregid, opcode, lsn, dbtype, meta_pgno, addp)
1309 DB_LOG_VRFY_INFO *lvh;
1310 VRFY_FILEREG_INFO *freg;
1315 db_pgno_t meta_pgno;
1318 int inarray, ret, tret;
1320 VRFY_FILELIFE flife;
1322 inarray = ret = tret = 0;
1323 for (i = 0; i < freg->regcnt; i++) {
1324 if (freg->dbregids[i] == dbregid) {
1325 if (!IS_DBREG_CLOSE(opcode)) {
1326 /* Opening an open dbreg id. */
1327 if (IS_DBREG_OPEN(opcode) &&
1328 (opcode != DBREG_CHKPNT &&
1329 opcode != DBREG_XCHKPNT)) {
1336 /* Found the dbregid; gonna remove it. */
1342 if (IS_DBREG_OPEN(opcode))
1343 tret = 1;/* dbregid not in the array, gonna add 1. */
1346 * Remove closed dbregid. dbregid can be recycled, not unique to a db
1347 * file, it's dynamically allocated for each db handle.
1350 for (j = i; j < freg->regcnt - 1; j++)
1351 freg->dbregids[j] = freg->dbregids[j + 1];
1353 BDBOP(__os_realloc(lvh->dbenv->env,
1354 sizeof(int32_t) * freg->regcnt, &(freg->dbregids)));
1355 /* Don't remove dbregid life info from dbregids db. */
1356 } else if (tret == 1) {
1359 BDBOP(__os_realloc(lvh->dbenv->env,
1360 sizeof(int32_t) * freg->regcnt, &(freg->dbregids)));
1361 freg->dbregids[freg->regcnt - 1] = dbregid;
1363 flife.dbregid = dbregid;
1364 memcpy(flife.fileid, freg->fileid.data, freg->fileid.size);
1365 flife.lifetime = opcode;
1366 flife.dbtype = dbtype;
1368 flife.meta_pgno = meta_pgno;
1369 if ((ret = __put_filelife(lvh, &flife)) != 0)
1380 * PUBLIC: int __get_filereg_info __P((const DB_LOG_VRFY_INFO *, const DBT *,
1381 * PUBLIC: VRFY_FILEREG_INFO **));
1384 __get_filereg_info (lvinfo, fuid, freginfopp)
1385 const DB_LOG_VRFY_INFO *lvinfo;
1387 VRFY_FILEREG_INFO **freginfopp;
1392 memset(&data, 0, sizeof(DBT));
1394 BDBOP3(lvinfo->dbenv, __db_get(lvinfo->fileregs, lvinfo->ip, NULL,
1395 (DBT *)fuid, &data, 0), DB_NOTFOUND, "__get_filereg_info");
1396 if (ret == DB_NOTFOUND)
1398 if ((ret = __lv_unpack_filereg(&data, freginfopp)) != 0)
1406 __lv_unpack_filereg(data, freginfopp)
1408 VRFY_FILEREG_INFO **freginfopp;
1411 u_int32_t fidsz, arrsz;
1412 VRFY_FILEREG_INFO *buf;
1420 if ((ret = __os_malloc(NULL, sizeof(VRFY_FILEREG_INFO), &buf)) != 0)
1422 memset(buf, 0, sizeof(VRFY_FILEREG_INFO));
1424 memcpy(buf, data->data, FILE_REG_INFO_FIXSIZE);
1425 *freginfopp = (VRFY_FILEREG_INFO *)buf;
1426 p = ((char *)(data->data)) + FILE_REG_INFO_FIXSIZE;
1428 if ((ret = __os_malloc(NULL, arrsz = (*freginfopp)->regcnt *
1429 sizeof(int32_t), &((*freginfopp)->dbregids))) != 0)
1431 memcpy((*freginfopp)->dbregids, p, arrsz);
1434 memcpy(&fidsz, p, sizeof(fidsz));
1436 if ((ret = __os_malloc(NULL, fidsz, &q)) != 0)
1438 memcpy(q, p, fidsz);
1439 (*freginfopp)->fileid.data = q;
1440 (*freginfopp)->fileid.size = fidsz;
1443 if ((ret = __os_malloc(NULL, sizeof(char) * (strlen(p) + 1), &q)) != 0)
1447 (*freginfopp)->fname = q;
1453 * PUBLIC: int __free_filereg_info __P((VRFY_FILEREG_INFO *));
1456 __free_filereg_info(p)
1457 VRFY_FILEREG_INFO *p;
1461 if (p ->fname != NULL)
1462 __os_free(NULL, (void *)(p->fname));
1463 if (p->fileid.data != NULL)
1464 __os_free(NULL, p->fileid.data);
1465 if (p->dbregids != NULL)
1466 __os_free(NULL, p->dbregids);
1473 * PUBLIC: int __get_ckp_info __P((const DB_LOG_VRFY_INFO *, DB_LSN,
1474 * PUBLIC: VRFY_CKP_INFO **));
1477 __get_ckp_info (lvinfo, lsn, ckpinfopp)
1478 const DB_LOG_VRFY_INFO *lvinfo;
1480 VRFY_CKP_INFO **ckpinfopp;
1484 VRFY_CKP_INFO *ckpinfo;
1486 memset(&key, 0, sizeof(DBT));
1487 memset(&data, 0, sizeof(DBT));
1489 key.size = sizeof(DB_LSN);
1490 BDBOP3(lvinfo->dbenv, __db_get(lvinfo->ckps, lvinfo->ip, NULL,
1491 &key, &data, 0), DB_NOTFOUND, "__get_ckp_info");
1493 if (ret == DB_NOTFOUND)
1496 if ((ret = __os_malloc(lvinfo->dbenv->env,
1497 sizeof(VRFY_CKP_INFO), &ckpinfo)) != 0)
1499 memcpy(ckpinfo, data.data, sizeof(VRFY_CKP_INFO));
1500 *ckpinfopp = ckpinfo;
1507 * PUBLIC: int __get_last_ckp_info __P((const DB_LOG_VRFY_INFO *,
1508 * PUBLIC: VRFY_CKP_INFO **));
1511 __get_last_ckp_info (lvinfo, ckpinfopp)
1512 const DB_LOG_VRFY_INFO *lvinfo;
1513 VRFY_CKP_INFO **ckpinfopp;
1517 VRFY_CKP_INFO *ckpinfo;
1521 memset(&key, 0, sizeof(DBT));
1522 memset(&data, 0, sizeof(DBT));
1524 BDBOP(__db_cursor(lvinfo->ckps, lvinfo->ip, NULL, &csr, 0));
1525 if ((ret = __dbc_get(csr, &key, &data, DB_LAST)) != 0)
1528 if ((ret = __os_malloc(lvinfo->dbenv->env,
1529 sizeof(VRFY_CKP_INFO), &ckpinfo)) != 0)
1531 DB_ASSERT(lvinfo->dbenv->env, sizeof(VRFY_CKP_INFO) == data.size);
1532 memcpy(ckpinfo, data.data, sizeof(VRFY_CKP_INFO));
1533 *ckpinfopp = ckpinfo;
1535 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1537 if (ret != 0 && ret != DB_NOTFOUND)
1538 __db_err(lvinfo->dbenv->env, ret, "__get_last_ckp_info");
1543 * PUBLIC: int __put_ckp_info __P((const DB_LOG_VRFY_INFO *,
1544 * PUBLIC: const VRFY_CKP_INFO *));
1546 int __put_ckp_info (lvinfo, ckpinfo)
1547 const DB_LOG_VRFY_INFO *lvinfo;
1548 const VRFY_CKP_INFO *ckpinfo;
1553 memset(&key, 0, sizeof(DBT));
1554 memset(&data, 0, sizeof(DBT));
1555 key.data = (void *)&ckpinfo->lsn;
1556 key.size = sizeof(DB_LSN);
1557 data.data = (void *)ckpinfo;
1558 data.size = sizeof(VRFY_CKP_INFO);
1560 BDBOP2(lvinfo->dbenv, __db_put(lvinfo->ckps, lvinfo->ip,
1561 NULL, &key, &data, 0), "__put_ckp_info");
1566 * PUBLIC: int __get_timestamp_info __P((const DB_LOG_VRFY_INFO *,
1567 * PUBLIC: DB_LSN, VRFY_TIMESTAMP_INFO **));
1569 int __get_timestamp_info (lvinfo, lsn, tsinfopp)
1570 const DB_LOG_VRFY_INFO *lvinfo;
1572 VRFY_TIMESTAMP_INFO **tsinfopp;
1576 VRFY_TIMESTAMP_INFO *tsinfo;
1578 memset(&key, 0, sizeof(DBT));
1579 memset(&data, 0, sizeof(DBT));
1581 key.size = sizeof(DB_LSN);
1582 BDBOP3(lvinfo->dbenv, __db_get(lvinfo->lsntime, lvinfo->ip, NULL,
1583 &key, &data, 0), DB_NOTFOUND, "__get_timestamp_info");
1585 if (ret == DB_NOTFOUND)
1588 if ((ret = __os_malloc(lvinfo->dbenv->env,
1589 sizeof(VRFY_TIMESTAMP_INFO), &tsinfo)) != 0)
1592 memcpy(tsinfo, data.data, sizeof(VRFY_TIMESTAMP_INFO));
1599 * __get_latest_timestamp_info --
1600 * Get latest timestamp info before lsn.
1601 * PUBLIC: int __get_latest_timestamp_info __P((const DB_LOG_VRFY_INFO *,
1602 * PUBLIC: DB_LSN, VRFY_TIMESTAMP_INFO **));
1604 int __get_latest_timestamp_info(lvinfo, lsn, tsinfopp)
1605 const DB_LOG_VRFY_INFO *lvinfo;
1607 VRFY_TIMESTAMP_INFO **tsinfopp;
1611 VRFY_TIMESTAMP_INFO *tsinfo;
1616 memset(&key, 0, sizeof(DBT));
1617 memset(&data, 0, sizeof(DBT));
1620 key.size = sizeof(lsn);
1621 BDBOP(__db_cursor(lvinfo->lsntime, lvinfo->ip, NULL, &csr, 0));
1623 BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1624 BDBOP(__dbc_get(csr, &key, &data, DB_PREV));
1626 if ((ret = __os_malloc(lvinfo->dbenv->env, sizeof(VRFY_TIMESTAMP_INFO),
1630 memcpy(tsinfo, data.data, sizeof(VRFY_TIMESTAMP_INFO));
1634 if (ret != 0 && ret != DB_NOTFOUND)
1635 __db_err(lvinfo->dbenv->env,
1636 ret, "__get_latest_timestamp_info");
1637 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1643 * PUBLIC: int __put_timestamp_info __P((const DB_LOG_VRFY_INFO *,
1644 * PUBLIC: const VRFY_TIMESTAMP_INFO *));
1646 int __put_timestamp_info (lvinfo, tsinfo)
1647 const DB_LOG_VRFY_INFO *lvinfo;
1648 const VRFY_TIMESTAMP_INFO *tsinfo;
1653 memset(&key, 0, sizeof(DBT));
1654 memset(&data, 0, sizeof(DBT));
1655 key.data = (void *)&(tsinfo->lsn);
1656 key.size = sizeof(DB_LSN);
1657 data.data = (void *)tsinfo;
1658 data.size = sizeof(VRFY_TIMESTAMP_INFO);
1659 BDBOP2(lvinfo->dbenv, __db_put(lvinfo->lsntime, lvinfo->ip, NULL,
1660 &key, &data, 0), "__put_timestamp_info");
1666 __lv_txnrgns_lsn_cmp (db, d1, d2)
1670 struct __lv_txnrange r1, r2;
1672 DB_ASSERT(db->env, d1->size == sizeof(r1));
1673 DB_ASSERT(db->env, d2->size == sizeof(r2));
1674 memcpy(&r1, d1->data, d1->size);
1675 memcpy(&r2, d2->data, d2->size);
1677 return (LOG_COMPARE(&(r1.end), &(r2.end)));
1681 * __find_lsnrg_by_timerg --
1682 * Find the lsn closed interval [beginlsn, endlsn] so that the
1683 * corresponding timestamp interval fully contains interval [begin, end].
1684 * PUBLIC: int __find_lsnrg_by_timerg __P((DB_LOG_VRFY_INFO *,
1685 * PUBLIC: time_t, time_t, DB_LSN *, DB_LSN *));
1688 __find_lsnrg_by_timerg(lvinfo, begin, end, startlsn, endlsn)
1689 DB_LOG_VRFY_INFO *lvinfo;
1691 DB_LSN *startlsn, *endlsn;
1695 struct __lv_timestamp_info *t1, *t2;
1700 memset(&key, 0, sizeof(DBT));
1701 memset(&data, 0, sizeof(DBT));
1703 BDBOP(__db_cursor(lvinfo->timelsn, lvinfo->ip, NULL, &csr, 0));
1706 * We want a lsn range that completely contains [begin, end], so
1707 * try move 1 record prev when getting the startlsn.
1710 key.size = sizeof(begin);
1711 BDBOP(__dbc_get(csr, &key, &data, DB_SET_RANGE));
1712 if ((ret = __dbc_get(csr, &key, &data, DB_PREV)) != 0 &&
1715 if (ret == DB_NOTFOUND)/* begin is smaller than the smallest key. */
1716 startlsn->file = startlsn->offset = 0;/* beginning. */
1718 t1 = (struct __lv_timestamp_info *)data.data;
1719 *startlsn = t1->lsn;
1723 * Move to the last key/data pair of the duplicate set to get the
1724 * biggest lsn having end as timestamp.
1727 key.size = sizeof(end);
1728 if ((ret = __dbc_get(csr, &key, &data, DB_SET_RANGE)) != 0 &&
1731 if (ret == DB_NOTFOUND) {
1732 endlsn->file = endlsn->offset = (u_int32_t)-1;/* Biggest lsn. */
1734 goto err; /* We are done. */
1738 * Go to the biggest lsn of the dup set, if the key is the last one,
1739 * go to the last one.
1741 if ((ret = __dbc_get(csr, &key, &data, DB_NEXT_NODUP)) != 0 &&
1745 if (ret == DB_NOTFOUND)
1746 BDBOP(__dbc_get(csr, &key, &data, DB_LAST));
1748 BDBOP(__dbc_get(csr, &key, &data, DB_PREV));
1750 t2 = (struct __lv_timestamp_info *)data.data;
1753 if (ret == DB_NOTFOUND)
1755 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1761 * PUBLIC: int __add_txnrange __P((DB_LOG_VRFY_INFO *, u_int32_t,
1762 * PUBLIC: DB_LSN, int32_t, int));
1764 int __add_txnrange (lvinfo, txnid, lsn, when, ishead)
1765 DB_LOG_VRFY_INFO *lvinfo;
1769 int ishead; /* Whether it's the 1st log of the txn. */
1773 struct __lv_txnrange tr, *ptr;
1779 memset(&key, 0, sizeof(DBT));
1780 memset(&data, 0, sizeof(DBT));
1781 memset(&tr, 0, sizeof(tr));
1784 key.size = sizeof(txnid);
1786 BDBOP(__db_cursor(lvinfo->txnrngs, lvinfo->ip, NULL, &csr, 0));
1788 * Note that we will backward play the logs to gather such information.
1792 tr.when_commit = when;
1794 data.size = sizeof(tr);
1795 BDBOP(__dbc_put(csr, &key, &data, DB_KEYFIRST));
1798 * Dup data sorted by lsn, and we are backward playing logs,
1799 * so the 1st record should be the one we want.
1801 BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1802 ptr = (struct __lv_txnrange *)data.data;
1803 DB_ASSERT(lvinfo->dbenv->env, IS_ZERO_LSN(ptr->begin));
1805 BDBOP(__dbc_put(csr, &key, &data, DB_CURRENT));
1809 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1816 * If lsn is the last log of an aborted txn T, T's txnid is
1817 * returned via the log verify handle.
1819 * PUBLIC: int __get_aborttxn __P((DB_LOG_VRFY_INFO *, DB_LSN));
1822 __get_aborttxn(lvinfo, lsn)
1823 DB_LOG_VRFY_INFO *lvinfo;
1834 memset(&key, 0, sizeof(DBT));
1835 memset(&data, 0, sizeof(DBT));
1838 key.size = sizeof(lsn);
1839 BDBOP(__db_cursor(lvinfo->txnaborts, lvinfo->ip, NULL, &csr, 0));
1840 BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1841 memcpy(&txnid, data.data, data.size);
1843 * The lsn is the last op of an aborted txn, call __on_txnabort
1844 * before processing next log record.
1846 lvinfo->aborted_txnid = txnid;
1847 lvinfo->aborted_txnlsn = lsn;
1850 /* It's OK if can't find it. */
1851 if (ret == DB_NOTFOUND)
1853 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1860 * Whether txnid is started before lsn and ended after lsn.
1862 * PUBLIC: int __txn_started __P((DB_LOG_VRFY_INFO *,
1863 * PUBLIC: DB_LSN, u_int32_t, int *));
1866 __txn_started(lvinfo, lsn, txnid, res)
1867 DB_LOG_VRFY_INFO *lvinfo;
1875 struct __lv_txnrange *ptr, tr;
1879 memset(&tr, 0, sizeof(tr));
1880 memset(&key, 0, sizeof(DBT));
1881 memset(&data, 0, sizeof(DBT));
1883 key.size = sizeof(txnid);
1885 BDBOP(__db_cursor(lvinfo->txnrngs, lvinfo->ip, NULL, &csr, 0));
1886 BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1887 for (;ret == 0; ret = __dbc_get(csr, &key, &data, DB_NEXT_DUP)) {
1888 ptr = (struct __lv_txnrange *)data.data;
1889 if (LOG_COMPARE(&lsn, &(ptr->begin)) > 0 &&
1890 LOG_COMPARE(&lsn, &(ptr->end)) <= 0) {
1896 if (ret == DB_NOTFOUND)
1897 ret = 0;/* It's OK if can't find it. */
1898 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1904 * PUBLIC: int __set_logvrfy_dbfuid __P((DB_LOG_VRFY_INFO *));
1907 __set_logvrfy_dbfuid(lvinfo)
1908 DB_LOG_VRFY_INFO *lvinfo;
1916 memset(&key, 0, sizeof(DBT));
1917 memset(&data, 0, sizeof(DBT));
1919 /* So far we only support verifying a specific db file. */
1920 p = lvinfo->lv_config->dbfile;
1921 buflen = sizeof(char) * (strlen(p) + 1);
1922 key.data = (char *)p;
1923 key.size = (u_int32_t)buflen;
1925 BDBOP2(lvinfo->dbenv, __db_get(lvinfo->fnameuid, lvinfo->ip, NULL,
1926 &key, &data, 0), "__set_logvrfy_dbfuid");
1928 memcpy(lvinfo->target_dbid, data.data, DB_FILE_ID_LEN);
1934 * __add_page_to_txn --
1935 * Try adding a page to a txn, result brings back if really added(0/1)
1936 * or if there is an access violation(-1).
1937 * PUBLIC: int __add_page_to_txn __P((DB_LOG_VRFY_INFO *,
1938 * PUBLIC: int32_t, db_pgno_t, u_int32_t, u_int32_t *, int *));
1941 __add_page_to_txn (lvinfo, dbregid, pgno, txnid, otxn, result)
1942 DB_LOG_VRFY_INFO *lvinfo;
1945 u_int32_t txnid, *otxn;
1955 if (txnid < TXN_MINIMUM) {
1963 buflen = sizeof(u_int8_t) * DB_FILE_ID_LEN + sizeof(db_pgno_t);
1964 BDBOP(__os_malloc(lvinfo->dbenv->env, buflen, &buf));
1965 memset(buf, 0, buflen);
1966 memset(&key, 0, sizeof(DBT));
1967 memset(&data, 0, sizeof(DBT));
1970 * We use the file uid as key because a single db file can have
1971 * multiple dbregid at the same time, and we may neglect the fact
1972 * that the same db file is being updated by multiple txns if we use
1975 key.data = &dbregid;
1976 key.size = sizeof(dbregid);
1977 if ((ret = __db_get(lvinfo->dbregids, lvinfo->ip, NULL,
1978 &key, &data, 0)) != 0) {
1979 if (ret == DB_NOTFOUND) {
1980 if (F_ISSET(lvinfo, DB_LOG_VERIFY_PARTIAL)) {
1984 F_SET(lvinfo, DB_LOG_VERIFY_INTERR);
1988 pff = (VRFY_FILELIFE *)data.data;
1989 memcpy(buf, pff->fileid, DB_FILE_ID_LEN);
1990 memcpy(buf + DB_FILE_ID_LEN, (u_int8_t *)&pgno, sizeof(pgno));
1991 memset(&key, 0, sizeof(DBT));
1992 memset(&data, 0, sizeof(DBT));
1994 key.size = (u_int32_t)buflen;
1995 if ((ret = __db_get(lvinfo->pgtxn, lvinfo->ip, NULL,
1996 &key, &data, 0)) != 0) {
1997 if (ret == DB_NOTFOUND) {
1999 data.size = sizeof(txnid);
2000 BDBOP(__db_put(lvinfo->pgtxn, lvinfo->ip, NULL, &key,
2003 ret = 0;/* This is not an error. */
2007 DB_ASSERT(lvinfo->dbenv->env, data.size == sizeof(txnid2));
2008 memcpy(&txnid2, data.data, data.size);
2009 if (txnid == txnid2)/* The same txn already has the page. */
2011 else {/* Txn txnid is updating pages still held by txnid2. */
2016 /* result is set to -1 on violation, 0 if already has it, 1 if added. */
2019 __os_free(lvinfo->dbenv->env, buf);
2024 * PUBLIC: int __del_txn_pages __P((DB_LOG_VRFY_INFO *, u_int32_t));
2027 __del_txn_pages(lvinfo, txnid)
2028 DB_LOG_VRFY_INFO *lvinfo;
2035 memset(&key, 0, sizeof(DBT));
2037 key.size = sizeof(txnid);
2039 BDBOP(__db_del(lvinfo->txnpg, lvinfo->ip, NULL, &key, 0));
2046 * __is_ancestor_txn --
2047 * Tells via res if ptxnid is txnid's parent txn at the moment of lsn.
2049 * PUBLIC: int __is_ancestor_txn __P((DB_LOG_VRFY_INFO *,
2050 * PUBLIC: u_int32_t, u_int32_t, DB_LSN, int *));
2053 __is_ancestor_txn (lvinfo, ptxnid, txnid, lsn, res)
2054 DB_LOG_VRFY_INFO *lvinfo;
2055 u_int32_t ptxnid, txnid;
2064 struct __lv_txnrange tr;
2069 pdb = lvinfo->txnrngs;
2070 memset(&key, 0, sizeof(DBT));
2071 memset(&data, 0, sizeof(DBT));
2073 BDBOP(__db_cursor(pdb, lvinfo->ip, NULL, &csr, 0));
2075 /* See if ptxnid is an ancestor of txnid. */
2078 key.size = sizeof(ptid);
2079 BDBOP(__dbc_get(csr, &key, &data, DB_SET));
2080 /* A txnid maybe reused, we want the range having lsn in it. */
2082 ret = __dbc_get(csr, &key, &data, DB_NEXT_DUP)) {
2083 DB_ASSERT(pdb->env, sizeof(tr) == data.size);
2084 memcpy(&tr, data.data, data.size);
2085 if (tr.ptxnid > 0 &&
2086 LOG_COMPARE(&lsn, &(tr.begin)) >= 0 &&
2087 LOG_COMPARE(&lsn, &(tr.end)) <= 0)
2091 if (tr.ptxnid == ptxnid) {
2097 } while (ptid != 0);
2101 if (ret == DB_NOTFOUND)
2103 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
2109 * PUBLIC: int __return_txn_pages __P((DB_LOG_VRFY_INFO *,
2110 * PUBLIC: u_int32_t, u_int32_t));
2112 int __return_txn_pages(lvh, ctxn, ptxn)
2113 DB_LOG_VRFY_INFO *lvh;
2114 u_int32_t ctxn, ptxn;
2119 DBT key, key2, data, data2;
2120 char buf[DB_FILE_ID_LEN + sizeof(db_pgno_t)];
2126 memset(&key, 0, sizeof(DBT));
2127 memset(&key2, 0, sizeof(DBT));
2128 memset(&data, 0, sizeof(DBT));
2129 memset(&data2, 0, sizeof(DBT));
2131 BDBOP(__db_cursor(sdb, lvh->ip, NULL, &csr, 0));
2133 key.size = sizeof(ctxn);
2135 key2.size = sizeof(ptxn);
2137 data2.ulen = DB_FILE_ID_LEN + sizeof(db_pgno_t);
2138 data2.flags = DB_DBT_USERMEM;
2140 for (ret = __dbc_pget(csr, &key, &data2, &data, DB_SET); ret == 0;
2141 ret = __dbc_pget(csr, &key, &data2, &data, DB_NEXT_DUP))
2142 BDBOP(__db_put(pdb, lvh->ip, NULL, &data2, &key2, 0));
2143 if ((ret = __del_txn_pages(lvh, ctxn)) != 0 && ret != DB_NOTFOUND)
2146 if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
2151 #define ADD_ITEM(lvh, logtype) ((lvh)->logtype_names[(logtype)] = (#logtype))
2153 __lv_setup_logtype_names(lvinfo)
2154 DB_LOG_VRFY_INFO *lvinfo;
2156 ADD_ITEM(lvinfo, DB___bam_irep);
2157 ADD_ITEM(lvinfo, DB___bam_split_42);
2158 ADD_ITEM(lvinfo, DB___bam_split);
2159 ADD_ITEM(lvinfo, DB___bam_rsplit);
2160 ADD_ITEM(lvinfo, DB___bam_adj);
2161 ADD_ITEM(lvinfo, DB___bam_cadjust);
2162 ADD_ITEM(lvinfo, DB___bam_cdel);
2163 ADD_ITEM(lvinfo, DB___bam_repl);
2164 ADD_ITEM(lvinfo, DB___bam_root);
2165 ADD_ITEM(lvinfo, DB___bam_curadj);
2166 ADD_ITEM(lvinfo, DB___bam_rcuradj);
2167 ADD_ITEM(lvinfo, DB___bam_relink_43);
2168 ADD_ITEM(lvinfo, DB___bam_merge_44);
2169 ADD_ITEM(lvinfo, DB___crdel_metasub);
2170 ADD_ITEM(lvinfo, DB___crdel_inmem_create);
2171 ADD_ITEM(lvinfo, DB___crdel_inmem_rename);
2172 ADD_ITEM(lvinfo, DB___crdel_inmem_remove);
2173 ADD_ITEM(lvinfo, DB___dbreg_register);
2174 ADD_ITEM(lvinfo, DB___db_addrem);
2175 ADD_ITEM(lvinfo, DB___db_big);
2176 ADD_ITEM(lvinfo, DB___db_ovref);
2177 ADD_ITEM(lvinfo, DB___db_relink_42);
2178 ADD_ITEM(lvinfo, DB___db_debug);
2179 ADD_ITEM(lvinfo, DB___db_noop);
2180 ADD_ITEM(lvinfo, DB___db_pg_alloc_42);
2181 ADD_ITEM(lvinfo, DB___db_pg_alloc);
2182 ADD_ITEM(lvinfo, DB___db_pg_free_42);
2183 ADD_ITEM(lvinfo, DB___db_pg_free);
2184 ADD_ITEM(lvinfo, DB___db_cksum);
2185 ADD_ITEM(lvinfo, DB___db_pg_freedata_42);
2186 ADD_ITEM(lvinfo, DB___db_pg_freedata);
2187 ADD_ITEM(lvinfo, DB___db_pg_init);
2188 ADD_ITEM(lvinfo, DB___db_pg_sort_44);
2189 ADD_ITEM(lvinfo, DB___db_pg_trunc);
2190 ADD_ITEM(lvinfo, DB___db_realloc);
2191 ADD_ITEM(lvinfo, DB___db_relink);
2192 ADD_ITEM(lvinfo, DB___db_merge);
2193 ADD_ITEM(lvinfo, DB___db_pgno);
2195 ADD_ITEM(lvinfo, DB___ham_insdel);
2196 ADD_ITEM(lvinfo, DB___ham_newpage);
2197 ADD_ITEM(lvinfo, DB___ham_splitdata);
2198 ADD_ITEM(lvinfo, DB___ham_replace);
2199 ADD_ITEM(lvinfo, DB___ham_copypage);
2200 ADD_ITEM(lvinfo, DB___ham_metagroup_42);
2201 ADD_ITEM(lvinfo, DB___ham_metagroup);
2202 ADD_ITEM(lvinfo, DB___ham_groupalloc_42);
2203 ADD_ITEM(lvinfo, DB___ham_groupalloc);
2204 ADD_ITEM(lvinfo, DB___ham_changeslot);
2205 ADD_ITEM(lvinfo, DB___ham_contract);
2206 ADD_ITEM(lvinfo, DB___ham_curadj);
2207 ADD_ITEM(lvinfo, DB___ham_chgpg);
2210 ADD_ITEM(lvinfo, DB___qam_incfirst);
2211 ADD_ITEM(lvinfo, DB___qam_mvptr);
2212 ADD_ITEM(lvinfo, DB___qam_del);
2213 ADD_ITEM(lvinfo, DB___qam_add);
2214 ADD_ITEM(lvinfo, DB___qam_delext);
2216 ADD_ITEM(lvinfo, DB___txn_regop_42);
2217 ADD_ITEM(lvinfo, DB___txn_regop);
2218 ADD_ITEM(lvinfo, DB___txn_ckp_42);
2219 ADD_ITEM(lvinfo, DB___txn_ckp);
2220 ADD_ITEM(lvinfo, DB___txn_child);
2221 ADD_ITEM(lvinfo, DB___txn_xa_regop_42);
2222 ADD_ITEM(lvinfo, DB___txn_prepare);
2223 ADD_ITEM(lvinfo, DB___txn_recycle);
2224 ADD_ITEM(lvinfo, DB___fop_create_42);
2225 ADD_ITEM(lvinfo, DB___fop_create);
2226 ADD_ITEM(lvinfo, DB___fop_remove);
2227 ADD_ITEM(lvinfo, DB___fop_write_42);
2228 ADD_ITEM(lvinfo, DB___fop_write);
2229 ADD_ITEM(lvinfo, DB___fop_rename_42);
2230 ADD_ITEM(lvinfo, DB___fop_rename_noundo_46);
2231 ADD_ITEM(lvinfo, DB___fop_rename);
2232 ADD_ITEM(lvinfo, DB___fop_rename_noundo);
2233 ADD_ITEM(lvinfo, DB___fop_file_remove);