Imported Upstream version 5.3.21
[platform/upstream/libdb.git] / src / log / log_verify_util.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 2012 Oracle and/or its affiliates.  All rights reserved.
5  *
6  * $Id$
7  */
8
9 /*
10  * This file contains helper functions like data structure and in-memory db
11  * management, which are used to store various log verification information.
12  */
13 #include "db_config.h"
14 #include "db_int.h"
15
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"
22 #include "dbinc/mp.h"
23 #include "dbinc/txn.h"
24 #include "dbinc/fop.h"
25
26 #include "dbinc/log_verify.h"
27
28 #define BDBOP(op)       do {            \
29         ret = (op);                     \
30         if (ret != 0) {                 \
31                 __lv_on_bdbop_err(ret); \
32                 goto err;               \
33         }                               \
34 } while (0)
35
36 #define BDBOP2(dbenv, op, funct)        do {                    \
37         ret = (op);                                             \
38         if (ret != 0) {                                         \
39                 __lv_on_bdbop_err(ret);                         \
40                 __db_err(dbenv->env, ret, "\n%s", funct);       \
41                 return (ret);                                   \
42         }                                                       \
43 } while (0)
44
45 #define BDBOP3(dbenv, op, excpt, funct) do {                            \
46         ret = (op);                                                     \
47         if (ret != 0) {                                                 \
48                 __lv_on_bdbop_err(ret);                                 \
49                 if (ret != excpt) {                                     \
50                         __db_err(dbenv->env, ret, "\n%s", funct);       \
51                         return (ret);                                   \
52                 }                                                       \
53         }                                                               \
54 } while (0)
55
56 typedef int (*btcmp_funct)(DB *, const DBT *, const DBT *);
57 typedef int (*dupcmp_funct)(DB *, const DBT *, const DBT *);
58
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 **));
80
81 static void __lv_on_bdbop_err(ret)
82         int ret;
83 {
84         /* Pass lint checks. We need the ret and this function for debugging. */
85         COMPQUIET(ret, 0);
86 }
87
88 /*
89  * __create_log_vrfy_info --
90  *      Initialize and return a log verification handle to be used throughout
91  *      a verification process.
92  *
93  * PUBLIC: int __create_log_vrfy_info __P((const DB_LOG_VERIFY_CONFIG *,
94  * PUBLIC:     DB_LOG_VRFY_INFO **, DB_THREAD_INFO *));
95  */
96 int
97 __create_log_vrfy_info(cfg, lvinfopp, ip)
98         const DB_LOG_VERIFY_CONFIG *cfg;
99         DB_LOG_VRFY_INFO **lvinfopp;
100         DB_THREAD_INFO *ip;
101 {
102         const char *envhome;
103         int inmem, ret;
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;
108
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";
120
121         envhome = cfg->temp_envhome;
122         lvinfop = NULL;
123         cachesz = cfg->cachesize;
124         if (cachesz== 0)
125                 cachesz = 1024 * 1024 * 256;
126
127         BDBOP(__os_malloc(NULL, sizeof(DB_LOG_VRFY_INFO), &lvinfop));
128         memset(lvinfop, 0, sizeof(DB_LOG_VRFY_INFO));
129         lvinfop->ip = ip;
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;
133
134         /*
135          * The envhome parameter determines if we will use an in-memory
136          * environment and databases.
137          */
138         if (envhome == NULL) {
139                 envflags = DB_PRIVATE;
140                 inmem = 1;
141         } else {
142                 envflags = 0;
143                 inmem = 0;
144         }
145
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));
149         /*
150          * Log verification internal db environment should be accessed
151          * single-threaded. No transaction semantics needed.
152          */
153         BDBOP(__env_open(lvinfop->dbenv, envhome,
154             envflags | DB_CREATE | DB_INIT_MPOOL, 0666));
155
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));
160
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));
180
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));
187
188         *lvinfopp = lvinfop;
189
190         return (0);
191 err:
192         if (lvinfop->dbenv && ret != 0)
193                 __db_err(lvinfop->dbenv->env, ret, "__create_log_vrfy_info");
194         (void)__destroy_log_vrfy_info(lvinfop);
195
196         return (ret);
197 }
198
199 /*
200  * __destroy_log_vrfy_info --
201  *      Destroy and free a log verification handle.
202  *
203  * PUBLIC: int __destroy_log_vrfy_info __P((DB_LOG_VRFY_INFO *));
204  */
205 int
206 __destroy_log_vrfy_info(lvinfop)
207         DB_LOG_VRFY_INFO *lvinfop;
208 {
209         int ret;
210
211         ret = 0;
212         if (lvinfop == NULL)
213                 return (0);
214
215         if (lvinfop->txnaborts != NULL &&
216             (ret = __db_close(lvinfop->txnaborts, NULL, 0)) != 0)
217                 goto err;
218         if (lvinfop->txninfo != NULL &&
219             (ret = __db_close(lvinfop->txninfo, NULL, 0)) != 0)
220                 goto err;
221         if (lvinfop->dbregids != NULL &&
222             (ret = __db_close(lvinfop->dbregids, NULL, 0)) != 0)
223                 goto err;
224         if (lvinfop->fileregs != NULL &&
225             (ret = __db_close(lvinfop->fileregs, NULL, 0)) != 0)
226                 goto err;
227         if (lvinfop->pgtxn != NULL &&
228             (ret = __db_close(lvinfop->pgtxn, NULL, 0)) != 0)
229                 goto err;
230         if (lvinfop->lsntime != NULL &&
231             (ret = __db_close(lvinfop->lsntime, NULL, 0)) != 0)
232                 goto err;
233         if (lvinfop->ckps != NULL &&
234             (ret = __db_close(lvinfop->ckps, NULL, 0)) != 0)
235                 goto err;
236         if (lvinfop->txnrngs != NULL &&
237             (ret = __db_close(lvinfop->txnrngs, NULL, 0)) != 0)
238                 goto err;
239         if (lvinfop->fnameuid != NULL &&
240             (ret = __db_close(lvinfop->fnameuid, NULL, 0)) != 0)
241                 goto err;
242         if (lvinfop->timelsn != NULL &&
243             (ret = __db_close(lvinfop->timelsn, NULL, 0)) != 0)
244                 goto err;
245         if (lvinfop->txnpg != NULL &&
246             (ret = __db_close(lvinfop->txnpg, NULL, 0)) != 0)
247                 goto err;
248         if (lvinfop->dbenv != NULL &&
249             (ret = __env_close(lvinfop->dbenv, 0)) != 0)
250                 goto err;
251 err:
252         __os_free(NULL, lvinfop);
253
254         return (ret);
255 }
256
257 /* Secondary index callback function for DB_LOG_VRFY_INFO->timelsn. */
258 static int
259 __lv_seccbk_fname(secdb, key, data, result)
260         DB *secdb;
261         const DBT *key;
262         const DBT *data;
263         DBT *result;
264 {
265         int ret, tret;
266         VRFY_FILEREG_INFO *freg;
267         char *buf;
268         size_t buflen, slen;
269
270         ret = tret = 0;
271         COMPQUIET(key, NULL);
272         if ((ret = __lv_unpack_filereg(data, &freg)) != 0)
273                 goto out;
274         if (freg->fname == NULL || (slen = strlen(freg->fname)) == 0) {
275                 ret = DB_DONOTINDEX;
276                 goto out;
277         }
278
279         buflen = (slen + 1) * sizeof(char);
280         if ((ret = __os_umalloc(secdb->dbenv->env, buflen, &buf)) != 0)
281                 goto out;
282         (void)strcpy(buf, freg->fname);
283         result->size = (u_int32_t)buflen;
284         result->flags |= DB_DBT_APPMALLOC;
285         result->data = buf;
286 out:
287         if (freg != NULL && (tret = __free_filereg_info(freg)) != 0 && ret == 0)
288                 ret = tret;
289         return (ret);
290 }
291
292 /* Secondary index callback function for DB_LOG_VRFY_INFO->txnpg. */
293 static int
294 __lv_seccbk_txnpg(secdb, key, data, result)
295         DB *secdb;
296         const DBT *key;
297         const DBT *data;
298         DBT *result;
299 {
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;
305
306         return (0);
307 }
308
309 /* Secondary index callback function for DB_LOG_VRFY_INFO->timelsn. */
310 static int
311 __lv_seccbk_lsn(secdb, key, data, result)
312         DB *secdb;
313         const DBT *key;
314         const DBT *data;
315         DBT *result;
316 {
317         VRFY_TIMESTAMP_INFO *lvti;
318
319         COMPQUIET(key, NULL);
320         COMPQUIET(secdb, NULL);
321
322         lvti = (VRFY_TIMESTAMP_INFO *)data->data;
323         result->data = &(lvti->timestamp);
324         result->size = sizeof(lvti->timestamp);
325
326         return (0);
327 }
328
329 /*
330  * Open a BTREE database handle, optionally set the btree compare function
331  * and flags if any.
332  */
333 static int
334 __lv_open_db(dbenv, dbpp, ip, name, inmem, cmpf, sflags, dupcmpf)
335         DB_ENV *dbenv;
336         DB **dbpp;
337         const char *name;
338         int inmem;
339         btcmp_funct cmpf;
340         u_int32_t sflags;
341         dupcmp_funct dupcmpf;
342         DB_THREAD_INFO *ip;
343 {
344         int ret;
345         const char *dbfname, *dbname;
346         DB *dbp;
347
348         dbp = NULL;
349         ret = 0;
350         if (inmem) {
351                 dbfname = NULL;
352                 dbname = name;
353         } else {
354                 dbfname = name;
355                 dbname = NULL;
356         }
357
358         BDBOP(db_create(&dbp, dbenv, 0));
359
360         if (cmpf != NULL)
361                 BDBOP(__bam_set_bt_compare(dbp, cmpf));
362         if (dupcmpf != NULL)
363                 dbp->dup_compare = dupcmpf;
364         if (sflags != 0)
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));
368
369         BDBOP(__db_open(dbp, ip, NULL, dbfname, dbname, DB_BTREE, DB_CREATE,
370             0666, PGNO_BASE_MD));
371
372         *dbpp = dbp;
373
374         return (0);
375 err:
376         if (dbenv != NULL && ret != 0)
377                 __db_err(dbenv->env, ret, "__lv_open_db");
378         if (dbp != NULL)
379                 (void)__db_close(dbp, NULL, 0);
380
381         return (ret);
382 }
383
384 /* Btree compare function for a [fileid, pgno] key. */
385 static int
386 __lv_fidpgno_cmp(db, dbt1, dbt2)
387         DB *db;
388         const DBT *dbt1;
389         const DBT *dbt2;
390 {
391         db_pgno_t pgno1, pgno2;
392         int ret;
393         size_t len;
394
395         COMPQUIET(db, NULL);
396         len = DB_FILE_ID_LEN;
397         ret = memcmp(dbt1->data, dbt2->data, len);
398         if (ret == 0) {
399                 memcpy(&pgno1, (u_int8_t *)dbt1->data + len,
400                     sizeof(pgno1));
401                 memcpy(&pgno2, (u_int8_t *)dbt2->data + len,
402                     sizeof(pgno2));
403                 ret = NUMCMP(pgno1, pgno2);
404         }
405
406         return (ret);
407 }
408
409 /* Btree compare function for a int32_t type of key. */
410 static int
411 __lv_i32_cmp(db, dbt1, dbt2)
412         DB *db;
413         const DBT *dbt1;
414         const DBT *dbt2;
415 {
416         int32_t k1, k2;
417
418         COMPQUIET(db, NULL);
419         memcpy(&k1, dbt1->data, sizeof(k1));
420         memcpy(&k2, dbt2->data, sizeof(k2));
421
422         return (NUMCMP(k1, k2));
423 }
424
425 /* Btree compare function for a u_int32_t type of key. */
426 static int
427 __lv_ui32_cmp(db, dbt1, dbt2)
428         DB *db;
429         const DBT *dbt1;
430         const DBT *dbt2;
431 {
432         u_int32_t k1, k2;
433
434         COMPQUIET(db, NULL);
435         memcpy(&k1, dbt1->data, sizeof(k1));
436         memcpy(&k2, dbt2->data, sizeof(k2));
437
438         return (NUMCMP(k1, k2));
439 }
440
441 /* Btree compare function for a DB_LSN type of key. */
442 static int
443 __lv_lsn_cmp(db, dbt1, dbt2)
444         DB *db;
445         const DBT *dbt1;
446         const DBT *dbt2;
447 {
448         DB_LSN lsn1, lsn2;
449
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));
454
455         return (LOG_COMPARE(&lsn1, &lsn2));
456 }
457
458 /*
459  * Structure management routines. We keep each structure on a
460  * consecutive memory chunk.
461  *
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.
465  */
466
467 /*
468  * PUBLIC: int __put_txn_vrfy_info __P((const DB_LOG_VRFY_INFO *,
469  * PUBLIC:     const VRFY_TXN_INFO *));
470  */
471 int
472 __put_txn_vrfy_info (lvinfo, txninfop)
473         const DB_LOG_VRFY_INFO *lvinfo;
474         const VRFY_TXN_INFO *txninfop;
475 {
476         int ret;
477         DBT key, data;
478
479         ret = __lv_pack_txn_vrfy_info(txninfop, &key, &data);
480         DB_ASSERT(lvinfo->dbenv->env, ret == 0);
481
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);
485
486         return (0);
487 }
488
489 /* Construct a key and data DBT from the structure. */
490 static int
491 __lv_pack_txn_vrfy_info(txninfop, key, data)
492         const VRFY_TXN_INFO *txninfop;
493         DBT *key, *data;
494 {
495         int ret;
496         char *buf, *p;
497         size_t bufsz, len;
498         u_int32_t i;
499         DBT *pdbt;
500
501         memset(key, 0, sizeof(DBT));
502         memset(data, 0, sizeof(DBT));
503         ret = 0;
504         bufsz = TXN_VERIFY_INFO_TOTSIZE(*txninfop);
505
506         if ((ret = __os_malloc(NULL, bufsz, &buf)) != 0)
507                 goto err;
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);
513         p += len;
514
515         for (i = 0; i < txninfop->filenum; i++) {
516
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);
521                 p += pdbt->size;
522         }
523
524         key->data = (void *)&txninfop->txnid;
525         key->size = sizeof(txninfop->txnid);
526         data->data = buf;
527         data->size = (u_int32_t)bufsz;
528         data->flags |= DB_DBT_MALLOC;
529 err:
530         return (ret);
531 }
532
533 /* Calculate a DBT array's total number of bytes to store. */
534 static size_t
535 __lv_dbt_arrsz(arr, arrlen)
536         const DBT *arr;
537         u_int32_t arrlen;
538 {
539         u_int32_t i;
540         size_t sz;
541
542         sz = 0;
543
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);
547
548         return sz;
549 }
550
551 /*
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.
555  *
556  * PUBLIC: int __get_txn_vrfy_info __P((const DB_LOG_VRFY_INFO *, u_int32_t,
557  * PUBLIC:     VRFY_TXN_INFO **));
558  */
559 int
560 __get_txn_vrfy_info (lvinfo, txnid, txninfopp)
561         const DB_LOG_VRFY_INFO *lvinfo;
562         u_int32_t txnid;
563         VRFY_TXN_INFO **txninfopp;
564 {
565         int ret;
566         DBT key, data;
567
568         memset(&key, 0, sizeof(DBT));
569         memset(&data, 0, sizeof(DBT));
570         key.data = &txnid;
571         key.size = sizeof(txnid);
572
573         BDBOP3(lvinfo->dbenv, __db_get(lvinfo->txninfo, lvinfo->ip, NULL,
574             &key, &data, 0), DB_NOTFOUND, "__get_txn_vrfy_info");
575
576         if (ret != DB_NOTFOUND)
577                 ret = __lv_unpack_txn_vrfy_info(txninfopp, &data);
578
579         return (ret);
580 }
581
582 /* Construct a structure from a DBT. */
583 static int
584 __lv_unpack_txn_vrfy_info(txninfopp, data)
585         VRFY_TXN_INFO **txninfopp;
586         const DBT *data;
587 {
588         size_t bufsz;
589         VRFY_TXN_INFO *buf, *txninfop;
590         DB_LSN *lsns, *p;
591         u_int32_t i, sz;
592         char *pb, *q;
593         int ret;
594
595         ret = 0;
596         i = sz = 0;
597         lsns = p = NULL;
598         pb = q = NULL;
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);
602
603         if ((ret = __os_malloc(NULL, bufsz = sizeof(VRFY_TXN_INFO), &buf)) != 0)
604                 goto err;
605         memset(buf, 0, bufsz);
606         memcpy(buf, data->data, TXN_VERIFY_INFO_FIXSIZE);
607
608         if (txninfop->num_recycle != 0) {
609                 if ((ret = __os_malloc(NULL,
610                     txninfop->num_recycle * sizeof(DB_LSN), &p)) != 0)
611                         goto err;
612                 memcpy(p, lsns, txninfop->num_recycle * sizeof(DB_LSN));
613                 buf->recycle_lsns = p;
614         }
615
616         if (txninfop->filenum != 0) {
617                 if ((ret = __os_malloc(NULL,
618                     txninfop->filenum * sizeof(DBT), &q)) != 0)
619                         goto err;
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));
624                         pb += sizeof(sz);
625                         if ((ret = __os_malloc(NULL, sz, &q)) != 0)
626                                 goto err;
627                         memcpy(q, pb, sz);
628                         pb += sz;
629
630                         buf->fileups[i].data = q;
631                         buf->fileups[i].size = sz;
632                 }
633         }
634
635         *txninfopp = buf;
636 err:
637         return (ret);
638 }
639
640 static int
641 __lv_add_recycle_lsn (txninfop, lsn)
642         VRFY_TXN_INFO *txninfop;
643         const DB_LSN *lsn;
644 {
645         int ret;
646
647         ret = 0;
648         txninfop->num_recycle++;
649         if ((ret = __os_realloc(NULL, txninfop->num_recycle * sizeof(DB_LSN),
650             &(txninfop->recycle_lsns))) != 0)
651                 goto err;
652         txninfop->recycle_lsns[txninfop->num_recycle - 1] = *lsn;
653 err:
654         return (ret);
655 }
656
657 /*
658  * __add_recycle_lsn_range --
659  *      Add recycle info for each txn within the recycled txnid range.
660  *
661  * PUBLIC: int __add_recycle_lsn_range __P((DB_LOG_VRFY_INFO *,
662  * PUBLIC:     const DB_LSN *, u_int32_t, u_int32_t));
663  */
664 int
665 __add_recycle_lsn_range(lvinfo, lsn, min, max)
666         DB_LOG_VRFY_INFO *lvinfo;
667         const DB_LSN *lsn;
668         u_int32_t min, max;
669 {
670         DBC *csr;
671         int ret, tret;
672         u_int32_t i;
673         DBT key2, data2;
674         struct __add_recycle_params param;
675
676         csr = NULL;
677         ret = tret = 0;
678         memset(&key2, 0, sizeof(DBT));
679         memset(&data2, 0, sizeof(DBT));
680         memset(&param, 0, sizeof(param));
681
682         if ((ret = __os_malloc(lvinfo->dbenv->env, sizeof(VRFY_TXN_INFO *) *
683             (param.ti2ul = 1024), &(param.ti2u))) != 0)
684                 goto err;
685         param.ti2ui = 0;
686         param.recycle_lsn = *lsn;
687         param.min = min;
688         param.max = max;
689
690         /* Iterate the specified range and process each transaction. */
691         if ((ret = __iterate_txninfo(lvinfo, min, max, __lv_add_recycle_handler,
692             &param)) != 0)
693                 goto err;
694
695         /*
696          * Save updated txninfo structures. We can't do so in the above
697          * iteration, so we have to save them here.
698          */
699         BDBOP(__db_cursor(lvinfo->txninfo, lvinfo->ip, NULL, &csr, DBC_BULK));
700
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));
705                 /*
706                  * key2.data refers to param.ti2u[i]'s memory, data2.data is
707                  * freed by DB since we set DB_DBT_MALLOC.
708                  */
709                 if ((ret = __free_txninfo(param.ti2u[i])) != 0)
710                         goto err;
711         }
712
713 err:
714         if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
715                 ret = tret;
716         __os_free(lvinfo->dbenv->env, param.ti2u);
717         if (ret != 0)
718                 __db_err(lvinfo->dbenv->env, ret,
719                     "__add_recycle_lsn_range");
720
721         return (ret);
722 }
723
724 /*
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.
729  *
730  * PUBLIC: int __iterate_txninfo __P((DB_LOG_VRFY_INFO *, u_int32_t,
731  * PUBLIC:     u_int32_t, TXNINFO_HANDLER, void *));
732  */
733 int
734 __iterate_txninfo(lvinfo, min, max, handler, param)
735         DB_LOG_VRFY_INFO *lvinfo;
736         u_int32_t min, max;
737         TXNINFO_HANDLER handler;
738         void *param;
739 {
740         ENV *env;
741         VRFY_TXN_INFO *txninfop;
742         int ret, tret;
743         u_int32_t bufsz, pgsz, txnid;
744         size_t retkl, retdl;
745         char *btbuf;
746         u_int8_t *retk, *retd;
747         DBT key, data, data2;
748         DBC *csr;
749         void *p;
750
751         csr = NULL;
752         env = lvinfo->dbenv->env;
753         txninfop = NULL;
754         ret = tret = 0;
755         txnid = 0;
756         retkl = retdl = 0;
757         bufsz = 64 * 1024;
758         btbuf = NULL;
759         retk = retd = NULL;
760
761         memset(&key, 0, sizeof(DBT));
762         memset(&data, 0, sizeof(DBT));
763         memset(&data2, 0, sizeof(DBT));
764
765         pgsz = lvinfo->txninfo->pgsize;
766         DB_ASSERT(env, ret == 0);
767
768         if (bufsz % pgsz != 0)
769                 bufsz = pgsz * (bufsz / pgsz);
770
771         if ((ret = __os_malloc(env, bufsz, &btbuf)) != 0)
772                 goto err;
773
774         BDBOP(__db_cursor(lvinfo->txninfo, lvinfo->ip, NULL, &csr, DBC_BULK));
775
776         /*
777          * Use bulk retrieval to scan the database as fast as possible.
778          */
779         data.data = btbuf;
780         data.ulen = bufsz;
781         data.flags |= DB_DBT_USERMEM;
782
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)) {
785                 switch (ret) {
786                 case 0:
787                         break;
788                 case DB_NOTFOUND:
789                         goto out;
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)
794                                 goto out;
795                         data.ulen = bufsz;
796                         data.data = btbuf;
797                         continue;/* Continue the for-loop. */
798                         /* No break statement allowed by lint here. */
799                 default:
800                         goto err;
801                 }
802
803                 /*
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
810                  * out of this loop.
811                  */
812                 DB_MULTIPLE_INIT(p, &data);
813                 while (1) {
814                         DB_MULTIPLE_KEY_NEXT(p, &data,
815                             retk, retkl, retd, retdl);
816                         if (p == NULL)
817                                 break;
818                         DB_ASSERT(env, retkl == sizeof(txnid) && retk != NULL);
819                         memcpy(&txnid, retk, retkl);
820                         /*
821                          * Process it if txnid in range or no range specified.
822                          * The range must be a closed one.
823                          */
824                         if ((min != 0 && txnid >= min && max != 0 &&
825                             txnid <= max) || (min == 0 && max == 0)) {
826                                 data2.data = retd;
827                                 data2.size = (u_int32_t)retdl;
828
829                                 if ((ret = __lv_unpack_txn_vrfy_info(
830                                     &txninfop, &data2)) != 0)
831                                         goto out;
832                                 if ((ret = handler(lvinfo, txninfop,
833                                     param)) != 0)
834                                         /* Stop the iteration on error. */
835                                         goto out;
836                         }
837                 }
838
839         }
840 out:
841         if (ret == DB_NOTFOUND)
842                 ret = 0;
843 err:
844         if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
845                 ret = tret;
846         __os_free(lvinfo->dbenv->env, btbuf);
847         return (ret);
848 }
849
850 /* Txninfo iteration handler to add recycle info for affected txns. */
851 static int
852 __lv_add_recycle_handler(lvinfo, txninfop, params)
853         DB_LOG_VRFY_INFO *lvinfo;
854         VRFY_TXN_INFO *txninfop;
855         void *params;
856 {
857         int ret;
858         struct __add_recycle_params *param;
859
860         ret = 0;
861         param = (struct __add_recycle_params *)params;
862
863         /*
864          * If the txnid is reused, update its recycle info and note it for
865          * later update, otherwise free the txninfop structure.
866          */
867         if (txninfop->txnid < param->min && txninfop->txnid > param->max) {
868                 ret = __free_txninfo(txninfop);
869                 return (ret);
870         }
871
872         ret = __lv_add_recycle_lsn(txninfop, &(param->recycle_lsn));
873
874         if (ret != 0)
875                 goto err;
876         /*
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
881          * txns.
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);
886          */
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);
893         }
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),
899                     &(param->ti2u)));
900 err:
901         return (ret);
902
903 }
904 /*
905  * PUBLIC: int __rem_last_recycle_lsn __P((VRFY_TXN_INFO *));
906  */
907 int
908 __rem_last_recycle_lsn(txninfop)
909         VRFY_TXN_INFO *txninfop;
910 {
911         int ret;
912
913         ret = 0;
914         if (txninfop->num_recycle == 0)
915                 return (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)));
920         else {
921                 __os_free(NULL, txninfop->recycle_lsns);
922                 txninfop->recycle_lsns = NULL;
923         }
924 err:
925         return (ret);
926
927 }
928
929 /*
930  * __add_file_updated --
931  *      Add a file's dbregid and uid to the updating txn if it's not yet
932  *      recorded.
933  *
934  * PUBLIC: int __add_file_updated __P((VRFY_TXN_INFO *, const DBT *, int32_t));
935  */
936 int
937 __add_file_updated (txninfop, fileid, dbregid)
938         VRFY_TXN_INFO *txninfop;
939         const DBT *fileid;
940         int32_t dbregid;
941 {
942         int ret;
943         DBT *pdbt, *p;
944         u_int32_t found, i;
945
946         ret = 0;
947         p = pdbt = NULL;
948
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) {
953                         found = 1;
954                         break;
955                 }
956         }
957
958         if (found)
959                 return (0);
960
961         /* Add file's uid into the array, deep copy from fileid. */
962         txninfop->filenum++;
963         if ((ret = __os_realloc(NULL, txninfop->filenum *
964             sizeof(DBT), &(txninfop->fileups))) != 0)
965                 goto err;
966
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)
971                 goto err;
972         memcpy(pdbt->data, fileid->data, fileid->size);
973
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;
978 err:
979         return (ret);
980 }
981
982 /*
983  * PUBLIC: int __del_file_updated __P((VRFY_TXN_INFO *, const DBT *));
984  */
985 int
986 __del_file_updated (txninfop, fileid)
987         VRFY_TXN_INFO *txninfop;
988         const DBT *fileid;
989 {
990         u_int32_t found, i;
991         int ret;
992         DBT *p;
993         void *pdbtdata;
994
995         ret = 0;
996
997         if (txninfop->filenum == 0)
998                 return (0);
999
1000         /*
1001          * If the array has an element identical to fileid, remove it. fileid
1002          * itself is intact after this function call.
1003          */
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) {
1008                         pdbtdata = p->data;
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)));
1016                         } else {
1017                                 __os_free(NULL, txninfop->fileups);
1018                                 __os_free(NULL, txninfop->dbregid);
1019                                 txninfop->fileups = NULL;
1020                                 txninfop->dbregid = NULL;
1021                         }
1022                         found = 1;
1023                         break;
1024                 }
1025         }
1026
1027         if (found) {
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)));
1034                 }
1035                 __os_free(NULL, pdbtdata);
1036         }
1037 err:
1038         return (ret);
1039 }
1040
1041 /*
1042  * PUBLIC: int __clear_fileups __P((VRFY_TXN_INFO *));
1043  */
1044 int
1045 __clear_fileups(txninfop)
1046         VRFY_TXN_INFO *txninfop;
1047 {
1048         u_int32_t i;
1049
1050         for (i = 0; i < txninfop->filenum; i++)
1051                 __os_free(NULL, txninfop->fileups[i].data);
1052
1053         __os_free(NULL, txninfop->fileups);
1054         __os_free(NULL, txninfop->dbregid);
1055         txninfop->fileups = NULL;
1056         txninfop->dbregid = NULL;
1057         txninfop->filenum = 0;
1058
1059         return (0);
1060 }
1061
1062 /*
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 *));
1066  */
1067 int
1068 __free_txninfo_stack (p)
1069         VRFY_TXN_INFO *p;
1070 {
1071         u_int32_t i;
1072
1073         if (p == NULL)
1074                 return (0);
1075
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);
1080         }
1081
1082         if (p->dbregid != NULL)
1083                 __os_free(NULL, p->dbregid);
1084
1085         if (p->recycle_lsns != NULL)
1086                 __os_free(NULL, p->recycle_lsns);
1087
1088         return (0);
1089 }
1090 /*
1091  * PUBLIC: int __free_txninfo __P((VRFY_TXN_INFO *));
1092  */
1093 int
1094 __free_txninfo(p)
1095         VRFY_TXN_INFO *p;
1096 {
1097         (void)__free_txninfo_stack(p);
1098         __os_free(NULL, p);
1099
1100         return (0);
1101 }
1102
1103 /* Construct a key and data DBT from the structure. */
1104 static int
1105 __lv_pack_filereg(freginfo, data)
1106         const VRFY_FILEREG_INFO *freginfo;
1107         DBT *data;
1108 {
1109         char *buf, *p;
1110         size_t bufsz, offset;
1111         int ret;
1112
1113         ret = 0;
1114         if ((ret = __os_malloc(NULL,
1115             bufsz = FILE_REG_INFO_TOTSIZE(*freginfo), &buf)) != 0)
1116                 goto err;
1117         memset(buf, 0, bufsz);
1118
1119         memcpy(buf, freginfo, FILE_REG_INFO_FIXSIZE);
1120         p = buf + FILE_REG_INFO_FIXSIZE;
1121
1122         offset = sizeof(int32_t) * freginfo->regcnt;
1123         memcpy(p, freginfo->dbregids, offset);
1124         p += offset;
1125
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);
1131
1132         data->data = buf;
1133         data->size = (u_int32_t)bufsz;
1134 err:
1135         return (ret);
1136 }
1137
1138 /*
1139  * PUBLIC: int __put_filereg_info __P((const DB_LOG_VRFY_INFO *,
1140  * PUBLIC:    const VRFY_FILEREG_INFO *));
1141  */
1142 int __put_filereg_info (lvinfo, freginfo)
1143         const DB_LOG_VRFY_INFO *lvinfo;
1144         const VRFY_FILEREG_INFO *freginfo;
1145 {
1146
1147         int ret;
1148         DBT data;
1149
1150         memset(&data, 0, sizeof(DBT));
1151
1152         if ((ret = __lv_pack_filereg(freginfo, &data)) != 0)
1153                 goto err;
1154
1155         /*
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.
1161          *
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.
1165          */
1166
1167         BDBOP2(lvinfo->dbenv, __db_put(lvinfo->fileregs, lvinfo->ip, NULL,
1168             (DBT *)&(freginfo->fileid), &data, 0), "__put_filereg_info");
1169
1170 err:
1171         if (data.data != NULL)
1172                 __os_free(lvinfo->dbenv->env, data.data);
1173
1174         return (ret);
1175 }
1176
1177 /*
1178  * PUBLIC: int __del_filelife __P((const DB_LOG_VRFY_INFO *, int32_t));
1179  */
1180 int
1181 __del_filelife(lvinfo, dbregid)
1182         const DB_LOG_VRFY_INFO *lvinfo;
1183         int32_t dbregid;
1184 {
1185         int ret;
1186         DBT key;
1187
1188         memset(&key, 0, sizeof(DBT));
1189         key.data = &(dbregid);
1190         key.size = sizeof(dbregid);
1191
1192         if ((ret = __db_del(lvinfo->dbregids, lvinfo->ip, NULL,
1193             &key, 0)) != 0)
1194                 goto err;
1195
1196 err:
1197         return (ret);
1198 }
1199
1200 /*
1201  * PUBLIC: int __put_filelife __P((const DB_LOG_VRFY_INFO *, VRFY_FILELIFE *));
1202  */
1203 int
1204 __put_filelife (lvinfo, pflife)
1205         const DB_LOG_VRFY_INFO *lvinfo;
1206         VRFY_FILELIFE *pflife;
1207 {
1208         int ret;
1209         DBT key, data;
1210
1211         memset(&key, 0, sizeof(DBT));
1212         memset(&data, 0, sizeof(DBT));
1213         key.data = &(pflife->dbregid);
1214         key.size = sizeof(pflife->dbregid);
1215         data.data = pflife;
1216         data.size = sizeof(VRFY_FILELIFE);
1217
1218         if ((ret = __db_put(lvinfo->dbregids, lvinfo->ip, NULL,
1219             &key, &data, 0)) != 0)
1220                 goto err;
1221
1222 err:
1223         return (ret);
1224 }
1225
1226 /*
1227  * PUBLIC: int __get_filelife __P((const DB_LOG_VRFY_INFO *,
1228  * PUBLIC:     int32_t, VRFY_FILELIFE **));
1229  */
1230 int
1231 __get_filelife (lvinfo, dbregid, flifepp)
1232         const DB_LOG_VRFY_INFO *lvinfo;
1233         int32_t dbregid;
1234         VRFY_FILELIFE **flifepp;
1235 {
1236         int ret;
1237         DBT key, data;
1238         VRFY_FILELIFE *flifep;
1239
1240         ret = 0;
1241         flifep = NULL;
1242         memset(&key, 0, sizeof(DBT));
1243         memset(&data, 0, sizeof(DBT));
1244
1245         key.data = &dbregid;
1246         key.size = sizeof(dbregid);
1247         if ((ret = __db_get(lvinfo->dbregids, lvinfo->ip, NULL,
1248             &key, &data, 0)) != 0)
1249                 goto err;
1250         if ((ret = __os_malloc(lvinfo->dbenv->env,
1251             sizeof(VRFY_FILELIFE), &flifep)) != 0)
1252                 goto err;
1253         DB_ASSERT(lvinfo->dbenv->env, flifep != NULL);
1254         memcpy(flifep, data.data, sizeof(VRFY_FILELIFE));
1255         *flifepp = flifep;
1256 err:
1257         return (ret);
1258 }
1259
1260 /*
1261  * PUBLIC: int __get_filereg_by_dbregid __P((const DB_LOG_VRFY_INFO *,
1262  * PUBLIC:     int32_t, VRFY_FILEREG_INFO **));
1263  */
1264 int
1265 __get_filereg_by_dbregid(lvinfo, dbregid, freginfopp)
1266         const DB_LOG_VRFY_INFO *lvinfo;
1267         int32_t dbregid;
1268         VRFY_FILEREG_INFO **freginfopp;
1269 {
1270         int ret;
1271         DBT key, data;
1272         char uid[DB_FILE_ID_LEN];
1273         VRFY_FILELIFE *pflife;
1274
1275         memset(&data, 0, sizeof(DBT));
1276         memset(&key, 0, sizeof(DBT));
1277         key.data = &dbregid;
1278         key.size = sizeof(dbregid);
1279
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)
1283                 goto err;
1284
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);
1288
1289         key.data = (void *)uid;
1290         memset(&data, 0, sizeof(DBT));
1291
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)
1295                 goto err;
1296         if ((ret = __lv_unpack_filereg(&data, freginfopp)) != 0)
1297                 goto err;
1298
1299 err:
1300         return (ret);
1301 }
1302
1303 /*
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 *));
1306  */
1307 int
1308 __add_dbregid(lvh, freg, dbregid, opcode, lsn, dbtype, meta_pgno, addp)
1309         DB_LOG_VRFY_INFO *lvh;
1310         VRFY_FILEREG_INFO *freg;
1311         int32_t dbregid;
1312         u_int32_t opcode;
1313         DB_LSN lsn;
1314         DBTYPE dbtype;
1315         db_pgno_t meta_pgno;
1316         int *addp;
1317 {
1318         int inarray, ret, tret;
1319         u_int32_t i, j;
1320         VRFY_FILELIFE flife;
1321
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)) {
1330                                         tret = 2;
1331                                         goto err;
1332                                 }
1333                                 tret = 0;
1334                                 inarray = 1;
1335                         } else
1336                                 /* Found the dbregid; gonna remove it. */
1337                                 tret = -1;
1338                         break;
1339                 }
1340         }
1341
1342         if (IS_DBREG_OPEN(opcode))
1343                 tret = 1;/* dbregid not in the array, gonna add 1. */
1344
1345         /*
1346          * Remove closed dbregid. dbregid can be recycled, not unique to a db
1347          * file, it's dynamically allocated for each db handle.
1348          */
1349         if (tret == -1) {
1350                 for (j = i; j < freg->regcnt - 1; j++)
1351                         freg->dbregids[j] = freg->dbregids[j + 1];
1352                 freg->regcnt--;
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) {
1357                 if (!inarray) {
1358                         freg->regcnt++;
1359                         BDBOP(__os_realloc(lvh->dbenv->env,
1360                             sizeof(int32_t) * freg->regcnt, &(freg->dbregids)));
1361                         freg->dbregids[freg->regcnt - 1] = dbregid;
1362                 }
1363                 flife.dbregid = dbregid;
1364                 memcpy(flife.fileid, freg->fileid.data, freg->fileid.size);
1365                 flife.lifetime = opcode;
1366                 flife.dbtype = dbtype;
1367                 flife.lsn = lsn;
1368                 flife.meta_pgno = meta_pgno;
1369                 if ((ret = __put_filelife(lvh, &flife)) != 0)
1370                         goto err;
1371         }
1372
1373 err:
1374         *addp = tret;
1375         return (ret);
1376
1377 }
1378
1379 /*
1380  * PUBLIC: int __get_filereg_info __P((const DB_LOG_VRFY_INFO *, const DBT *,
1381  * PUBLIC:     VRFY_FILEREG_INFO **));
1382  */
1383 int
1384 __get_filereg_info (lvinfo, fuid, freginfopp)
1385         const DB_LOG_VRFY_INFO *lvinfo;
1386         const DBT *fuid;
1387         VRFY_FILEREG_INFO **freginfopp;
1388 {
1389         int ret;
1390         DBT data;
1391
1392         memset(&data, 0, sizeof(DBT));
1393
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)
1397                 goto err;
1398         if ((ret = __lv_unpack_filereg(&data, freginfopp)) != 0)
1399                 goto err;
1400
1401 err:
1402         return (ret);
1403 }
1404
1405 static int
1406 __lv_unpack_filereg(data, freginfopp)
1407         const DBT *data;
1408         VRFY_FILEREG_INFO **freginfopp;
1409 {
1410         char *p, *q;
1411         u_int32_t fidsz, arrsz;
1412         VRFY_FILEREG_INFO *buf;
1413         int ret;
1414
1415         ret = 0;
1416         p = q = NULL;
1417         fidsz = arrsz = 0;
1418         buf = NULL;
1419
1420         if ((ret = __os_malloc(NULL, sizeof(VRFY_FILEREG_INFO), &buf)) != 0)
1421                 goto err;
1422         memset(buf, 0, sizeof(VRFY_FILEREG_INFO));
1423
1424         memcpy(buf, data->data, FILE_REG_INFO_FIXSIZE);
1425         *freginfopp = (VRFY_FILEREG_INFO *)buf;
1426         p = ((char *)(data->data)) + FILE_REG_INFO_FIXSIZE;
1427
1428         if ((ret = __os_malloc(NULL, arrsz = (*freginfopp)->regcnt *
1429             sizeof(int32_t), &((*freginfopp)->dbregids))) != 0)
1430                 goto err;
1431         memcpy((*freginfopp)->dbregids, p, arrsz);
1432         p += arrsz;
1433
1434         memcpy(&fidsz, p, sizeof(fidsz));
1435         p += sizeof(fidsz);
1436         if ((ret = __os_malloc(NULL, fidsz, &q)) != 0)
1437                 goto err;
1438         memcpy(q, p, fidsz);
1439         (*freginfopp)->fileid.data = q;
1440         (*freginfopp)->fileid.size = fidsz;
1441         p += fidsz;
1442
1443         if ((ret = __os_malloc(NULL, sizeof(char) * (strlen(p) + 1), &q)) != 0)
1444                 goto err;
1445         (void)strcpy(q, p);
1446
1447         (*freginfopp)->fname = q;
1448 err:
1449         return (ret);
1450 }
1451
1452 /*
1453  * PUBLIC: int __free_filereg_info __P((VRFY_FILEREG_INFO *));
1454  */
1455 int
1456 __free_filereg_info(p)
1457         VRFY_FILEREG_INFO *p;
1458 {
1459         if (p == NULL)
1460                 return (0);
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);
1467         __os_free(NULL, p);
1468
1469         return (0);
1470 }
1471
1472 /*
1473  * PUBLIC: int __get_ckp_info __P((const DB_LOG_VRFY_INFO *, DB_LSN,
1474  * PUBLIC:     VRFY_CKP_INFO **));
1475  */
1476 int
1477 __get_ckp_info (lvinfo, lsn, ckpinfopp)
1478         const DB_LOG_VRFY_INFO *lvinfo;
1479         DB_LSN lsn;
1480         VRFY_CKP_INFO **ckpinfopp;
1481 {
1482         int ret;
1483         DBT key, data;
1484         VRFY_CKP_INFO *ckpinfo;
1485
1486         memset(&key, 0, sizeof(DBT));
1487         memset(&data, 0, sizeof(DBT));
1488         key.data = &lsn;
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");
1492
1493         if (ret == DB_NOTFOUND)
1494                 goto err;
1495
1496         if ((ret = __os_malloc(lvinfo->dbenv->env,
1497             sizeof(VRFY_CKP_INFO), &ckpinfo)) != 0)
1498                 goto err;
1499         memcpy(ckpinfo, data.data, sizeof(VRFY_CKP_INFO));
1500         *ckpinfopp = ckpinfo;
1501 err:
1502         return (ret);
1503
1504 }
1505
1506 /*
1507  * PUBLIC: int __get_last_ckp_info __P((const DB_LOG_VRFY_INFO *,
1508  * PUBLIC:     VRFY_CKP_INFO **));
1509  */
1510 int
1511 __get_last_ckp_info (lvinfo, ckpinfopp)
1512         const DB_LOG_VRFY_INFO *lvinfo;
1513         VRFY_CKP_INFO **ckpinfopp;
1514 {
1515         int ret, tret;
1516         DBT key, data;
1517         VRFY_CKP_INFO *ckpinfo;
1518         DBC *csr;
1519
1520         csr = NULL;
1521         memset(&key, 0, sizeof(DBT));
1522         memset(&data, 0, sizeof(DBT));
1523
1524         BDBOP(__db_cursor(lvinfo->ckps, lvinfo->ip, NULL, &csr, 0));
1525         if ((ret = __dbc_get(csr, &key, &data, DB_LAST)) != 0)
1526                 goto err;
1527
1528         if ((ret = __os_malloc(lvinfo->dbenv->env,
1529             sizeof(VRFY_CKP_INFO), &ckpinfo)) != 0)
1530                 goto err;
1531         DB_ASSERT(lvinfo->dbenv->env, sizeof(VRFY_CKP_INFO) == data.size);
1532         memcpy(ckpinfo, data.data, sizeof(VRFY_CKP_INFO));
1533         *ckpinfopp = ckpinfo;
1534 err:
1535         if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1536                 ret = tret;
1537         if (ret != 0 && ret != DB_NOTFOUND)
1538                 __db_err(lvinfo->dbenv->env, ret, "__get_last_ckp_info");
1539         return (ret);
1540 }
1541
1542 /*
1543  * PUBLIC: int __put_ckp_info __P((const DB_LOG_VRFY_INFO *,
1544  * PUBLIC:     const VRFY_CKP_INFO *));
1545  */
1546 int __put_ckp_info (lvinfo, ckpinfo)
1547         const DB_LOG_VRFY_INFO *lvinfo;
1548         const VRFY_CKP_INFO *ckpinfo;
1549 {
1550         int ret;
1551         DBT key, data;
1552
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);
1559
1560         BDBOP2(lvinfo->dbenv, __db_put(lvinfo->ckps, lvinfo->ip,
1561             NULL, &key, &data, 0), "__put_ckp_info");
1562         return (0);
1563 }
1564
1565 /*
1566  * PUBLIC: int __get_timestamp_info __P((const DB_LOG_VRFY_INFO *,
1567  * PUBLIC:     DB_LSN, VRFY_TIMESTAMP_INFO **));
1568  */
1569 int __get_timestamp_info (lvinfo, lsn, tsinfopp)
1570         const DB_LOG_VRFY_INFO *lvinfo;
1571         DB_LSN lsn;
1572         VRFY_TIMESTAMP_INFO **tsinfopp;
1573 {
1574         int ret;
1575         DBT key, data;
1576         VRFY_TIMESTAMP_INFO *tsinfo;
1577
1578         memset(&key, 0, sizeof(DBT));
1579         memset(&data, 0, sizeof(DBT));
1580         key.data = &lsn;
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");
1584
1585         if (ret == DB_NOTFOUND)
1586                 goto err;
1587
1588         if ((ret = __os_malloc(lvinfo->dbenv->env,
1589             sizeof(VRFY_TIMESTAMP_INFO), &tsinfo)) != 0)
1590                 goto err;
1591
1592         memcpy(tsinfo, data.data, sizeof(VRFY_TIMESTAMP_INFO));
1593         *tsinfopp = tsinfo;
1594 err:
1595         return (ret);
1596 }
1597
1598 /*
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 **));
1603  */
1604 int __get_latest_timestamp_info(lvinfo, lsn, tsinfopp)
1605         const DB_LOG_VRFY_INFO *lvinfo;
1606         DB_LSN lsn;
1607         VRFY_TIMESTAMP_INFO **tsinfopp;
1608 {
1609         int ret, tret;
1610         DBT key, data;
1611         VRFY_TIMESTAMP_INFO *tsinfo;
1612         DBC *csr;
1613
1614         csr = NULL;
1615         ret = tret = 0;
1616         memset(&key, 0, sizeof(DBT));
1617         memset(&data, 0, sizeof(DBT));
1618
1619         key.data = &lsn;
1620         key.size = sizeof(lsn);
1621         BDBOP(__db_cursor(lvinfo->lsntime, lvinfo->ip, NULL, &csr, 0));
1622
1623         BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1624         BDBOP(__dbc_get(csr, &key, &data, DB_PREV));
1625
1626         if ((ret = __os_malloc(lvinfo->dbenv->env, sizeof(VRFY_TIMESTAMP_INFO),
1627             &tsinfo)) != 0)
1628                 goto err;
1629
1630         memcpy(tsinfo, data.data, sizeof(VRFY_TIMESTAMP_INFO));
1631         *tsinfopp = tsinfo;
1632
1633 err:
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)
1638                 ret = tret;
1639         return (ret);
1640 }
1641
1642 /*
1643  * PUBLIC: int __put_timestamp_info __P((const DB_LOG_VRFY_INFO *,
1644  * PUBLIC:     const VRFY_TIMESTAMP_INFO *));
1645  */
1646 int __put_timestamp_info (lvinfo, tsinfo)
1647         const DB_LOG_VRFY_INFO *lvinfo;
1648         const VRFY_TIMESTAMP_INFO *tsinfo;
1649 {
1650         int ret;
1651         DBT key, data;
1652
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");
1661
1662         return (0);
1663 }
1664
1665 static int
1666 __lv_txnrgns_lsn_cmp (db, d1, d2)
1667         DB *db;
1668         const DBT *d1, *d2;
1669 {
1670         struct __lv_txnrange r1, r2;
1671
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);
1676
1677         return (LOG_COMPARE(&(r1.end), &(r2.end)));
1678 }
1679
1680 /*
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 *));
1686  */
1687 int
1688 __find_lsnrg_by_timerg(lvinfo, begin, end, startlsn, endlsn)
1689         DB_LOG_VRFY_INFO *lvinfo;
1690         time_t begin, end;
1691         DB_LSN *startlsn, *endlsn;
1692 {
1693         int ret, tret;
1694         DBC *csr;
1695         struct __lv_timestamp_info *t1, *t2;
1696         DBT key, data;
1697
1698         ret = tret = 0;
1699         csr = NULL;
1700         memset(&key, 0, sizeof(DBT));
1701         memset(&data, 0, sizeof(DBT));
1702
1703         BDBOP(__db_cursor(lvinfo->timelsn, lvinfo->ip, NULL, &csr, 0));
1704
1705         /*
1706          * We want a lsn range that completely contains [begin, end], so
1707          * try move 1 record prev when getting the startlsn.
1708          */
1709         key.data = &begin;
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 &&
1713             ret != DB_NOTFOUND)
1714                 goto err;
1715         if (ret == DB_NOTFOUND)/* begin is smaller than the smallest key. */
1716                 startlsn->file = startlsn->offset = 0;/* beginning. */
1717         else {
1718                 t1 = (struct __lv_timestamp_info *)data.data;
1719                 *startlsn = t1->lsn;
1720         }
1721
1722         /*
1723          * Move to the last key/data pair of the duplicate set to get the
1724          * biggest lsn having end as timestamp.
1725          */
1726         key.data = &end;
1727         key.size = sizeof(end);
1728         if ((ret = __dbc_get(csr, &key, &data, DB_SET_RANGE)) != 0 &&
1729             ret != DB_NOTFOUND)
1730                 goto err;
1731         if (ret == DB_NOTFOUND) {
1732                 endlsn->file = endlsn->offset = (u_int32_t)-1;/* Biggest lsn. */
1733                 ret = 0;
1734                 goto err; /* We are done. */
1735         }
1736
1737         /*
1738          * Go to the biggest lsn of the dup set, if the key is the last one,
1739          * go to the last one.
1740          */
1741         if ((ret = __dbc_get(csr, &key, &data, DB_NEXT_NODUP)) != 0 &&
1742             ret != DB_NOTFOUND)
1743                 goto err;
1744
1745         if (ret == DB_NOTFOUND)
1746                 BDBOP(__dbc_get(csr, &key, &data, DB_LAST));
1747         else
1748                 BDBOP(__dbc_get(csr, &key, &data, DB_PREV));
1749
1750         t2 = (struct __lv_timestamp_info *)data.data;
1751         *endlsn = t2->lsn;
1752 err:
1753         if (ret == DB_NOTFOUND)
1754                 ret = 0;
1755         if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1756                 ret = tret;
1757         return (ret);
1758 }
1759
1760 /*
1761  * PUBLIC: int __add_txnrange __P((DB_LOG_VRFY_INFO *, u_int32_t,
1762  * PUBLIC:     DB_LSN, int32_t, int));
1763  */
1764 int __add_txnrange (lvinfo, txnid, lsn, when, ishead)
1765         DB_LOG_VRFY_INFO *lvinfo;
1766         u_int32_t txnid;
1767         DB_LSN lsn;
1768         int32_t when;
1769         int ishead; /* Whether it's the 1st log of the txn. */
1770 {
1771         int ret, tret;
1772         DBC *csr;
1773         struct __lv_txnrange tr, *ptr;
1774         DBT key, data;
1775
1776         csr = NULL;
1777         ret = 0;
1778         ptr = NULL;
1779         memset(&key, 0, sizeof(DBT));
1780         memset(&data, 0, sizeof(DBT));
1781         memset(&tr, 0, sizeof(tr));
1782
1783         key.data = &txnid;
1784         key.size = sizeof(txnid);
1785         tr.txnid = txnid;
1786         BDBOP(__db_cursor(lvinfo->txnrngs, lvinfo->ip, NULL, &csr, 0));
1787         /*
1788          * Note that we will backward play the logs to gather such information.
1789          */
1790         if (!ishead) {
1791                 tr.end = lsn;
1792                 tr.when_commit = when;
1793                 data.data = &tr;
1794                 data.size = sizeof(tr);
1795                 BDBOP(__dbc_put(csr, &key, &data, DB_KEYFIRST));
1796         } else {
1797                 /*
1798                  * Dup data sorted by lsn, and we are backward playing logs,
1799                  * so the 1st record should be the one we want.
1800                  */
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));
1804                 ptr->begin = lsn;
1805                 BDBOP(__dbc_put(csr, &key, &data, DB_CURRENT));
1806         }
1807
1808 err:
1809         if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1810                 ret = tret;
1811         return (ret);
1812 }
1813
1814 /*
1815  * __get_aborttxn --
1816  *      If lsn is the last log of an aborted txn T, T's txnid is
1817  *      returned via the log verify handle.
1818  *
1819  * PUBLIC: int __get_aborttxn __P((DB_LOG_VRFY_INFO *, DB_LSN));
1820  */
1821 int
1822 __get_aborttxn(lvinfo, lsn)
1823         DB_LOG_VRFY_INFO *lvinfo;
1824         DB_LSN lsn;
1825 {
1826         int ret, tret;
1827         u_int32_t txnid;
1828         DBC *csr;
1829         DBT key, data;
1830
1831         csr = NULL;
1832         txnid = 0;
1833         ret = tret = 0;
1834         memset(&key, 0, sizeof(DBT));
1835         memset(&data, 0, sizeof(DBT));
1836
1837         key.data = &lsn;
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);
1842         /*
1843          * The lsn is the last op of an aborted txn, call __on_txnabort
1844          * before processing next log record.
1845          */
1846         lvinfo->aborted_txnid = txnid;
1847         lvinfo->aborted_txnlsn = lsn;
1848
1849 err:
1850         /* It's OK if can't find it. */
1851         if (ret == DB_NOTFOUND)
1852                 ret = 0;
1853         if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1854                 ret = tret;
1855         return (ret);
1856 }
1857
1858 /*
1859  * __txn_started --
1860  *      Whether txnid is started before lsn and ended after lsn.
1861  *
1862  * PUBLIC: int __txn_started __P((DB_LOG_VRFY_INFO *,
1863  * PUBLIC:     DB_LSN, u_int32_t, int *));
1864  */
1865 int
1866 __txn_started(lvinfo, lsn, txnid, res)
1867         DB_LOG_VRFY_INFO *lvinfo;
1868         DB_LSN lsn;
1869         u_int32_t txnid;
1870         int *res;
1871 {
1872         int ret, tret;
1873         DBC *csr;
1874         DBT key, data;
1875         struct __lv_txnrange *ptr, tr;
1876
1877         ret = *res = 0;
1878         csr = NULL;
1879         memset(&tr, 0, sizeof(tr));
1880         memset(&key, 0, sizeof(DBT));
1881         memset(&data, 0, sizeof(DBT));
1882         key.data = &txnid;
1883         key.size = sizeof(txnid);
1884
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) {
1891                         *res = 1;
1892                         break;
1893                 }
1894         }
1895 err:
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)
1899                 ret = tret;
1900         return (ret);
1901 }
1902
1903 /*
1904  * PUBLIC: int __set_logvrfy_dbfuid __P((DB_LOG_VRFY_INFO *));
1905  */
1906 int
1907 __set_logvrfy_dbfuid(lvinfo)
1908         DB_LOG_VRFY_INFO *lvinfo;
1909 {
1910         int ret;
1911         const char *p;
1912         DBT key, data;
1913         size_t buflen;
1914
1915         p = NULL;
1916         memset(&key, 0, sizeof(DBT));
1917         memset(&data, 0, sizeof(DBT));
1918
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;
1924
1925         BDBOP2(lvinfo->dbenv, __db_get(lvinfo->fnameuid, lvinfo->ip, NULL,
1926             &key, &data, 0), "__set_logvrfy_dbfuid");
1927
1928         memcpy(lvinfo->target_dbid, data.data, DB_FILE_ID_LEN);
1929
1930         return (ret);
1931 }
1932
1933 /*
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 *));
1939  */
1940 int
1941 __add_page_to_txn (lvinfo, dbregid, pgno, txnid, otxn, result)
1942         DB_LOG_VRFY_INFO *lvinfo;
1943         int32_t dbregid;
1944         db_pgno_t pgno;
1945         u_int32_t txnid, *otxn;
1946         int *result;
1947 {
1948         int ret;
1949         u_int8_t *buf;
1950         DBT key, data;
1951         size_t buflen;
1952         u_int32_t txnid2;
1953         VRFY_FILELIFE *pff;
1954
1955         if (txnid < TXN_MINIMUM) {
1956                 *result = 0;
1957                 return (0);
1958         }
1959         buf = NULL;
1960         ret = 0;
1961         txnid2 = 0;
1962         pff = NULL;
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));
1968
1969         /*
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
1973          * dbregid as key.
1974          */
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)) {
1981                                 ret = 0;
1982                                 goto out;
1983                         } else
1984                                 F_SET(lvinfo, DB_LOG_VERIFY_INTERR);
1985                 }
1986                 goto err;
1987         }
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));
1993         key.data = buf;
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) {
1998                         data.data = &txnid;
1999                         data.size = sizeof(txnid);
2000                         BDBOP(__db_put(lvinfo->pgtxn, lvinfo->ip, NULL, &key,
2001                             &data, 0));
2002                         *result = 1;
2003                         ret = 0;/* This is not an error. */
2004                 }
2005                 goto err;
2006         }
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. */
2010                 *result = 0;
2011         else {/* Txn txnid is updating pages still held by txnid2. */
2012                 *result = -1;
2013                 *otxn = txnid2;
2014         }
2015 out:
2016         /* result is set to -1 on violation, 0 if already has it, 1 if added. */
2017 err:
2018         if (buf != NULL)
2019                 __os_free(lvinfo->dbenv->env, buf);
2020         return (ret);
2021 }
2022
2023 /*
2024  * PUBLIC: int __del_txn_pages __P((DB_LOG_VRFY_INFO *, u_int32_t));
2025  */
2026 int
2027 __del_txn_pages(lvinfo, txnid)
2028         DB_LOG_VRFY_INFO *lvinfo;
2029         u_int32_t txnid;
2030 {
2031         int ret;
2032         DBT key;
2033
2034         ret = 0;
2035         memset(&key, 0, sizeof(DBT));
2036         key.data = &txnid;
2037         key.size = sizeof(txnid);
2038
2039         BDBOP(__db_del(lvinfo->txnpg, lvinfo->ip, NULL, &key, 0));
2040
2041 err:
2042         return (ret);
2043 }
2044
2045 /*
2046  * __is_ancestor_txn --
2047  *      Tells via res if ptxnid is txnid's parent txn at the moment of lsn.
2048  *
2049  * PUBLIC: int __is_ancestor_txn __P((DB_LOG_VRFY_INFO *,
2050  * PUBLIC:     u_int32_t, u_int32_t, DB_LSN, int *));
2051  */
2052 int
2053 __is_ancestor_txn (lvinfo, ptxnid, txnid, lsn, res)
2054         DB_LOG_VRFY_INFO *lvinfo;
2055         u_int32_t ptxnid, txnid;
2056         DB_LSN lsn;
2057         int *res;
2058 {
2059         u_int32_t ptid;
2060         int ret, tret;
2061         DBC *csr;
2062         DB *pdb;
2063         DBT key, data;
2064         struct __lv_txnrange tr;
2065
2066         ret = 0;
2067         ptid = txnid;
2068         csr = NULL;
2069         pdb = lvinfo->txnrngs;
2070         memset(&key, 0, sizeof(DBT));
2071         memset(&data, 0, sizeof(DBT));
2072         *res = 0;
2073         BDBOP(__db_cursor(pdb, lvinfo->ip, NULL, &csr, 0));
2074
2075         /* See if ptxnid is an ancestor of txnid. */
2076         do {
2077                 key.data = &ptid;
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. */
2081                 for (;ret == 0;
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)
2088                                 break;
2089                 }
2090
2091                 if (tr.ptxnid == ptxnid) {
2092                         *res = 1;
2093                         goto out;
2094                 } else
2095                         ptid = tr.ptxnid;
2096
2097         } while (ptid != 0);
2098 out:
2099
2100 err:
2101         if (ret == DB_NOTFOUND)
2102                 ret = 0;
2103         if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
2104                 ret = tret;
2105         return (ret);
2106 }
2107
2108 /*
2109  * PUBLIC: int __return_txn_pages __P((DB_LOG_VRFY_INFO *,
2110  * PUBLIC:     u_int32_t, u_int32_t));
2111  */
2112 int __return_txn_pages(lvh, ctxn, ptxn)
2113         DB_LOG_VRFY_INFO *lvh;
2114         u_int32_t ctxn, ptxn;
2115 {
2116         int ret, tret;
2117         DBC *csr;
2118         DB *pdb, *sdb;
2119         DBT key, key2, data, data2;
2120         char buf[DB_FILE_ID_LEN + sizeof(db_pgno_t)];
2121
2122         ret = tret = 0;
2123         csr = NULL;
2124         sdb = lvh->txnpg;
2125         pdb = lvh->pgtxn;
2126         memset(&key, 0, sizeof(DBT));
2127         memset(&key2, 0, sizeof(DBT));
2128         memset(&data, 0, sizeof(DBT));
2129         memset(&data2, 0, sizeof(DBT));
2130
2131         BDBOP(__db_cursor(sdb, lvh->ip, NULL, &csr, 0));
2132         key.data = &ctxn;
2133         key.size = sizeof(ctxn);
2134         key2.data = &ptxn;
2135         key2.size = sizeof(ptxn);
2136         data2.data = buf;
2137         data2.ulen = DB_FILE_ID_LEN + sizeof(db_pgno_t);
2138         data2.flags = DB_DBT_USERMEM;
2139
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)
2144                 goto err;
2145 err:
2146         if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
2147                 ret = tret;
2148         return (ret);
2149 }
2150
2151 #define ADD_ITEM(lvh, logtype) ((lvh)->logtype_names[(logtype)] = (#logtype))
2152 static void
2153 __lv_setup_logtype_names(lvinfo)
2154         DB_LOG_VRFY_INFO *lvinfo;
2155 {
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);
2194 #ifdef HAVE_HASH
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);
2208 #endif
2209 #ifdef HAVE_QUEUE
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);
2215 #endif
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);
2234 }