1 /*-
2  * Copyright (c) 1996, 2020 Oracle and/or its affiliates.  All rights reserved.
3  *
4  * See the file LICENSE for license information.
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 *, size_t *);
57 typedef int (*dupcmp_funct)(DB *, const DBT *, const DBT *, size_t *);
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 *, size_t *));
64 static int __lv_i32_cmp __P((DB *, const DBT *, const DBT *, size_t *));
65 static int __lv_lsn_cmp __P((DB *, const DBT *, const DBT *, size_t *));
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 *, size_t *));
77 static int __lv_ui32_cmp __P((DB *, const DBT *, const DBT *, size_t *));
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 
__lv_on_bdbop_err(ret)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
__create_log_vrfy_info(cfg,lvinfopp,ip)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
__destroy_log_vrfy_info(lvinfop)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
__lv_seccbk_fname(secdb,key,data,result)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 	freg = NULL;
272 	COMPQUIET(key, NULL);
273 	if ((ret = __lv_unpack_filereg(data, &freg)) != 0)
274 		goto out;
275 	if (freg->fname == NULL || (slen = strlen(freg->fname)) == 0) {
276 		ret = DB_DONOTINDEX;
277 		goto out;
278 	}
279 
280 	buflen = (slen + 1) * sizeof(char);
281 	if ((ret = __os_umalloc(secdb->dbenv->env, buflen, &buf)) != 0)
282 		goto out;
283 	(void)strcpy(buf, freg->fname);
284 	result->size = (u_int32_t)buflen;
285 	result->flags |= DB_DBT_APPMALLOC;
286 	result->data = buf;
287 out:
288 	if (freg != NULL && (tret = __free_filereg_info(freg)) != 0 && ret == 0)
289 		ret = tret;
290 	return (ret);
291 }
292 
293 /* Secondary index callback function for DB_LOG_VRFY_INFO->txnpg. */
294 static int
__lv_seccbk_txnpg(secdb,key,data,result)295 __lv_seccbk_txnpg(secdb, key, data, result)
296 	DB *secdb;
297 	const DBT *key;
298 	const DBT *data;
299 	DBT *result;
300 {
301 	COMPQUIET(key, NULL);
302 	COMPQUIET(secdb, NULL);
303 	/* Txnid is the secondary key, and it's all the data dbt has. */
304 	result->data = data->data;
305 	result->size = data->size;
306 
307 	return (0);
308 }
309 
310 /* Secondary index callback function for DB_LOG_VRFY_INFO->timelsn. */
311 static int
__lv_seccbk_lsn(secdb,key,data,result)312 __lv_seccbk_lsn(secdb, key, data, result)
313 	DB *secdb;
314 	const DBT *key;
315 	const DBT *data;
316 	DBT *result;
317 {
318 	VRFY_TIMESTAMP_INFO *lvti;
319 
320 	COMPQUIET(key, NULL);
321 	COMPQUIET(secdb, NULL);
322 
323 	lvti = (VRFY_TIMESTAMP_INFO *)data->data;
324 	result->data = &(lvti->timestamp);
325 	result->size = sizeof(lvti->timestamp);
326 
327 	return (0);
328 }
329 
330 /*
331  * Open a BTREE database handle, optionally set the btree compare function
332  * and flags if any.
333  */
334 static int
__lv_open_db(dbenv,dbpp,ip,name,inmem,cmpf,sflags,dupcmpf)335 __lv_open_db(dbenv, dbpp, ip, name, inmem, cmpf, sflags, dupcmpf)
336 	DB_ENV *dbenv;
337 	DB **dbpp;
338 	const char *name;
339 	int inmem;
340 	btcmp_funct cmpf;
341 	u_int32_t sflags;
342 	dupcmp_funct dupcmpf;
343 	DB_THREAD_INFO *ip;
344 {
345 	int ret;
346 	const char *dbfname, *dbname;
347 	DB *dbp;
348 
349 	dbp = NULL;
350 	ret = 0;
351 	if (inmem) {
352 		dbfname = NULL;
353 		dbname = name;
354 	} else {
355 		dbfname = name;
356 		dbname = NULL;
357 	}
358 
359 	BDBOP(db_create(&dbp, dbenv, 0));
360 
361 	if (cmpf != NULL)
362 		BDBOP(__bam_set_bt_compare(dbp, cmpf));
363 	if (dupcmpf != NULL)
364 		dbp->dup_compare = dupcmpf;
365 	if (sflags != 0)
366 		BDBOP(__db_set_flags(dbp, sflags));
367 	/* No concurrency needed, a big page size reduces overflow pages. */
368 	BDBOP(__db_set_pagesize(dbp, 16 * 1024));
369 
370 	BDBOP(__db_open(dbp, ip, NULL, dbfname, dbname, DB_BTREE, DB_CREATE,
371 	    0666, PGNO_BASE_MD));
372 
373 	*dbpp = dbp;
374 
375 	return (0);
376 err:
377 	if (dbenv != NULL && ret != 0)
378 		__db_err(dbenv->env, ret, "__lv_open_db");
379 	if (dbp != NULL)
380 		(void)__db_close(dbp, NULL, 0);
381 
382 	return (ret);
383 }
384 
385 /* Btree compare function for a [fileid, pgno] key. */
386 static int
__lv_fidpgno_cmp(db,dbt1,dbt2,locp)387 __lv_fidpgno_cmp(db, dbt1, dbt2, locp)
388 	DB *db;
389 	const DBT *dbt1;
390 	const DBT *dbt2;
391 	size_t * locp;
392 {
393 	db_pgno_t pgno1, pgno2;
394 	int ret;
395 	size_t len;
396 
397 	COMPQUIET(db, NULL);
398 	COMPQUIET(locp, NULL);
399 	len = DB_FILE_ID_LEN;
400 	ret = memcmp(dbt1->data, dbt2->data, len);
401 	if (ret == 0) {
402 		memcpy(&pgno1, (u_int8_t *)dbt1->data + len,
403 		    sizeof(pgno1));
404 		memcpy(&pgno2, (u_int8_t *)dbt2->data + len,
405 		    sizeof(pgno2));
406 		ret = NUMCMP(pgno1, pgno2);
407 	}
408 
409 	return (ret);
410 }
411 
412 /* Btree compare function for a int32_t type of key. */
413 static int
__lv_i32_cmp(db,dbt1,dbt2,locp)414 __lv_i32_cmp(db, dbt1, dbt2, locp)
415 	DB *db;
416 	const DBT *dbt1;
417 	const DBT *dbt2;
418 	size_t *locp;
419 {
420 	int32_t k1, k2;
421 
422 	COMPQUIET(db, NULL);
423 	COMPQUIET(locp, NULL);
424 	memcpy(&k1, dbt1->data, sizeof(k1));
425 	memcpy(&k2, dbt2->data, sizeof(k2));
426 
427 	return (NUMCMP(k1, k2));
428 }
429 
430 /* Btree compare function for a u_int32_t type of key. */
431 static int
__lv_ui32_cmp(db,dbt1,dbt2,locp)432 __lv_ui32_cmp(db, dbt1, dbt2, locp)
433 	DB *db;
434 	const DBT *dbt1;
435 	const DBT *dbt2;
436 	size_t *locp;
437 {
438 	u_int32_t k1, k2;
439 
440 	COMPQUIET(db, NULL);
441 	COMPQUIET(locp, NULL);
442 	memcpy(&k1, dbt1->data, sizeof(k1));
443 	memcpy(&k2, dbt2->data, sizeof(k2));
444 
445 	return (NUMCMP(k1, k2));
446 }
447 
448 /* Btree compare function for a DB_LSN type of key. */
449 static int
__lv_lsn_cmp(db,dbt1,dbt2,locp)450 __lv_lsn_cmp(db, dbt1, dbt2, locp)
451 	DB *db;
452 	const DBT *dbt1;
453 	const DBT *dbt2;
454 	size_t *locp;
455 {
456 	DB_LSN lsn1, lsn2;
457 
458 	COMPQUIET(locp, NULL);
459 	DB_ASSERT(db->env, dbt1->size == sizeof(DB_LSN));
460 	DB_ASSERT(db->env, dbt2->size == sizeof(DB_LSN));
461 	memcpy(&lsn1, dbt1->data, sizeof(DB_LSN));
462 	memcpy(&lsn2, dbt2->data, sizeof(DB_LSN));
463 
464 	COMPQUIET(db, NULL);
465 	return (LOG_COMPARE(&lsn1, &lsn2));
466 }
467 
468 /*
469  * Structure management routines. We keep each structure on a
470  * consecutive memory chunk.
471  *
472  * The get functions will allocate memory via __os_malloc, and callers
473  * should free the memory after use. The update functions for VRFY_TXN_INFO
474  * and VRFY_FILEREG_INFO may realloc the structure.
475  */
476 
477 /*
478  * PUBLIC: int __put_txn_vrfy_info __P((const DB_LOG_VRFY_INFO *,
479  * PUBLIC:     const VRFY_TXN_INFO *));
480  */
481 int
__put_txn_vrfy_info(lvinfo,txninfop)482 __put_txn_vrfy_info (lvinfo, txninfop)
483 	const DB_LOG_VRFY_INFO *lvinfo;
484 	const VRFY_TXN_INFO *txninfop;
485 {
486 	int ret;
487 	DBT key, data;
488 
489 	ret = __lv_pack_txn_vrfy_info(txninfop, &key, &data);
490 	DB_ASSERT(lvinfo->dbenv->env, ret == 0);
491 
492 	BDBOP2(lvinfo->dbenv, __db_put(lvinfo->txninfo, lvinfo->ip, NULL,
493 	    &key, &data, 0), "__put_txn_vrfy_info");
494 	__os_free(lvinfo->dbenv->env, data.data);
495 
496 	return (0);
497 }
498 
499 /* Construct a key and data DBT from the structure. */
500 static int
__lv_pack_txn_vrfy_info(txninfop,key,data)501 __lv_pack_txn_vrfy_info(txninfop, key, data)
502 	const VRFY_TXN_INFO *txninfop;
503 	DBT *key, *data;
504 {
505 	int ret;
506 	char *buf, *p;
507 	size_t bufsz, len;
508 	u_int32_t i;
509 	DBT *pdbt;
510 
511 	memset(key, 0, sizeof(DBT));
512 	memset(data, 0, sizeof(DBT));
513 	ret = 0;
514 	bufsz = TXN_VERIFY_INFO_TOTSIZE(*txninfop);
515 
516 	if ((ret = __os_malloc(NULL, bufsz, &buf)) != 0)
517 		goto err;
518 	memset(buf, 0, bufsz);
519 	memcpy(buf, txninfop, TXN_VERIFY_INFO_FIXSIZE);
520 	p = buf + TXN_VERIFY_INFO_FIXSIZE;
521 	memcpy(p, txninfop->recycle_lsns, len = sizeof(DB_LSN) *
522 	    txninfop->num_recycle);
523 	p += len;
524 
525 	for (i = 0; i < txninfop->filenum; i++) {
526 
527 		pdbt = &(txninfop->fileups[i]);
528 		memcpy(p, &(pdbt->size), sizeof(pdbt->size));
529 		p += sizeof(pdbt->size);
530 		memcpy(p, pdbt->data, pdbt->size);
531 		p += pdbt->size;
532 	}
533 
534 	key->data = (void *)&txninfop->txnid;
535 	key->size = sizeof(txninfop->txnid);
536 	data->data = buf;
537 	data->size = (u_int32_t)bufsz;
538 	data->flags |= DB_DBT_MALLOC;
539 err:
540 	return (ret);
541 }
542 
543 /* Calculate a DBT array's total number of bytes to store. */
544 static size_t
__lv_dbt_arrsz(arr,arrlen)545 __lv_dbt_arrsz(arr, arrlen)
546 	const DBT *arr;
547 	u_int32_t arrlen;
548 {
549 	u_int32_t i;
550 	size_t sz;
551 
552 	sz = 0;
553 
554 	/* For each DBT object, store its size and its data bytes. */
555 	for (i = 0; i < arrlen; i++)
556 		sz += arr[i].size + sizeof(arr[i].size);
557 
558 	return sz;
559 }
560 
561 /*
562  *  __get_txn_vrfy_info --
563  *	Get a VRFY_TXN_INFO object from db by txnid. Callers should free the
564  *	object by calling __free_txninfo.
565  *
566  * PUBLIC: int __get_txn_vrfy_info __P((const DB_LOG_VRFY_INFO *, u_int32_t,
567  * PUBLIC:     VRFY_TXN_INFO **));
568  */
569 int
__get_txn_vrfy_info(lvinfo,txnid,txninfopp)570 __get_txn_vrfy_info (lvinfo, txnid, txninfopp)
571 	const DB_LOG_VRFY_INFO *lvinfo;
572 	u_int32_t txnid;
573 	VRFY_TXN_INFO **txninfopp;
574 {
575 	int ret;
576 	DBT key, data;
577 
578 	memset(&key, 0, sizeof(DBT));
579 	memset(&data, 0, sizeof(DBT));
580 	key.data = &txnid;
581 	key.size = sizeof(txnid);
582 
583 	BDBOP3(lvinfo->dbenv, __db_get(lvinfo->txninfo, lvinfo->ip, NULL,
584 	    &key, &data, 0), DB_NOTFOUND, "__get_txn_vrfy_info");
585 
586 	if (ret != DB_NOTFOUND)
587 		ret = __lv_unpack_txn_vrfy_info(txninfopp, &data);
588 
589 	return (ret);
590 }
591 
592 /* Construct a structure from a DBT. */
593 static int
__lv_unpack_txn_vrfy_info(txninfopp,data)594 __lv_unpack_txn_vrfy_info(txninfopp, data)
595 	VRFY_TXN_INFO **txninfopp;
596 	const DBT *data;
597 {
598 	size_t bufsz;
599 	VRFY_TXN_INFO *buf, *txninfop;
600 	DB_LSN *lsns, *p;
601 	u_int32_t i, sz;
602 	char *pb, *q;
603 	int ret;
604 
605 	ret = 0;
606 	i = sz = 0;
607 	lsns = p = NULL;
608 	pb = q = NULL;
609 	txninfop = (VRFY_TXN_INFO *)data->data;
610 	lsns = (DB_LSN *)((char *)data->data + TXN_VERIFY_INFO_FIXSIZE);
611 	pb = (char *)lsns + txninfop->num_recycle * sizeof(DB_LSN);
612 
613 	if ((ret = __os_malloc(NULL, bufsz = sizeof(VRFY_TXN_INFO), &buf)) != 0)
614 		goto err;
615 	memset(buf, 0, bufsz);
616 	memcpy(buf, data->data, TXN_VERIFY_INFO_FIXSIZE);
617 
618 	if (txninfop->num_recycle != 0) {
619 		if ((ret = __os_malloc(NULL,
620 		    txninfop->num_recycle * sizeof(DB_LSN), &p)) != 0)
621 			goto err;
622 		memcpy(p, lsns, txninfop->num_recycle * sizeof(DB_LSN));
623 		buf->recycle_lsns = p;
624 	}
625 
626 	if (txninfop->filenum != 0) {
627 		if ((ret = __os_malloc(NULL,
628 		    txninfop->filenum * sizeof(DBT), &q)) != 0)
629 			goto err;
630 		memset(q, 0, txninfop->filenum * sizeof(DBT));
631 		buf->fileups = (DBT *)q;
632 		for (i = 0; i < txninfop->filenum; i++) {
633 			memcpy(&sz, pb, sizeof(sz));
634 			pb += sizeof(sz);
635 			if ((ret = __os_malloc(NULL, sz, &q)) != 0)
636 				goto err;
637 			memcpy(q, pb, sz);
638 			pb += sz;
639 
640 			buf->fileups[i].data = q;
641 			buf->fileups[i].size = sz;
642 		}
643 	}
644 
645 	*txninfopp = buf;
646 err:
647 	return (ret);
648 }
649 
650 static int
__lv_add_recycle_lsn(txninfop,lsn)651 __lv_add_recycle_lsn (txninfop, lsn)
652 	VRFY_TXN_INFO *txninfop;
653 	const DB_LSN *lsn;
654 {
655 	int ret;
656 
657 	ret = 0;
658 	txninfop->num_recycle++;
659 	if ((ret = __os_realloc(NULL, txninfop->num_recycle * sizeof(DB_LSN),
660 	    &(txninfop->recycle_lsns))) != 0)
661 		goto err;
662 	txninfop->recycle_lsns[txninfop->num_recycle - 1] = *lsn;
663 err:
664 	return (ret);
665 }
666 
667 /*
668  * __add_recycle_lsn_range --
669  *	Add recycle info for each txn within the recycled txnid range.
670  *
671  * PUBLIC: int __add_recycle_lsn_range __P((DB_LOG_VRFY_INFO *,
672  * PUBLIC:     const DB_LSN *, u_int32_t, u_int32_t));
673  */
674 int
__add_recycle_lsn_range(lvinfo,lsn,min,max)675 __add_recycle_lsn_range(lvinfo, lsn, min, max)
676 	DB_LOG_VRFY_INFO *lvinfo;
677 	const DB_LSN *lsn;
678 	u_int32_t min, max;
679 {
680 	DBC *csr;
681 	int ret, tret;
682 	u_int32_t i;
683 	DBT key2, data2;
684 	struct __add_recycle_params param;
685 
686 	csr = NULL;
687 	ret = tret = 0;
688 	memset(&key2, 0, sizeof(DBT));
689 	memset(&data2, 0, sizeof(DBT));
690 	memset(&param, 0, sizeof(param));
691 
692 	if ((ret = __os_malloc(lvinfo->dbenv->env, sizeof(VRFY_TXN_INFO *) *
693 	    (param.ti2ul = 1024), &(param.ti2u))) != 0)
694 		goto err;
695 	param.ti2ui = 0;
696 	param.recycle_lsn = *lsn;
697 	param.min = min;
698 	param.max = max;
699 
700 	/* Iterate the specified range and process each transaction. */
701 	if ((ret = __iterate_txninfo(lvinfo, min, max, __lv_add_recycle_handler,
702 	    &param)) != 0)
703 		goto err;
704 
705 	/*
706 	 * Save updated txninfo structures. We can't do so in the above
707 	 * iteration, so we have to save them here.
708 	 */
709 	BDBOP(__db_cursor(lvinfo->txninfo, lvinfo->ip, NULL, &csr, DBC_BULK));
710 
711 	for (i = 0; i < param.ti2ui; i++) {
712 		ret = __lv_pack_txn_vrfy_info(param.ti2u[i], &key2, &data2);
713 		DB_ASSERT(lvinfo->dbenv->env, ret == 0);
714 		BDBOP(__dbc_put(csr, &key2, &data2, DB_KEYLAST));
715 		/*
716 		 * key2.data refers to param.ti2u[i]'s memory, data2.data is
717 		 * freed by DB since we set DB_DBT_MALLOC.
718 		 */
719 		if ((ret = __free_txninfo(param.ti2u[i])) != 0)
720 			goto err;
721 	}
722 
723 err:
724 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
725 		ret = tret;
726 	__os_free(lvinfo->dbenv->env, param.ti2u);
727 	if (ret != 0)
728 		__db_err(lvinfo->dbenv->env, ret,
729 		    "__add_recycle_lsn_range");
730 
731 	return (ret);
732 }
733 
734 /*
735  *  __iterate_txninfo --
736  *	Iterate throught the transaction info database as fast as possible,
737  *	and process each key/data pair using a callback handler. Break the
738  *	iteration if the handler returns non-zero values.
739  *
740  * PUBLIC: int __iterate_txninfo __P((DB_LOG_VRFY_INFO *, u_int32_t,
741  * PUBLIC:     u_int32_t, TXNINFO_HANDLER, void *));
742  */
743 int
__iterate_txninfo(lvinfo,min,max,handler,param)744 __iterate_txninfo(lvinfo, min, max, handler, param)
745 	DB_LOG_VRFY_INFO *lvinfo;
746 	u_int32_t min, max;
747 	TXNINFO_HANDLER handler;
748 	void *param;
749 {
750 	ENV *env;
751 	VRFY_TXN_INFO *txninfop;
752 	int ret, tret;
753 	u_int32_t bufsz, pgsz, txnid;
754 	size_t retkl, retdl;
755 	char *btbuf;
756 	u_int8_t *retk, *retd;
757 	DBT key, data, data2;
758 	DBC *csr;
759 	void *p;
760 
761 	csr = NULL;
762 	env = lvinfo->dbenv->env;
763 	txninfop = NULL;
764 	ret = tret = 0;
765 	txnid = 0;
766 	retkl = retdl = 0;
767 	bufsz = 64 * 1024;
768 	btbuf = NULL;
769 	retk = retd = NULL;
770 
771 	memset(&key, 0, sizeof(DBT));
772 	memset(&data, 0, sizeof(DBT));
773 	memset(&data2, 0, sizeof(DBT));
774 
775 	pgsz = lvinfo->txninfo->pgsize;
776 	DB_ASSERT(env, ret == 0);
777 
778 	if (bufsz % pgsz != 0)
779 		bufsz = pgsz * (bufsz / pgsz);
780 
781 	if ((ret = __os_malloc(env, bufsz, &btbuf)) != 0)
782 		goto err;
783 
784 	BDBOP(__db_cursor(lvinfo->txninfo, lvinfo->ip, NULL, &csr, DBC_BULK));
785 
786 	/*
787 	 * Use bulk retrieval to scan the database as fast as possible.
788 	 */
789 	data.data = btbuf;
790 	data.ulen = bufsz;
791 	data.flags |= DB_DBT_USERMEM;
792 
793 	for (ret = __dbc_get(csr, &key, &data, DB_FIRST | DB_MULTIPLE_KEY) ;;
794 	    ret = __dbc_get(csr, &key, &data, DB_NEXT | DB_MULTIPLE_KEY)) {
795 		switch (ret) {
796 		case 0:
797 			break;
798 		case DB_NOTFOUND:
799 			goto out;
800 			/* No break statement allowed by lint here. */
801 		case DB_BUFFER_SMALL:
802 			if ((ret = __os_realloc(lvinfo->dbenv->env,
803 			    bufsz *= 2, &btbuf)) != 0)
804 				goto out;
805 			data.ulen = bufsz;
806 			data.data = btbuf;
807 			continue;/* Continue the for-loop. */
808 			/* No break statement allowed by lint here. */
809 		default:
810 			goto err;
811 		}
812 
813 		/*
814 		 * Do bulk get. Some txninfo objects may be updated by the
815 		 * handler, but we can't store them immediately in the same
816 		 * loop because we wouldn't be able to continue the bulk get
817 		 * using the same cursor; and we can't use another cursor
818 		 * otherwise we may self-block. In the handler we need to
819 		 * store the updated objects and store them to db when we get
820 		 * out of this loop.
821 		 */
822 		DB_MULTIPLE_INIT(p, &data);
823 		while (1) {
824 			DB_MULTIPLE_KEY_NEXT(p, &data,
825 			    retk, retkl, retd, retdl);
826 			if (p == NULL)
827 				break;
828 			DB_ASSERT(env, retkl == sizeof(txnid) && retk != NULL);
829 			memcpy(&txnid, retk, retkl);
830 			/*
831 			 * Process it if txnid in range or no range specified.
832 			 * The range must be a closed one.
833 			 */
834 			if ((min != 0 && txnid >= min && max != 0 &&
835 			    txnid <= max) || (min == 0 && max == 0)) {
836 				data2.data = retd;
837 				data2.size = (u_int32_t)retdl;
838 
839 				if ((ret = __lv_unpack_txn_vrfy_info(
840 				    &txninfop, &data2)) != 0)
841 					goto out;
842 				if ((ret = handler(lvinfo, txninfop,
843 				    param)) != 0)
844 					/* Stop the iteration on error. */
845 					goto out;
846 			}
847 		}
848 
849 	}
850 out:
851 	if (ret == DB_NOTFOUND)
852 		ret = 0;
853 err:
854 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
855 		ret = tret;
856 	__os_free(lvinfo->dbenv->env, btbuf);
857 	return (ret);
858 }
859 
860 /* Txninfo iteration handler to add recycle info for affected txns. */
861 static int
__lv_add_recycle_handler(lvinfo,txninfop,params)862 __lv_add_recycle_handler(lvinfo, txninfop, params)
863 	DB_LOG_VRFY_INFO *lvinfo;
864 	VRFY_TXN_INFO *txninfop;
865 	void *params;
866 {
867 	int ret;
868 	struct __add_recycle_params *param;
869 
870 	ret = 0;
871 	param = (struct __add_recycle_params *)params;
872 
873 	/*
874 	 * If the txnid is reused, update its recycle info and note it for
875 	 * later update, otherwise free the txninfop structure.
876 	 */
877 	if (txninfop->txnid < param->min && txninfop->txnid > param->max) {
878 		ret = __free_txninfo(txninfop);
879 		return (ret);
880 	}
881 
882 	ret = __lv_add_recycle_lsn(txninfop, &(param->recycle_lsn));
883 
884 	if (ret != 0)
885 		goto err;
886 	/*
887 	 * Below is one way to tell if a txn is aborted without doing another
888 	 * backward pass of the log. However if the txn id is not in the
889 	 * chosen recycled txn id range, we can't tell, until all the log
890 	 * records are passed --- the remaining active txns are the aborted
891 	 * txns.
892 	 * No longer needed since we did another backward pass of the log
893 	 * and have all the txn lifetimes.
894 	if (txninfop->status == TXN_STAT_ACTIVE)
895 		__on_txn_abort(lvinfo, txninfop);
896 	 */
897 	if (txninfop->status == TXN_STAT_PREPARE) {
898 		__db_errx(lvinfo->dbenv->env,
899 		    "[ERROR] Transaction with ID %u is prepared and not "
900 		    "committed, but its ID is recycled by log record [%u, %u].",
901 		    txninfop->txnid, param->recycle_lsn.file,
902 		    param->recycle_lsn.offset);
903 	}
904 	/* Note down to store later. */
905 	param->ti2u[(param->ti2ui)++] = txninfop;
906 	if (param->ti2ui == param->ti2ul)
907 		BDBOP(__os_realloc(lvinfo->dbenv->env,
908 		    sizeof(VRFY_TXN_INFO *) * (param->ti2ul *= 2),
909 		    &(param->ti2u)));
910 err:
911 	return (ret);
912 
913 }
914 /*
915  * PUBLIC: int __rem_last_recycle_lsn __P((VRFY_TXN_INFO *));
916  */
917 int
__rem_last_recycle_lsn(txninfop)918 __rem_last_recycle_lsn(txninfop)
919 	VRFY_TXN_INFO *txninfop;
920 {
921 	int ret;
922 
923 	ret = 0;
924 	if (txninfop->num_recycle == 0)
925 		return (0);
926 	txninfop->num_recycle--;
927 	if (txninfop->num_recycle > 0)
928 		BDBOP(__os_realloc(NULL, txninfop->num_recycle * sizeof(DB_LSN),
929 		    &(txninfop->recycle_lsns)));
930 	else {
931 		__os_free(NULL, txninfop->recycle_lsns);
932 		txninfop->recycle_lsns = NULL;
933 	}
934 err:
935 	return (ret);
936 
937 }
938 
939 /*
940  * __add_file_updated --
941  *	Add a file's dbregid and uid to the updating txn if it's not yet
942  *	recorded.
943  *
944  * PUBLIC: int __add_file_updated __P((VRFY_TXN_INFO *, const DBT *, int32_t));
945  */
946 int
__add_file_updated(txninfop,fileid,dbregid)947 __add_file_updated (txninfop, fileid, dbregid)
948 	VRFY_TXN_INFO *txninfop;
949 	const DBT *fileid;
950 	int32_t dbregid;
951 {
952 	int ret;
953 	DBT *pdbt, *p;
954 	u_int32_t found, i;
955 
956 	ret = 0;
957 	p = pdbt = NULL;
958 
959 	for (found = 0, i = 0; i < txninfop->filenum; i++) {
960 		p = &(txninfop->fileups[i]);
961 		if (p->size == fileid->size &&
962 		    memcmp(p->data, fileid->data, p->size) == 0) {
963 			found = 1;
964 			break;
965 		}
966 	}
967 
968 	if (found)
969 		return (0);
970 
971 	/* Add file's uid into the array, deep copy from fileid. */
972 	txninfop->filenum++;
973 	if ((ret = __os_realloc(NULL, txninfop->filenum *
974 	    sizeof(DBT), &(txninfop->fileups))) != 0)
975 		goto err;
976 
977 	pdbt = &(txninfop->fileups[txninfop->filenum - 1]);
978 	memset(pdbt, 0, sizeof(DBT));
979 	if ((ret = __os_malloc(NULL,
980 	    pdbt->size = fileid->size, &(pdbt->data))) != 0)
981 		goto err;
982 	memcpy(pdbt->data, fileid->data, fileid->size);
983 
984 	/* Add file dbregid into the array. */
985 	BDBOP(__os_realloc(NULL, txninfop->filenum *
986 	    sizeof(int32_t), &(txninfop->dbregid)));
987 	txninfop->dbregid[txninfop->filenum - 1] = dbregid;
988 err:
989 	return (ret);
990 }
991 
992 /*
993  * PUBLIC: int __del_file_updated __P((VRFY_TXN_INFO *, const DBT *));
994  */
995 int
__del_file_updated(txninfop,fileid)996 __del_file_updated (txninfop, fileid)
997 	VRFY_TXN_INFO *txninfop;
998 	const DBT *fileid;
999 {
1000 	u_int32_t found, i;
1001 	int ret;
1002 	DBT *p;
1003 	void *pdbtdata;
1004 
1005 	ret = 0;
1006 
1007 	if (txninfop->filenum == 0)
1008 		return (0);
1009 
1010 	/*
1011 	 * If the array has an element identical to fileid, remove it. fileid
1012 	 * itself is intact after this function call.
1013 	 */
1014 	for (found = 0, i = 0, pdbtdata = NULL; i < txninfop->filenum; i++) {
1015 		p = &(txninfop->fileups[i]);
1016 		if (p->size == fileid->size &&
1017 		    memcmp(p->data, fileid->data, p->size) == 0) {
1018 			pdbtdata = p->data;
1019 			if (txninfop->filenum > 1) {
1020 				memmove(txninfop->fileups + i, txninfop->
1021 				    fileups + i + 1, sizeof(DBT) * (txninfop->
1022 				    filenum - (i + 1)));
1023 				memmove(txninfop->dbregid + i, txninfop->
1024 				    dbregid + i + 1, sizeof(int32_t) *
1025 				    (txninfop->filenum - (i + 1)));
1026 			} else {
1027 				__os_free(NULL, txninfop->fileups);
1028 				__os_free(NULL, txninfop->dbregid);
1029 				txninfop->fileups = NULL;
1030 				txninfop->dbregid = NULL;
1031 			}
1032 			found = 1;
1033 			break;
1034 		}
1035 	}
1036 
1037 	if (found) {
1038 		txninfop->filenum--;
1039 		if (txninfop->filenum) {
1040 			BDBOP(__os_realloc(NULL, sizeof(DBT) *
1041 			    txninfop->filenum, &(txninfop->fileups)));
1042 			BDBOP(__os_realloc(NULL, sizeof(int32_t) *
1043 			    txninfop->filenum, &(txninfop->dbregid)));
1044 		}
1045 		__os_free(NULL, pdbtdata);
1046 	}
1047 err:
1048 	return (ret);
1049 }
1050 
1051 /*
1052  * PUBLIC: int __clear_fileups __P((VRFY_TXN_INFO *));
1053  */
1054 int
__clear_fileups(txninfop)1055 __clear_fileups(txninfop)
1056 	VRFY_TXN_INFO *txninfop;
1057 {
1058 	u_int32_t i;
1059 
1060 	for (i = 0; i < txninfop->filenum; i++)
1061 		__os_free(NULL, txninfop->fileups[i].data);
1062 
1063 	__os_free(NULL, txninfop->fileups);
1064 	__os_free(NULL, txninfop->dbregid);
1065 	txninfop->fileups = NULL;
1066 	txninfop->dbregid = NULL;
1067 	txninfop->filenum = 0;
1068 
1069 	return (0);
1070 }
1071 
1072 /*
1073  *  __free_txninfo_stack  --
1074  *	The object is on stack, only free its internal memory, not itself.
1075  * PUBLIC: int __free_txninfo_stack __P((VRFY_TXN_INFO *));
1076  */
1077 int
__free_txninfo_stack(p)1078 __free_txninfo_stack (p)
1079 	VRFY_TXN_INFO *p;
1080 {
1081 	u_int32_t i;
1082 
1083 	if (p == NULL)
1084 		return (0);
1085 
1086 	if (p->fileups != NULL) {
1087 		for (i = 0; i < p->filenum; i++)
1088 			__os_free(NULL, p->fileups[i].data);
1089 		__os_free(NULL, p->fileups);
1090 	}
1091 
1092 	if (p->dbregid != NULL)
1093 		__os_free(NULL, p->dbregid);
1094 
1095 	if (p->recycle_lsns != NULL)
1096 		__os_free(NULL, p->recycle_lsns);
1097 
1098 	return (0);
1099 }
1100 /*
1101  * PUBLIC: int __free_txninfo __P((VRFY_TXN_INFO *));
1102  */
1103 int
__free_txninfo(p)1104 __free_txninfo(p)
1105 	VRFY_TXN_INFO *p;
1106 {
1107 	(void)__free_txninfo_stack(p);
1108 	__os_free(NULL, p);
1109 
1110 	return (0);
1111 }
1112 
1113 /* Construct a key and data DBT from the structure. */
1114 static int
__lv_pack_filereg(freginfo,data)1115 __lv_pack_filereg(freginfo, data)
1116 	const VRFY_FILEREG_INFO *freginfo;
1117 	DBT *data;
1118 {
1119 	char *buf, *p;
1120 	size_t bufsz, offset;
1121 	int ret;
1122 
1123 	ret = 0;
1124 	if ((ret = __os_malloc(NULL,
1125 	    bufsz = FILE_REG_INFO_TOTSIZE(*freginfo), &buf)) != 0)
1126 		goto err;
1127 	memset(buf, 0, bufsz);
1128 
1129 	memcpy(buf, freginfo, FILE_REG_INFO_FIXSIZE);
1130 	p = buf + FILE_REG_INFO_FIXSIZE;
1131 
1132 	offset = sizeof(int32_t) * freginfo->regcnt;
1133 	memcpy(p, freginfo->dbregids, offset);
1134 	p += offset;
1135 
1136 	memcpy(p, &(freginfo->fileid.size), sizeof(freginfo->fileid.size));
1137 	p += sizeof(freginfo->fileid.size);
1138 	memcpy(p, freginfo->fileid.data, freginfo->fileid.size);
1139 	p += freginfo->fileid.size;
1140 	(void)strcpy(p, freginfo->fname);
1141 
1142 	data->data = buf;
1143 	data->size = (u_int32_t)bufsz;
1144 err:
1145 	return (ret);
1146 }
1147 
1148 /*
1149  * PUBLIC: int __put_filereg_info __P((const DB_LOG_VRFY_INFO *,
1150  * PUBLIC:    const VRFY_FILEREG_INFO *));
1151  */
__put_filereg_info(lvinfo,freginfo)1152 int __put_filereg_info (lvinfo, freginfo)
1153 	const DB_LOG_VRFY_INFO *lvinfo;
1154 	const VRFY_FILEREG_INFO *freginfo;
1155 {
1156 
1157 	int ret;
1158 	DBT data;
1159 
1160 	memset(&data, 0, sizeof(DBT));
1161 
1162 	if ((ret = __lv_pack_filereg(freginfo, &data)) != 0)
1163 		goto err;
1164 
1165 	/*
1166 	 * We store dbregid-filereg map into dbregids.db, but we can't make
1167 	 * dbregids.db the sec db of fileregs.db, because dbregid is only
1168 	 * valid when a db file is open, we want to delete data with same
1169 	 * key in dbregids.db, but we want to keep all filereg_info data in
1170 	 * fileregs.db to track all db file lifetime and status.
1171 	 *
1172 	 * Consequently we will store dbregid-file_uid in dbregs.db, so that we
1173 	 * can delete dbregid when the db handle is closed, and we can
1174 	 * use the dbregid to get the currently open db file's uid.
1175 	 */
1176 
1177 	BDBOP2(lvinfo->dbenv, __db_put(lvinfo->fileregs, lvinfo->ip, NULL,
1178 	    (DBT *)&(freginfo->fileid), &data, 0), "__put_filereg_info");
1179 
1180 err:
1181 	if (data.data != NULL)
1182 		__os_free(lvinfo->dbenv->env, data.data);
1183 
1184 	return (ret);
1185 }
1186 
1187 /*
1188  * PUBLIC: int __del_filelife __P((const DB_LOG_VRFY_INFO *, int32_t));
1189  */
1190 int
__del_filelife(lvinfo,dbregid)1191 __del_filelife(lvinfo, dbregid)
1192 	const DB_LOG_VRFY_INFO *lvinfo;
1193 	int32_t dbregid;
1194 {
1195 	int ret;
1196 	DBT key;
1197 
1198 	memset(&key, 0, sizeof(DBT));
1199 	key.data = &(dbregid);
1200 	key.size = sizeof(dbregid);
1201 
1202 	if ((ret = __db_del(lvinfo->dbregids, lvinfo->ip, NULL,
1203 	    &key, 0)) != 0)
1204 		goto err;
1205 
1206 err:
1207 	return (ret);
1208 }
1209 
1210 /*
1211  * PUBLIC: int __put_filelife __P((const DB_LOG_VRFY_INFO *, VRFY_FILELIFE *));
1212  */
1213 int
__put_filelife(lvinfo,pflife)1214 __put_filelife (lvinfo, pflife)
1215 	const DB_LOG_VRFY_INFO *lvinfo;
1216 	VRFY_FILELIFE *pflife;
1217 {
1218 	int ret;
1219 	DBT key, data;
1220 
1221 	memset(&key, 0, sizeof(DBT));
1222 	memset(&data, 0, sizeof(DBT));
1223 	key.data = &(pflife->dbregid);
1224 	key.size = sizeof(pflife->dbregid);
1225 	data.data = pflife;
1226 	data.size = sizeof(VRFY_FILELIFE);
1227 
1228 	if ((ret = __db_put(lvinfo->dbregids, lvinfo->ip, NULL,
1229 	    &key, &data, 0)) != 0)
1230 		goto err;
1231 
1232 err:
1233 	return (ret);
1234 }
1235 
1236 /*
1237  * PUBLIC: int __get_filelife __P((const DB_LOG_VRFY_INFO *,
1238  * PUBLIC:     int32_t, VRFY_FILELIFE **));
1239  */
1240 int
__get_filelife(lvinfo,dbregid,flifepp)1241 __get_filelife (lvinfo, dbregid, flifepp)
1242 	const DB_LOG_VRFY_INFO *lvinfo;
1243 	int32_t dbregid;
1244 	VRFY_FILELIFE **flifepp;
1245 {
1246 	int ret;
1247 	DBT key, data;
1248 	VRFY_FILELIFE *flifep;
1249 
1250 	ret = 0;
1251 	flifep = NULL;
1252 	memset(&key, 0, sizeof(DBT));
1253 	memset(&data, 0, sizeof(DBT));
1254 
1255 	key.data = &dbregid;
1256 	key.size = sizeof(dbregid);
1257 	if ((ret = __db_get(lvinfo->dbregids, lvinfo->ip, NULL,
1258 	    &key, &data, 0)) != 0)
1259 		goto err;
1260 	if ((ret = __os_malloc(lvinfo->dbenv->env,
1261 	    sizeof(VRFY_FILELIFE), &flifep)) != 0)
1262 		goto err;
1263 	DB_ASSERT(lvinfo->dbenv->env, flifep != NULL);
1264 	memcpy(flifep, data.data, sizeof(VRFY_FILELIFE));
1265 	*flifepp = flifep;
1266 err:
1267 	return (ret);
1268 }
1269 
1270 /*
1271  * PUBLIC: int __get_filereg_by_dbregid __P((const DB_LOG_VRFY_INFO *,
1272  * PUBLIC:     int32_t, VRFY_FILEREG_INFO **));
1273  */
1274 int
__get_filereg_by_dbregid(lvinfo,dbregid,freginfopp)1275 __get_filereg_by_dbregid(lvinfo, dbregid, freginfopp)
1276 	const DB_LOG_VRFY_INFO *lvinfo;
1277 	int32_t dbregid;
1278 	VRFY_FILEREG_INFO **freginfopp;
1279 {
1280 	int ret;
1281 	DBT key, data;
1282 	char uid[DB_FILE_ID_LEN];
1283 	VRFY_FILELIFE *pflife;
1284 
1285 	memset(&data, 0, sizeof(DBT));
1286 	memset(&key, 0, sizeof(DBT));
1287 	key.data = &dbregid;
1288 	key.size = sizeof(dbregid);
1289 
1290 	BDBOP3(lvinfo->dbenv, __db_get(lvinfo->dbregids, lvinfo->ip, NULL,
1291 	    &key, &data, 0), DB_NOTFOUND,  "__get_filereg_by_dbregid");
1292 	if (ret == DB_NOTFOUND)
1293 		goto err;
1294 
1295 	/* Use the file-uid as key to retrieve from fileregs.db. */
1296 	pflife = (VRFY_FILELIFE *)data.data;
1297 	memcpy((void *)uid, (void *)pflife->fileid, key.size = DB_FILE_ID_LEN);
1298 
1299 	key.data = (void *)uid;
1300 	memset(&data, 0, sizeof(DBT));
1301 
1302 	BDBOP3(lvinfo->dbenv, __db_get(lvinfo->fileregs, lvinfo->ip, NULL,
1303 	    &key, &data, 0), DB_NOTFOUND,  "__get_filereg_by_dbregid");
1304 	if (ret == DB_NOTFOUND)
1305 		goto err;
1306 	if ((ret = __lv_unpack_filereg(&data, freginfopp)) != 0)
1307 		goto err;
1308 
1309 err:
1310 	return (ret);
1311 }
1312 
1313 /*
1314  * PUBLIC: int __add_dbregid __P((DB_LOG_VRFY_INFO *, VRFY_FILEREG_INFO *,
1315  * PUBLIC:     int32_t, u_int32_t, DB_LSN, DBTYPE, db_pgno_t, int *));
1316  */
1317 int
__add_dbregid(lvh,freg,dbregid,opcode,lsn,dbtype,meta_pgno,addp)1318 __add_dbregid(lvh, freg, dbregid, opcode, lsn, dbtype, meta_pgno, addp)
1319 	DB_LOG_VRFY_INFO *lvh;
1320 	VRFY_FILEREG_INFO *freg;
1321 	int32_t dbregid;
1322 	u_int32_t opcode;
1323 	DB_LSN lsn;
1324 	DBTYPE dbtype;
1325 	db_pgno_t meta_pgno;
1326 	int *addp;
1327 {
1328 	int inarray, ret, tret;
1329 	u_int32_t i, j;
1330 	VRFY_FILELIFE flife;
1331 
1332 	inarray = ret = tret = 0;
1333 	for (i = 0; i < freg->regcnt; i++) {
1334 		if (freg->dbregids[i] == dbregid) {
1335 			if (!IS_DBREG_CLOSE(opcode)) {
1336 				/* Opening an open dbreg id. */
1337 				if (IS_DBREG_OPEN(opcode) &&
1338 				    (opcode != DBREG_CHKPNT &&
1339 				    opcode != DBREG_XCHKPNT)) {
1340 					tret = 2;
1341 					goto err;
1342 				}
1343 				tret = 0;
1344 				inarray = 1;
1345 			} else
1346 				/* Found the dbregid; gonna remove it. */
1347 				tret = -1;
1348 			break;
1349 		}
1350 	}
1351 
1352 	if (IS_DBREG_OPEN(opcode))
1353 		tret = 1;/* dbregid not in the array, gonna add 1. */
1354 
1355 	/*
1356 	 * Remove closed dbregid. dbregid can be recycled, not unique to a db
1357 	 * file, it's dynamically allocated for each db handle.
1358 	 */
1359 	if (tret == -1) {
1360 		for (j = i; j < freg->regcnt - 1; j++)
1361 			freg->dbregids[j] = freg->dbregids[j + 1];
1362 		freg->regcnt--;
1363 		BDBOP(__os_realloc(lvh->dbenv->env,
1364 		    sizeof(int32_t) * freg->regcnt, &(freg->dbregids)));
1365 		/* Don't remove dbregid life info from dbregids db. */
1366 	} else if (tret == 1) {
1367 		if (!inarray) {
1368 			freg->regcnt++;
1369 			BDBOP(__os_realloc(lvh->dbenv->env,
1370 			    sizeof(int32_t) * freg->regcnt, &(freg->dbregids)));
1371 			freg->dbregids[freg->regcnt - 1] = dbregid;
1372 		}
1373 		flife.dbregid = dbregid;
1374 		memcpy(flife.fileid, freg->fileid.data, freg->fileid.size);
1375 		flife.lifetime = opcode;
1376 		flife.dbtype = dbtype;
1377 		flife.lsn = lsn;
1378 		flife.meta_pgno = meta_pgno;
1379 		if ((ret = __put_filelife(lvh, &flife)) != 0)
1380 			goto err;
1381 	}
1382 
1383 err:
1384 	*addp = tret;
1385 	return (ret);
1386 
1387 }
1388 
1389 /*
1390  * PUBLIC: int __get_filereg_info __P((const DB_LOG_VRFY_INFO *, const DBT *,
1391  * PUBLIC:     VRFY_FILEREG_INFO **));
1392  */
1393 int
__get_filereg_info(lvinfo,fuid,freginfopp)1394 __get_filereg_info (lvinfo, fuid, freginfopp)
1395 	const DB_LOG_VRFY_INFO *lvinfo;
1396 	const DBT *fuid;
1397 	VRFY_FILEREG_INFO **freginfopp;
1398 {
1399 	int ret;
1400 	DBT data;
1401 
1402 	memset(&data, 0, sizeof(DBT));
1403 
1404 	BDBOP3(lvinfo->dbenv, __db_get(lvinfo->fileregs, lvinfo->ip, NULL,
1405 	    (DBT *)fuid, &data, 0), DB_NOTFOUND,  "__get_filereg_info");
1406 	if (ret == DB_NOTFOUND)
1407 		goto err;
1408 	if ((ret = __lv_unpack_filereg(&data, freginfopp)) != 0)
1409 		goto err;
1410 
1411 err:
1412 	return (ret);
1413 }
1414 
1415 static int
__lv_unpack_filereg(data,freginfopp)1416 __lv_unpack_filereg(data, freginfopp)
1417 	const DBT *data;
1418 	VRFY_FILEREG_INFO **freginfopp;
1419 {
1420 	char *p, *q;
1421 	u_int32_t fidsz, arrsz;
1422 	VRFY_FILEREG_INFO *buf;
1423 	int ret;
1424 
1425 	ret = 0;
1426 	p = q = NULL;
1427 	fidsz = arrsz = 0;
1428 	buf = NULL;
1429 
1430 	if ((ret = __os_malloc(NULL, sizeof(VRFY_FILEREG_INFO), &buf)) != 0)
1431 		goto err;
1432 	memset(buf, 0, sizeof(VRFY_FILEREG_INFO));
1433 
1434 	memcpy(buf, data->data, FILE_REG_INFO_FIXSIZE);
1435 	*freginfopp = (VRFY_FILEREG_INFO *)buf;
1436 	p = ((char *)(data->data)) + FILE_REG_INFO_FIXSIZE;
1437 
1438 	if ((ret = __os_malloc(NULL, arrsz = (*freginfopp)->regcnt *
1439 	    sizeof(int32_t), &((*freginfopp)->dbregids))) != 0)
1440 		goto err;
1441 	memcpy((*freginfopp)->dbregids, p, arrsz);
1442 	p += arrsz;
1443 
1444 	memcpy(&fidsz, p, sizeof(fidsz));
1445 	p += sizeof(fidsz);
1446 	if ((ret = __os_malloc(NULL, fidsz, &q)) != 0)
1447 		goto err;
1448 	memcpy(q, p, fidsz);
1449 	(*freginfopp)->fileid.data = q;
1450 	(*freginfopp)->fileid.size = fidsz;
1451 	p += fidsz;
1452 
1453 	if ((ret = __os_malloc(NULL, sizeof(char) * (strlen(p) + 1), &q)) != 0)
1454 		goto err;
1455 	(void)strcpy(q, p);
1456 
1457 	(*freginfopp)->fname = q;
1458 err:
1459 	return (ret);
1460 }
1461 
1462 /*
1463  * PUBLIC: int __free_filereg_info __P((VRFY_FILEREG_INFO *));
1464  */
1465 int
__free_filereg_info(p)1466 __free_filereg_info(p)
1467 	VRFY_FILEREG_INFO *p;
1468 {
1469 	if (p == NULL)
1470 		return (0);
1471 	if (p ->fname != NULL)
1472 		__os_free(NULL, (void *)(p->fname));
1473 	if (p->fileid.data != NULL)
1474 		__os_free(NULL, p->fileid.data);
1475 	if (p->dbregids != NULL)
1476 		__os_free(NULL, p->dbregids);
1477 	__os_free(NULL, p);
1478 
1479 	return (0);
1480 }
1481 
1482 /*
1483  * PUBLIC: int __get_ckp_info __P((const DB_LOG_VRFY_INFO *, DB_LSN,
1484  * PUBLIC:     VRFY_CKP_INFO **));
1485  */
1486 int
__get_ckp_info(lvinfo,lsn,ckpinfopp)1487 __get_ckp_info (lvinfo, lsn, ckpinfopp)
1488 	const DB_LOG_VRFY_INFO *lvinfo;
1489 	DB_LSN lsn;
1490 	VRFY_CKP_INFO **ckpinfopp;
1491 {
1492 	int ret;
1493 	DBT key, data;
1494 	VRFY_CKP_INFO *ckpinfo;
1495 
1496 	memset(&key, 0, sizeof(DBT));
1497 	memset(&data, 0, sizeof(DBT));
1498 	key.data = &lsn;
1499 	key.size = sizeof(DB_LSN);
1500 	BDBOP3(lvinfo->dbenv, __db_get(lvinfo->ckps, lvinfo->ip, NULL,
1501 	    &key, &data, 0), DB_NOTFOUND, "__get_ckp_info");
1502 
1503 	if (ret == DB_NOTFOUND)
1504 		goto err;
1505 
1506 	if ((ret = __os_malloc(lvinfo->dbenv->env,
1507 	    sizeof(VRFY_CKP_INFO), &ckpinfo)) != 0)
1508 		goto err;
1509 	memcpy(ckpinfo, data.data, sizeof(VRFY_CKP_INFO));
1510 	*ckpinfopp = ckpinfo;
1511 err:
1512 	return (ret);
1513 
1514 }
1515 
1516 /*
1517  * PUBLIC: int __get_last_ckp_info __P((const DB_LOG_VRFY_INFO *,
1518  * PUBLIC:     VRFY_CKP_INFO **));
1519  */
1520 int
__get_last_ckp_info(lvinfo,ckpinfopp)1521 __get_last_ckp_info (lvinfo, ckpinfopp)
1522 	const DB_LOG_VRFY_INFO *lvinfo;
1523 	VRFY_CKP_INFO **ckpinfopp;
1524 {
1525 	int ret, tret;
1526 	DBT key, data;
1527 	VRFY_CKP_INFO *ckpinfo;
1528 	DBC *csr;
1529 
1530 	csr = NULL;
1531 	memset(&key, 0, sizeof(DBT));
1532 	memset(&data, 0, sizeof(DBT));
1533 
1534 	BDBOP(__db_cursor(lvinfo->ckps, lvinfo->ip, NULL, &csr, 0));
1535 	if ((ret = __dbc_get(csr, &key, &data, DB_LAST)) != 0)
1536 		goto err;
1537 
1538 	if ((ret = __os_malloc(lvinfo->dbenv->env,
1539 	    sizeof(VRFY_CKP_INFO), &ckpinfo)) != 0)
1540 		goto err;
1541 	DB_ASSERT(lvinfo->dbenv->env, sizeof(VRFY_CKP_INFO) == data.size);
1542 	memcpy(ckpinfo, data.data, sizeof(VRFY_CKP_INFO));
1543 	*ckpinfopp = ckpinfo;
1544 err:
1545 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1546 		ret = tret;
1547 	if (ret != 0 && ret != DB_NOTFOUND)
1548 		__db_err(lvinfo->dbenv->env, ret, "__get_last_ckp_info");
1549 	return (ret);
1550 }
1551 
1552 /*
1553  * PUBLIC: int __put_ckp_info __P((const DB_LOG_VRFY_INFO *,
1554  * PUBLIC:     const VRFY_CKP_INFO *));
1555  */
__put_ckp_info(lvinfo,ckpinfo)1556 int __put_ckp_info (lvinfo, ckpinfo)
1557 	const DB_LOG_VRFY_INFO *lvinfo;
1558 	const VRFY_CKP_INFO *ckpinfo;
1559 {
1560 	int ret;
1561 	DBT key, data;
1562 
1563 	memset(&key, 0, sizeof(DBT));
1564 	memset(&data, 0, sizeof(DBT));
1565 	key.data = (void *)&ckpinfo->lsn;
1566 	key.size = sizeof(DB_LSN);
1567 	data.data = (void *)ckpinfo;
1568 	data.size = sizeof(VRFY_CKP_INFO);
1569 
1570 	BDBOP2(lvinfo->dbenv, __db_put(lvinfo->ckps, lvinfo->ip,
1571 	    NULL, &key, &data, 0), "__put_ckp_info");
1572 	return (0);
1573 }
1574 
1575 /*
1576  * PUBLIC: int __get_timestamp_info __P((const DB_LOG_VRFY_INFO *,
1577  * PUBLIC:     DB_LSN, VRFY_TIMESTAMP_INFO **));
1578  */
__get_timestamp_info(lvinfo,lsn,tsinfopp)1579 int __get_timestamp_info (lvinfo, lsn, tsinfopp)
1580 	const DB_LOG_VRFY_INFO *lvinfo;
1581 	DB_LSN lsn;
1582 	VRFY_TIMESTAMP_INFO **tsinfopp;
1583 {
1584 	int ret;
1585 	DBT key, data;
1586 	VRFY_TIMESTAMP_INFO *tsinfo;
1587 
1588 	memset(&key, 0, sizeof(DBT));
1589 	memset(&data, 0, sizeof(DBT));
1590 	key.data = &lsn;
1591 	key.size = sizeof(DB_LSN);
1592 	BDBOP3(lvinfo->dbenv, __db_get(lvinfo->lsntime, lvinfo->ip, NULL,
1593 	    &key, &data, 0), DB_NOTFOUND, "__get_timestamp_info");
1594 
1595 	if (ret == DB_NOTFOUND)
1596 		goto err;
1597 
1598 	if ((ret = __os_malloc(lvinfo->dbenv->env,
1599 	    sizeof(VRFY_TIMESTAMP_INFO), &tsinfo)) != 0)
1600 		goto err;
1601 
1602 	memcpy(tsinfo, data.data, sizeof(VRFY_TIMESTAMP_INFO));
1603 	*tsinfopp = tsinfo;
1604 err:
1605 	return (ret);
1606 }
1607 
1608 /*
1609  * __get_latest_timestamp_info --
1610  *	Get latest timestamp info before lsn.
1611  * PUBLIC: int __get_latest_timestamp_info __P((const DB_LOG_VRFY_INFO *,
1612  * PUBLIC:     DB_LSN, VRFY_TIMESTAMP_INFO **));
1613  */
__get_latest_timestamp_info(lvinfo,lsn,tsinfopp)1614 int __get_latest_timestamp_info(lvinfo, lsn, tsinfopp)
1615 	const DB_LOG_VRFY_INFO *lvinfo;
1616 	DB_LSN lsn;
1617 	VRFY_TIMESTAMP_INFO **tsinfopp;
1618 {
1619 	int ret, tret;
1620 	DBT key, data;
1621 	VRFY_TIMESTAMP_INFO *tsinfo;
1622 	DBC *csr;
1623 
1624 	csr = NULL;
1625 	ret = tret = 0;
1626 	memset(&key, 0, sizeof(DBT));
1627 	memset(&data, 0, sizeof(DBT));
1628 
1629 	key.data = &lsn;
1630 	key.size = sizeof(lsn);
1631 	BDBOP(__db_cursor(lvinfo->lsntime, lvinfo->ip, NULL, &csr, 0));
1632 
1633 	BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1634 	BDBOP(__dbc_get(csr, &key, &data, DB_PREV));
1635 
1636 	if ((ret = __os_malloc(lvinfo->dbenv->env, sizeof(VRFY_TIMESTAMP_INFO),
1637 	    &tsinfo)) != 0)
1638 		goto err;
1639 
1640 	memcpy(tsinfo, data.data, sizeof(VRFY_TIMESTAMP_INFO));
1641 	*tsinfopp = tsinfo;
1642 
1643 err:
1644 	if (ret != 0 && ret != DB_NOTFOUND)
1645 		__db_err(lvinfo->dbenv->env,
1646 		    ret, "__get_latest_timestamp_info");
1647 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1648 		ret = tret;
1649 	return (ret);
1650 }
1651 
1652 /*
1653  * PUBLIC: int __put_timestamp_info __P((const DB_LOG_VRFY_INFO *,
1654  * PUBLIC:     const VRFY_TIMESTAMP_INFO *));
1655  */
__put_timestamp_info(lvinfo,tsinfo)1656 int __put_timestamp_info (lvinfo, tsinfo)
1657 	const DB_LOG_VRFY_INFO *lvinfo;
1658 	const VRFY_TIMESTAMP_INFO *tsinfo;
1659 {
1660 	int ret;
1661 	DBT key, data;
1662 
1663 	memset(&key, 0, sizeof(DBT));
1664 	memset(&data, 0, sizeof(DBT));
1665 	key.data = (void *)&(tsinfo->lsn);
1666 	key.size = sizeof(DB_LSN);
1667 	data.data = (void *)tsinfo;
1668 	data.size = sizeof(VRFY_TIMESTAMP_INFO);
1669 	BDBOP2(lvinfo->dbenv, __db_put(lvinfo->lsntime, lvinfo->ip, NULL,
1670 	    &key, &data, 0), "__put_timestamp_info");
1671 
1672 	return (0);
1673 }
1674 
1675 static int
__lv_txnrgns_lsn_cmp(db,d1,d2,locp)1676 __lv_txnrgns_lsn_cmp (db, d1, d2, locp)
1677 	DB *db;
1678 	const DBT *d1, *d2;
1679 	size_t *locp;
1680 {
1681 	struct __lv_txnrange r1, r2;
1682 
1683 	COMPQUIET(locp, NULL);
1684 
1685 	DB_ASSERT(db->env, d1->size == sizeof(r1));
1686 	DB_ASSERT(db->env, d2->size == sizeof(r2));
1687 	memcpy(&r1, d1->data, d1->size);
1688 	memcpy(&r2, d2->data, d2->size);
1689 
1690 	COMPQUIET(db, NULL);
1691 	return (LOG_COMPARE(&(r1.end), &(r2.end)));
1692 }
1693 
1694 /*
1695  * __find_lsnrg_by_timerg --
1696  *	Find the lsn closed interval [beginlsn, endlsn] so that the
1697  *	corresponding timestamp interval fully contains interval [begin, end].
1698  * PUBLIC: int __find_lsnrg_by_timerg __P((DB_LOG_VRFY_INFO *,
1699  * PUBLIC:     time_t, time_t, DB_LSN *, DB_LSN *));
1700  */
1701 int
__find_lsnrg_by_timerg(lvinfo,begin,end,startlsn,endlsn)1702 __find_lsnrg_by_timerg(lvinfo, begin, end, startlsn, endlsn)
1703 	DB_LOG_VRFY_INFO *lvinfo;
1704 	time_t begin, end;
1705 	DB_LSN *startlsn, *endlsn;
1706 {
1707 	int ret, tret;
1708 	DBC *csr;
1709 	struct __lv_timestamp_info *t1, *t2;
1710 	DBT key, data;
1711 
1712 	ret = tret = 0;
1713 	csr = NULL;
1714 	memset(&key, 0, sizeof(DBT));
1715 	memset(&data, 0, sizeof(DBT));
1716 
1717 	BDBOP(__db_cursor(lvinfo->timelsn, lvinfo->ip, NULL, &csr, 0));
1718 
1719 	/*
1720 	 * We want a lsn range that completely contains [begin, end], so
1721 	 * try move 1 record prev when getting the startlsn.
1722 	 */
1723 	key.data = &begin;
1724 	key.size = sizeof(begin);
1725 	BDBOP(__dbc_get(csr, &key, &data, DB_SET_RANGE));
1726 	if ((ret = __dbc_get(csr, &key, &data, DB_PREV)) != 0 &&
1727 	    ret != DB_NOTFOUND)
1728 		goto err;
1729 	if (ret == DB_NOTFOUND)/* begin is smaller than the smallest key. */
1730 		startlsn->file = startlsn->offset = 0;/* beginning. */
1731 	else {
1732 		t1 = (struct __lv_timestamp_info *)data.data;
1733 		*startlsn = t1->lsn;
1734 	}
1735 
1736 	/*
1737 	 * Move to the last key/data pair of the duplicate set to get the
1738 	 * biggest lsn having end as timestamp.
1739 	 */
1740 	key.data = &end;
1741 	key.size = sizeof(end);
1742 	if ((ret = __dbc_get(csr, &key, &data, DB_SET_RANGE)) != 0 &&
1743 	    ret != DB_NOTFOUND)
1744 		goto err;
1745 	if (ret == DB_NOTFOUND) {
1746 		endlsn->file = endlsn->offset = (u_int32_t)-1;/* Biggest lsn. */
1747 		ret = 0;
1748 		goto err; /* We are done. */
1749 	}
1750 
1751 	/*
1752 	 * Go to the biggest lsn of the dup set, if the key is the last one,
1753 	 * go to the last one.
1754 	 */
1755 	if ((ret = __dbc_get(csr, &key, &data, DB_NEXT_NODUP)) != 0 &&
1756 	    ret != DB_NOTFOUND)
1757 		goto err;
1758 
1759 	if (ret == DB_NOTFOUND)
1760 		BDBOP(__dbc_get(csr, &key, &data, DB_LAST));
1761 	else
1762 		BDBOP(__dbc_get(csr, &key, &data, DB_PREV));
1763 
1764 	t2 = (struct __lv_timestamp_info *)data.data;
1765 	*endlsn = t2->lsn;
1766 err:
1767 	if (ret == DB_NOTFOUND)
1768 		ret = 0;
1769 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1770 		ret = tret;
1771 	return (ret);
1772 }
1773 
1774 /*
1775  * PUBLIC: int __add_txnrange __P((DB_LOG_VRFY_INFO *, u_int32_t,
1776  * PUBLIC:     DB_LSN, int32_t, int));
1777  */
__add_txnrange(lvinfo,txnid,lsn,when,ishead)1778 int __add_txnrange (lvinfo, txnid, lsn, when, ishead)
1779 	DB_LOG_VRFY_INFO *lvinfo;
1780 	u_int32_t txnid;
1781 	DB_LSN lsn;
1782 	int32_t when;
1783 	int ishead; /* Whether it's the 1st log of the txn. */
1784 {
1785 	int ret, tret;
1786 	DBC *csr;
1787 	struct __lv_txnrange tr, *ptr;
1788 	DBT key, data;
1789 
1790 	csr = NULL;
1791 	ret = 0;
1792 	ptr = NULL;
1793 	memset(&key, 0, sizeof(DBT));
1794 	memset(&data, 0, sizeof(DBT));
1795 	memset(&tr, 0, sizeof(tr));
1796 
1797 	key.data = &txnid;
1798 	key.size = sizeof(txnid);
1799 	tr.txnid = txnid;
1800 	BDBOP(__db_cursor(lvinfo->txnrngs, lvinfo->ip, NULL, &csr, 0));
1801 	/*
1802 	 * Note that we will backward play the logs to gather such information.
1803 	 */
1804 	if (!ishead) {
1805 		tr.end = lsn;
1806 		tr.when_commit = when;
1807 		data.data = &tr;
1808 		data.size = sizeof(tr);
1809 		BDBOP(__dbc_put(csr, &key, &data, DB_KEYFIRST));
1810 	} else {
1811 		/*
1812 		 * Dup data sorted by lsn, and we are backward playing logs,
1813 		 * so the 1st record should be the one we want.
1814 		 */
1815 		BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1816 		ptr = (struct __lv_txnrange *)data.data;
1817 		DB_ASSERT(lvinfo->dbenv->env, IS_ZERO_LSN(ptr->begin));
1818 		ptr->begin = lsn;
1819 		BDBOP(__dbc_put(csr, &key, &data, DB_CURRENT));
1820 	}
1821 
1822 err:
1823 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1824 		ret = tret;
1825 	return (ret);
1826 }
1827 
1828 /*
1829  * __get_aborttxn --
1830  *	If lsn is the last log of an aborted txn T, T's txnid is
1831  *	returned via the log verify handle.
1832  *
1833  * PUBLIC: int __get_aborttxn __P((DB_LOG_VRFY_INFO *, DB_LSN));
1834  */
1835 int
__get_aborttxn(lvinfo,lsn)1836 __get_aborttxn(lvinfo, lsn)
1837 	DB_LOG_VRFY_INFO *lvinfo;
1838 	DB_LSN lsn;
1839 {
1840 	int ret, tret;
1841 	u_int32_t txnid;
1842 	DBC *csr;
1843 	DBT key, data;
1844 
1845 	csr = NULL;
1846 	txnid = 0;
1847 	ret = tret = 0;
1848 	memset(&key, 0, sizeof(DBT));
1849 	memset(&data, 0, sizeof(DBT));
1850 
1851 	key.data = &lsn;
1852 	key.size = sizeof(lsn);
1853 	BDBOP(__db_cursor(lvinfo->txnaborts, lvinfo->ip, NULL, &csr, 0));
1854 	BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1855 	memcpy(&txnid, data.data, data.size);
1856 	/*
1857 	 * The lsn is the last op of an aborted txn, call __on_txnabort
1858 	 * before processing next log record.
1859 	 */
1860 	lvinfo->aborted_txnid = txnid;
1861 	lvinfo->aborted_txnlsn = lsn;
1862 
1863 err:
1864 	/* It's OK if can't find it. */
1865 	if (ret == DB_NOTFOUND)
1866 		ret = 0;
1867 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1868 		ret = tret;
1869 	return (ret);
1870 }
1871 
1872 /*
1873  * __txn_started --
1874  *	Whether txnid is started before lsn and ended after lsn.
1875  *
1876  * PUBLIC: int __txn_started __P((DB_LOG_VRFY_INFO *,
1877  * PUBLIC:     DB_LSN, u_int32_t, int *));
1878  */
1879 int
__txn_started(lvinfo,lsn,txnid,res)1880 __txn_started(lvinfo, lsn, txnid, res)
1881 	DB_LOG_VRFY_INFO *lvinfo;
1882 	DB_LSN lsn;
1883 	u_int32_t txnid;
1884 	int *res;
1885 {
1886 	int ret, tret;
1887 	DBC *csr;
1888 	DBT key, data;
1889 	struct __lv_txnrange *ptr, tr;
1890 
1891 	ret = *res = 0;
1892 	csr = NULL;
1893 	memset(&tr, 0, sizeof(tr));
1894 	memset(&key, 0, sizeof(DBT));
1895 	memset(&data, 0, sizeof(DBT));
1896 	key.data = &txnid;
1897 	key.size = sizeof(txnid);
1898 
1899 	BDBOP(__db_cursor(lvinfo->txnrngs, lvinfo->ip, NULL, &csr, 0));
1900 	BDBOP(__dbc_get(csr, &key, &data, DB_SET));
1901 	for (;ret == 0; ret = __dbc_get(csr, &key, &data, DB_NEXT_DUP)) {
1902 		ptr = (struct __lv_txnrange *)data.data;
1903 		if (LOG_COMPARE(&lsn, &(ptr->begin)) > 0 &&
1904 		    LOG_COMPARE(&lsn, &(ptr->end)) <= 0) {
1905 			*res = 1;
1906 			break;
1907 		}
1908 	}
1909 err:
1910 	if (ret == DB_NOTFOUND)
1911 		ret = 0;/* It's OK if can't find it. */
1912 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
1913 		ret = tret;
1914 	return (ret);
1915 }
1916 
1917 /*
1918  * PUBLIC: int __set_logvrfy_dbfuid __P((DB_LOG_VRFY_INFO *));
1919  */
1920 int
__set_logvrfy_dbfuid(lvinfo)1921 __set_logvrfy_dbfuid(lvinfo)
1922 	DB_LOG_VRFY_INFO *lvinfo;
1923 {
1924 	int ret;
1925 	const char *p;
1926 	DBT key, data;
1927 	size_t buflen;
1928 
1929 	p = NULL;
1930 	memset(&key, 0, sizeof(DBT));
1931 	memset(&data, 0, sizeof(DBT));
1932 
1933 	/* So far we only support verifying a specific db file. */
1934 	p = lvinfo->lv_config->dbfile;
1935 	buflen = sizeof(char) * (strlen(p) + 1);
1936 	key.data = (char *)p;
1937 	key.size = (u_int32_t)buflen;
1938 
1939 	BDBOP2(lvinfo->dbenv, __db_get(lvinfo->fnameuid, lvinfo->ip, NULL,
1940 	    &key, &data, 0), "__set_logvrfy_dbfuid");
1941 
1942 	memcpy(lvinfo->target_dbid, data.data, DB_FILE_ID_LEN);
1943 
1944 	return (ret);
1945 }
1946 
1947 /*
1948  * __add_page_to_txn --
1949  *	Try adding a page to a txn, result brings back if really added(0/1)
1950  *	or if there is an access violation(-1).
1951  * PUBLIC: int __add_page_to_txn __P((DB_LOG_VRFY_INFO *,
1952  * PUBLIC:     int32_t, db_pgno_t, u_int32_t, u_int32_t *, int *));
1953  */
1954 int
__add_page_to_txn(lvinfo,dbregid,pgno,txnid,otxn,result)1955 __add_page_to_txn (lvinfo, dbregid, pgno, txnid, otxn, result)
1956 	DB_LOG_VRFY_INFO *lvinfo;
1957 	int32_t dbregid;
1958 	db_pgno_t pgno;
1959 	u_int32_t txnid, *otxn;
1960 	int *result;
1961 {
1962 	int ret;
1963 	u_int8_t *buf;
1964 	DBT key, data;
1965 	size_t buflen;
1966 	u_int32_t txnid2;
1967 	VRFY_FILELIFE *pff;
1968 
1969 	if (txnid < TXN_MINIMUM) {
1970 		*result = 0;
1971 		return (0);
1972 	}
1973 	buf = NULL;
1974 	ret = 0;
1975 	txnid2 = 0;
1976 	pff = NULL;
1977 	buflen = sizeof(u_int8_t) * DB_FILE_ID_LEN + sizeof(db_pgno_t);
1978 	BDBOP(__os_malloc(lvinfo->dbenv->env, buflen, &buf));
1979 	memset(buf, 0, buflen);
1980 	memset(&key, 0, sizeof(DBT));
1981 	memset(&data, 0, sizeof(DBT));
1982 
1983 	/*
1984 	 * We use the file uid as key because a single db file can have
1985 	 * multiple dbregid at the same time, and we may neglect the fact
1986 	 * that the same db file is being updated by multiple txns if we use
1987 	 * dbregid as key.
1988 	 */
1989 	key.data = &dbregid;
1990 	key.size = sizeof(dbregid);
1991 	if ((ret = __db_get(lvinfo->dbregids, lvinfo->ip, NULL,
1992 	    &key, &data, 0)) != 0) {
1993 		if (ret == DB_NOTFOUND) {
1994 			if (F_ISSET(lvinfo, DB_LOG_VERIFY_PARTIAL)) {
1995 				ret = 0;
1996 				goto out;
1997 			} else
1998 				F_SET(lvinfo, DB_LOG_VERIFY_INTERR);
1999 		}
2000 		goto err;
2001 	}
2002 	pff = (VRFY_FILELIFE *)data.data;
2003 	memcpy(buf, pff->fileid, DB_FILE_ID_LEN);
2004 	memcpy(buf + DB_FILE_ID_LEN, (u_int8_t *)&pgno, sizeof(pgno));
2005 	memset(&key, 0, sizeof(DBT));
2006 	memset(&data, 0, sizeof(DBT));
2007 	key.data = buf;
2008 	key.size = (u_int32_t)buflen;
2009 	if ((ret = __db_get(lvinfo->pgtxn, lvinfo->ip, NULL,
2010 	    &key, &data, 0)) != 0) {
2011 		if (ret == DB_NOTFOUND) {
2012 			data.data = &txnid;
2013 			data.size = sizeof(txnid);
2014 			BDBOP(__db_put(lvinfo->pgtxn, lvinfo->ip, NULL, &key,
2015 			    &data, 0));
2016 			*result = 1;
2017 			ret = 0;/* This is not an error. */
2018 		}
2019 		goto err;
2020 	}
2021 	DB_ASSERT(lvinfo->dbenv->env, data.size == sizeof(txnid2));
2022 	memcpy(&txnid2, data.data, data.size);
2023 	if (txnid == txnid2)/* The same txn already has the page. */
2024 		*result = 0;
2025 	else {/* Txn txnid is updating pages still held by txnid2. */
2026 		*result = -1;
2027 		*otxn = txnid2;
2028 	}
2029 out:
2030 	/* result is set to -1 on violation, 0 if already has it, 1 if added. */
2031 err:
2032 	if (buf != NULL)
2033 		__os_free(lvinfo->dbenv->env, buf);
2034 	return (ret);
2035 }
2036 
2037 /*
2038  * PUBLIC: int __del_txn_pages __P((DB_LOG_VRFY_INFO *, u_int32_t));
2039  */
2040 int
__del_txn_pages(lvinfo,txnid)2041 __del_txn_pages(lvinfo, txnid)
2042 	DB_LOG_VRFY_INFO *lvinfo;
2043 	u_int32_t txnid;
2044 {
2045 	int ret;
2046 	DBT key;
2047 
2048 	ret = 0;
2049 	memset(&key, 0, sizeof(DBT));
2050 	key.data = &txnid;
2051 	key.size = sizeof(txnid);
2052 
2053 	BDBOP(__db_del(lvinfo->txnpg, lvinfo->ip, NULL, &key, 0));
2054 
2055 err:
2056 	return (ret);
2057 }
2058 
2059 /*
2060  * __is_ancestor_txn --
2061  *	Tells via res if ptxnid is txnid's parent txn at the moment of lsn.
2062  *
2063  * PUBLIC: int __is_ancestor_txn __P((DB_LOG_VRFY_INFO *,
2064  * PUBLIC:     u_int32_t, u_int32_t, DB_LSN, int *));
2065  */
2066 int
__is_ancestor_txn(lvinfo,ptxnid,txnid,lsn,res)2067 __is_ancestor_txn (lvinfo, ptxnid, txnid, lsn, res)
2068 	DB_LOG_VRFY_INFO *lvinfo;
2069 	u_int32_t ptxnid, txnid;
2070 	DB_LSN lsn;
2071 	int *res;
2072 {
2073 	u_int32_t ptid;
2074 	int ret, tret;
2075 	DBC *csr;
2076 	DB *pdb;
2077 	DBT key, data;
2078 	struct __lv_txnrange tr;
2079 
2080 	ret = 0;
2081 	ptid = txnid;
2082 	csr = NULL;
2083 	pdb = lvinfo->txnrngs;
2084 	memset(&key, 0, sizeof(DBT));
2085 	memset(&data, 0, sizeof(DBT));
2086 	*res = 0;
2087 	BDBOP(__db_cursor(pdb, lvinfo->ip, NULL, &csr, 0));
2088 
2089 	/* See if ptxnid is an ancestor of txnid. */
2090 	do {
2091 		key.data = &ptid;
2092 		key.size = sizeof(ptid);
2093 		BDBOP(__dbc_get(csr, &key, &data, DB_SET));
2094 		/* A txnid maybe reused, we want the range having lsn in it. */
2095 		for (;ret == 0;
2096 		    ret = __dbc_get(csr, &key, &data, DB_NEXT_DUP)) {
2097 			DB_ASSERT(pdb->env, sizeof(tr) == data.size);
2098 			memcpy(&tr, data.data, data.size);
2099 			if (tr.ptxnid > 0 &&
2100 			    LOG_COMPARE(&lsn, &(tr.begin)) >= 0 &&
2101 			    LOG_COMPARE(&lsn, &(tr.end)) <= 0)
2102 				break;
2103 		}
2104 
2105 		if (tr.ptxnid == ptxnid) {
2106 			*res = 1;
2107 			goto out;
2108 		} else
2109 			ptid = tr.ptxnid;
2110 
2111 	} while (ptid != 0);
2112 out:
2113 
2114 err:
2115 	if (ret == DB_NOTFOUND)
2116 		ret = 0;
2117 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
2118 		ret = tret;
2119 	return (ret);
2120 }
2121 
2122 /*
2123  * PUBLIC: int __return_txn_pages __P((DB_LOG_VRFY_INFO *,
2124  * PUBLIC:     u_int32_t, u_int32_t));
2125  */
__return_txn_pages(lvh,ctxn,ptxn)2126 int __return_txn_pages(lvh, ctxn, ptxn)
2127 	DB_LOG_VRFY_INFO *lvh;
2128 	u_int32_t ctxn, ptxn;
2129 {
2130 	int ret, tret;
2131 	DBC *csr;
2132 	DB *pdb, *sdb;
2133 	DBT key, key2, data, data2;
2134 	char buf[DB_FILE_ID_LEN + sizeof(db_pgno_t)];
2135 
2136 	ret = tret = 0;
2137 	csr = NULL;
2138 	sdb = lvh->txnpg;
2139 	pdb = lvh->pgtxn;
2140 	memset(&key, 0, sizeof(DBT));
2141 	memset(&key2, 0, sizeof(DBT));
2142 	memset(&data, 0, sizeof(DBT));
2143 	memset(&data2, 0, sizeof(DBT));
2144 
2145 	BDBOP(__db_cursor(sdb, lvh->ip, NULL, &csr, 0));
2146 	key.data = &ctxn;
2147 	key.size = sizeof(ctxn);
2148 	key2.data = &ptxn;
2149 	key2.size = sizeof(ptxn);
2150 	data2.data = buf;
2151 	data2.ulen = DB_FILE_ID_LEN + sizeof(db_pgno_t);
2152 	data2.flags = DB_DBT_USERMEM;
2153 
2154 	for (ret = __dbc_pget(csr, &key, &data2, &data, DB_SET); ret == 0;
2155 	    ret = __dbc_pget(csr, &key, &data2, &data, DB_NEXT_DUP))
2156 		BDBOP(__db_put(pdb, lvh->ip, NULL, &data2, &key2, 0));
2157 	if ((ret = __del_txn_pages(lvh, ctxn)) != 0 && ret != DB_NOTFOUND)
2158 		goto err;
2159 err:
2160 	if (csr != NULL && (tret = __dbc_close(csr)) != 0 && ret == 0)
2161 		ret = tret;
2162 	return (ret);
2163 }
2164 
2165 #define	ADD_ITEM(lvh, logtype) ((lvh)->logtype_names[(logtype)] = (#logtype))
2166 static void
__lv_setup_logtype_names(lvinfo)2167 __lv_setup_logtype_names(lvinfo)
2168 	DB_LOG_VRFY_INFO *lvinfo;
2169 {
2170 	ADD_ITEM(lvinfo, DB___bam_irep);
2171 	ADD_ITEM(lvinfo, DB___bam_split_42);
2172 	ADD_ITEM(lvinfo, DB___bam_split);
2173 	ADD_ITEM(lvinfo, DB___bam_rsplit);
2174 	ADD_ITEM(lvinfo, DB___bam_adj);
2175 	ADD_ITEM(lvinfo, DB___bam_cadjust);
2176 	ADD_ITEM(lvinfo, DB___bam_cdel);
2177 	ADD_ITEM(lvinfo, DB___bam_repl);
2178 	ADD_ITEM(lvinfo, DB___bam_root);
2179 	ADD_ITEM(lvinfo, DB___bam_curadj);
2180 	ADD_ITEM(lvinfo, DB___bam_rcuradj);
2181 	ADD_ITEM(lvinfo, DB___bam_relink_43);
2182 	ADD_ITEM(lvinfo, DB___bam_merge_44);
2183 	ADD_ITEM(lvinfo, DB___crdel_metasub);
2184 	ADD_ITEM(lvinfo, DB___crdel_inmem_create);
2185 	ADD_ITEM(lvinfo, DB___crdel_inmem_rename);
2186 	ADD_ITEM(lvinfo, DB___crdel_inmem_remove);
2187 	ADD_ITEM(lvinfo, DB___dbreg_register);
2188 	ADD_ITEM(lvinfo, DB___db_addrem);
2189 	ADD_ITEM(lvinfo, DB___db_big);
2190 	ADD_ITEM(lvinfo, DB___db_ovref);
2191 	ADD_ITEM(lvinfo, DB___db_relink_42);
2192 	ADD_ITEM(lvinfo, DB___db_debug);
2193 	ADD_ITEM(lvinfo, DB___db_noop);
2194 	ADD_ITEM(lvinfo, DB___db_pg_alloc_42);
2195 	ADD_ITEM(lvinfo, DB___db_pg_alloc);
2196 	ADD_ITEM(lvinfo, DB___db_pg_free_42);
2197 	ADD_ITEM(lvinfo, DB___db_pg_free);
2198 	ADD_ITEM(lvinfo, DB___db_cksum);
2199 	ADD_ITEM(lvinfo, DB___db_pg_freedata_42);
2200 	ADD_ITEM(lvinfo, DB___db_pg_freedata);
2201 	ADD_ITEM(lvinfo, DB___db_pg_init);
2202 	ADD_ITEM(lvinfo, DB___db_pg_sort_44);
2203 	ADD_ITEM(lvinfo, DB___db_pg_trunc);
2204 	ADD_ITEM(lvinfo, DB___db_realloc);
2205 	ADD_ITEM(lvinfo, DB___db_relink);
2206 	ADD_ITEM(lvinfo, DB___db_merge);
2207 	ADD_ITEM(lvinfo, DB___db_pgno);
2208 #ifdef HAVE_HASH
2209 	ADD_ITEM(lvinfo, DB___ham_insdel);
2210 	ADD_ITEM(lvinfo, DB___ham_newpage);
2211 	ADD_ITEM(lvinfo, DB___ham_splitdata);
2212 	ADD_ITEM(lvinfo, DB___ham_replace);
2213 	ADD_ITEM(lvinfo, DB___ham_copypage);
2214 	ADD_ITEM(lvinfo, DB___ham_metagroup_42);
2215 	ADD_ITEM(lvinfo, DB___ham_metagroup);
2216 	ADD_ITEM(lvinfo, DB___ham_groupalloc_42);
2217 	ADD_ITEM(lvinfo, DB___ham_groupalloc);
2218 	ADD_ITEM(lvinfo, DB___ham_changeslot);
2219 	ADD_ITEM(lvinfo, DB___ham_contract);
2220 	ADD_ITEM(lvinfo, DB___ham_curadj);
2221 	ADD_ITEM(lvinfo, DB___ham_chgpg);
2222 #endif
2223 #ifdef HAVE_QUEUE
2224 	ADD_ITEM(lvinfo, DB___qam_incfirst);
2225 	ADD_ITEM(lvinfo, DB___qam_mvptr);
2226 	ADD_ITEM(lvinfo, DB___qam_del);
2227 	ADD_ITEM(lvinfo, DB___qam_add);
2228 	ADD_ITEM(lvinfo, DB___qam_delext);
2229 #endif
2230 	ADD_ITEM(lvinfo, DB___txn_regop_42);
2231 	ADD_ITEM(lvinfo, DB___txn_regop);
2232 	ADD_ITEM(lvinfo, DB___txn_ckp_42);
2233 	ADD_ITEM(lvinfo, DB___txn_ckp);
2234 	ADD_ITEM(lvinfo, DB___txn_child);
2235 	ADD_ITEM(lvinfo, DB___txn_xa_regop_42);
2236 	ADD_ITEM(lvinfo, DB___txn_prepare);
2237 	ADD_ITEM(lvinfo, DB___txn_recycle);
2238 	ADD_ITEM(lvinfo, DB___fop_create_42);
2239 	ADD_ITEM(lvinfo, DB___fop_create);
2240 	ADD_ITEM(lvinfo, DB___fop_remove);
2241 	ADD_ITEM(lvinfo, DB___fop_write_42);
2242 	ADD_ITEM(lvinfo, DB___fop_write);
2243 	ADD_ITEM(lvinfo, DB___fop_rename_42);
2244 	ADD_ITEM(lvinfo, DB___fop_rename_noundo_46);
2245 	ADD_ITEM(lvinfo, DB___fop_rename);
2246 	ADD_ITEM(lvinfo, DB___fop_rename_noundo);
2247 	ADD_ITEM(lvinfo, DB___fop_file_remove);
2248 }
2249