1N/A/*-
1N/A * See the file LICENSE for redistribution information.
1N/A *
1N/A * Copyright (c) 1996, 1997, 1998
1N/A * Sleepycat Software. All rights reserved.
1N/A */
1N/A
1N/A#include "config.h"
1N/A
1N/A#ifndef lint
1N/Astatic const char sccsid[] = "@(#)db_rec.c 10.19 (Sleepycat) 9/27/98";
1N/A#endif /* not lint */
1N/A
1N/A#ifndef NO_SYSTEM_INCLUDES
1N/A#include <sys/types.h>
1N/A
1N/A#include <string.h>
1N/A#endif
1N/A
1N/A#include "db_int.h"
1N/A#include "shqueue.h"
1N/A#include "db_page.h"
1N/A#include "log.h"
1N/A#include "hash.h"
1N/A#include "btree.h"
1N/A
1N/A/*
1N/A * PUBLIC: int __db_addrem_recover
1N/A * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
1N/A *
1N/A * This log message is generated whenever we add or remove a duplicate
1N/A * to/from a duplicate page. On recover, we just do the opposite.
1N/A */
1N/Aint
1N/A__db_addrem_recover(logp, dbtp, lsnp, redo, info)
1N/A DB_LOG *logp;
1N/A DBT *dbtp;
1N/A DB_LSN *lsnp;
1N/A int redo;
1N/A void *info;
1N/A{
1N/A __db_addrem_args *argp;
1N/A DB *file_dbp;
1N/A DBC *dbc;
1N/A DB_MPOOLFILE *mpf;
1N/A PAGE *pagep;
1N/A u_int32_t change;
1N/A int cmp_n, cmp_p, ret;
1N/A
1N/A REC_PRINT(__db_addrem_print);
1N/A REC_INTRO(__db_addrem_read);
1N/A
1N/A if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
1N/A if (!redo) {
1N/A /*
1N/A * We are undoing and the page doesn't exist. That
1N/A * is equivalent to having a pagelsn of 0, so we
1N/A * would not have to undo anything. In this case,
1N/A * don't bother creating a page.
1N/A */
1N/A goto done;
1N/A } else
1N/A if ((ret = memp_fget(mpf,
1N/A &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
1N/A goto out;
1N/A }
1N/A
1N/A cmp_n = log_compare(lsnp, &LSN(pagep));
1N/A cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
1N/A change = 0;
1N/A if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_DUP) ||
1N/A (cmp_n == 0 && !redo && argp->opcode == DB_REM_DUP)) {
1N/A
1N/A /* Need to redo an add, or undo a delete. */
1N/A if ((ret = __db_pitem(dbc, pagep, argp->indx, argp->nbytes,
1N/A argp->hdr.size == 0 ? NULL : &argp->hdr,
1N/A argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
1N/A goto out;
1N/A
1N/A change = DB_MPOOL_DIRTY;
1N/A
1N/A } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_DUP) ||
1N/A (cmp_p == 0 && redo && argp->opcode == DB_REM_DUP)) {
1N/A /* Need to undo an add, or redo a delete. */
1N/A if ((ret = __db_ditem(dbc,
1N/A pagep, argp->indx, argp->nbytes)) != 0)
1N/A goto out;
1N/A change = DB_MPOOL_DIRTY;
1N/A }
1N/A
1N/A if (change)
1N/A if (redo)
1N/A LSN(pagep) = *lsnp;
1N/A else
1N/A LSN(pagep) = argp->pagelsn;
1N/A
1N/A if ((ret = memp_fput(mpf, pagep, change)) != 0)
1N/A goto out;
1N/A
1N/Adone: *lsnp = argp->prev_lsn;
1N/A ret = 0;
1N/A
1N/Aout: REC_CLOSE;
1N/A}
1N/A
1N/A/*
1N/A * PUBLIC: int __db_split_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
1N/A */
1N/Aint
1N/A__db_split_recover(logp, dbtp, lsnp, redo, info)
1N/A DB_LOG *logp;
1N/A DBT *dbtp;
1N/A DB_LSN *lsnp;
1N/A int redo;
1N/A void *info;
1N/A{
1N/A __db_split_args *argp;
1N/A DB *file_dbp;
1N/A DBC *dbc;
1N/A DB_MPOOLFILE *mpf;
1N/A PAGE *pagep;
1N/A int change, cmp_n, cmp_p, ret;
1N/A
1N/A REC_PRINT(__db_split_print);
1N/A REC_INTRO(__db_split_read);
1N/A
1N/A if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0)
1N/A if (!redo) {
1N/A /*
1N/A * We are undoing and the page doesn't exist. That
1N/A * is equivalent to having a pagelsn of 0, so we
1N/A * would not have to undo anything. In this case,
1N/A * don't bother creating a page.
1N/A */
1N/A goto done;
1N/A } else
1N/A if ((ret = memp_fget(mpf,
1N/A &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
1N/A goto out;
1N/A
1N/A /*
1N/A * There are two types of log messages here, one for the old page
1N/A * and one for the new pages created. The original image in the
1N/A * SPLITOLD record is used for undo. The image in the SPLITNEW
1N/A * is used for redo. We should never have a case where there is
1N/A * a redo operation and the SPLITOLD record is on disk, but not
1N/A * the SPLITNEW record. Therefore, we only redo NEW messages
1N/A * and only undo OLD messages.
1N/A */
1N/A
1N/A change = 0;
1N/A cmp_n = log_compare(lsnp, &LSN(pagep));
1N/A cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
1N/A if (cmp_p == 0 && redo) {
1N/A if (argp->opcode == DB_SPLITNEW) {
1N/A /* Need to redo the split described. */
1N/A memcpy(pagep,
1N/A argp->pageimage.data, argp->pageimage.size);
1N/A }
1N/A LSN(pagep) = *lsnp;
1N/A change = DB_MPOOL_DIRTY;
1N/A } else if (cmp_n == 0 && !redo) {
1N/A if (argp->opcode == DB_SPLITOLD) {
1N/A /* Put back the old image. */
1N/A memcpy(pagep,
1N/A argp->pageimage.data, argp->pageimage.size);
1N/A }
1N/A LSN(pagep) = argp->pagelsn;
1N/A change = DB_MPOOL_DIRTY;
1N/A }
1N/A if ((ret = memp_fput(mpf, pagep, change)) != 0)
1N/A goto out;
1N/A
1N/Adone: *lsnp = argp->prev_lsn;
1N/A ret = 0;
1N/A
1N/Aout: REC_CLOSE;
1N/A}
1N/A
1N/A/*
1N/A * PUBLIC: int __db_big_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
1N/A */
1N/Aint
1N/A__db_big_recover(logp, dbtp, lsnp, redo, info)
1N/A DB_LOG *logp;
1N/A DBT *dbtp;
1N/A DB_LSN *lsnp;
1N/A int redo;
1N/A void *info;
1N/A{
1N/A __db_big_args *argp;
1N/A DB *file_dbp;
1N/A DBC *dbc;
1N/A DB_MPOOLFILE *mpf;
1N/A PAGE *pagep;
1N/A u_int32_t change;
1N/A int cmp_n, cmp_p, ret;
1N/A
1N/A REC_PRINT(__db_big_print);
1N/A REC_INTRO(__db_big_read);
1N/A
1N/A if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
1N/A if (!redo) {
1N/A /*
1N/A * We are undoing and the page doesn't exist. That
1N/A * is equivalent to having a pagelsn of 0, so we
1N/A * would not have to undo anything. In this case,
1N/A * don't bother creating a page.
1N/A */
1N/A ret = 0;
1N/A goto ppage;
1N/A } else
1N/A if ((ret = memp_fget(mpf,
1N/A &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
1N/A goto out;
1N/A }
1N/A
1N/A /*
1N/A * There are three pages we need to check. The one on which we are
1N/A * adding data, the previous one whose next_pointer may have
1N/A * been updated, and the next one whose prev_pointer may have
1N/A * been updated.
1N/A */
1N/A cmp_n = log_compare(lsnp, &LSN(pagep));
1N/A cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
1N/A change = 0;
1N/A if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
1N/A (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
1N/A /* We are either redo-ing an add, or undoing a delete. */
1N/A P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno,
1N/A argp->next_pgno, 0, P_OVERFLOW);
1N/A OV_LEN(pagep) = argp->dbt.size;
1N/A OV_REF(pagep) = 1;
1N/A memcpy((u_int8_t *)pagep + P_OVERHEAD, argp->dbt.data,
1N/A argp->dbt.size);
1N/A PREV_PGNO(pagep) = argp->prev_pgno;
1N/A change = DB_MPOOL_DIRTY;
1N/A } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_BIG) ||
1N/A (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
1N/A /*
1N/A * We are either undo-ing an add or redo-ing a delete.
1N/A * The page is about to be reclaimed in either case, so
1N/A * there really isn't anything to do here.
1N/A */
1N/A change = DB_MPOOL_DIRTY;
1N/A }
1N/A if (change)
1N/A LSN(pagep) = redo ? *lsnp : argp->pagelsn;
1N/A
1N/A if ((ret = memp_fput(mpf, pagep, change)) != 0)
1N/A goto out;
1N/A
1N/A /* Now check the previous page. */
1N/Appage: if (argp->prev_pgno != PGNO_INVALID) {
1N/A change = 0;
1N/A if ((ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0)
1N/A if (!redo) {
1N/A /*
1N/A * We are undoing and the page doesn't exist.
1N/A * That is equivalent to having a pagelsn of 0,
1N/A * so we would not have to undo anything. In
1N/A * this case, don't bother creating a page.
1N/A */
1N/A *lsnp = argp->prev_lsn;
1N/A ret = 0;
1N/A goto npage;
1N/A } else
1N/A if ((ret = memp_fget(mpf, &argp->prev_pgno,
1N/A DB_MPOOL_CREATE, &pagep)) != 0)
1N/A goto out;
1N/A
1N/A cmp_n = log_compare(lsnp, &LSN(pagep));
1N/A cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
1N/A
1N/A if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
1N/A (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
1N/A /* Redo add, undo delete. */
1N/A NEXT_PGNO(pagep) = argp->pgno;
1N/A change = DB_MPOOL_DIRTY;
1N/A } else if ((cmp_n == 0 &&
1N/A !redo && argp->opcode == DB_ADD_BIG) ||
1N/A (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
1N/A /* Redo delete, undo add. */
1N/A NEXT_PGNO(pagep) = argp->next_pgno;
1N/A change = DB_MPOOL_DIRTY;
1N/A }
1N/A if (change)
1N/A LSN(pagep) = redo ? *lsnp : argp->prevlsn;
1N/A if ((ret = memp_fput(mpf, pagep, change)) != 0)
1N/A goto out;
1N/A }
1N/A
1N/A /* Now check the next page. Can only be set on a delete. */
1N/Anpage: if (argp->next_pgno != PGNO_INVALID) {
1N/A change = 0;
1N/A if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0)
1N/A if (!redo) {
1N/A /*
1N/A * We are undoing and the page doesn't exist.
1N/A * That is equivalent to having a pagelsn of 0,
1N/A * so we would not have to undo anything. In
1N/A * this case, don't bother creating a page.
1N/A */
1N/A goto done;
1N/A } else
1N/A if ((ret = memp_fget(mpf, &argp->next_pgno,
1N/A DB_MPOOL_CREATE, &pagep)) != 0)
1N/A goto out;
1N/A
1N/A cmp_n = log_compare(lsnp, &LSN(pagep));
1N/A cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
1N/A if (cmp_p == 0 && redo) {
1N/A PREV_PGNO(pagep) = PGNO_INVALID;
1N/A change = DB_MPOOL_DIRTY;
1N/A } else if (cmp_n == 0 && !redo) {
1N/A PREV_PGNO(pagep) = argp->pgno;
1N/A change = DB_MPOOL_DIRTY;
1N/A }
1N/A if (change)
1N/A LSN(pagep) = redo ? *lsnp : argp->nextlsn;
1N/A if ((ret = memp_fput(mpf, pagep, change)) != 0)
1N/A goto out;
1N/A }
1N/A
1N/Adone: *lsnp = argp->prev_lsn;
1N/A ret = 0;
1N/A
1N/Aout: REC_CLOSE;
1N/A}
1N/A
1N/A/*
1N/A * __db_ovref_recover --
1N/A * Recovery function for __db_ovref().
1N/A *
1N/A * PUBLIC: int __db_ovref_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
1N/A */
1N/Aint
1N/A__db_ovref_recover(logp, dbtp, lsnp, redo, info)
1N/A DB_LOG *logp;
1N/A DBT *dbtp;
1N/A DB_LSN *lsnp;
1N/A int redo;
1N/A void *info;
1N/A{
1N/A __db_ovref_args *argp;
1N/A DB *file_dbp;
1N/A DBC *dbc;
1N/A DB_MPOOLFILE *mpf;
1N/A PAGE *pagep;
1N/A int modified, ret;
1N/A
1N/A REC_PRINT(__db_ovref_print);
1N/A REC_INTRO(__db_ovref_read);
1N/A
1N/A if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
1N/A (void)__db_pgerr(file_dbp, argp->pgno);
1N/A goto out;
1N/A }
1N/A
1N/A modified = 0;
1N/A if (log_compare(&LSN(pagep), &argp->lsn) == 0 && redo) {
1N/A /* Need to redo update described. */
1N/A OV_REF(pagep) += argp->adjust;
1N/A
1N/A pagep->lsn = *lsnp;
1N/A modified = 1;
1N/A } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
1N/A /* Need to undo update described. */
1N/A OV_REF(pagep) -= argp->adjust;
1N/A
1N/A pagep->lsn = argp->lsn;
1N/A modified = 1;
1N/A }
1N/A if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
1N/A goto out;
1N/A
1N/Adone: *lsnp = argp->prev_lsn;
1N/A ret = 0;
1N/A
1N/Aout: REC_CLOSE;
1N/A}
1N/A
1N/A/*
1N/A * __db_relink_recover --
1N/A * Recovery function for relink.
1N/A *
1N/A * PUBLIC: int __db_relink_recover
1N/A * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
1N/A */
1N/Aint
1N/A__db_relink_recover(logp, dbtp, lsnp, redo, info)
1N/A DB_LOG *logp;
1N/A DBT *dbtp;
1N/A DB_LSN *lsnp;
1N/A int redo;
1N/A void *info;
1N/A{
1N/A __db_relink_args *argp;
1N/A DB *file_dbp;
1N/A DBC *dbc;
1N/A DB_MPOOLFILE *mpf;
1N/A PAGE *pagep;
1N/A int cmp_n, cmp_p, modified, ret;
1N/A
1N/A REC_PRINT(__db_relink_print);
1N/A REC_INTRO(__db_relink_read);
1N/A
1N/A /*
1N/A * There are up to three pages we need to check -- the page, and the
1N/A * previous and next pages, if they existed. For a page add operation,
1N/A * the current page is the result of a split and is being recovered
1N/A * elsewhere, so all we need do is recover the next page.
1N/A */
1N/A if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
1N/A if (redo) {
1N/A (void)__db_pgerr(file_dbp, argp->pgno);
1N/A goto out;
1N/A }
1N/A goto next;
1N/A }
1N/A if (argp->opcode == DB_ADD_PAGE)
1N/A goto next;
1N/A
1N/A modified = 0;
1N/A if (log_compare(&LSN(pagep), &argp->lsn) == 0 && redo) {
1N/A /* Redo the relink. */
1N/A pagep->lsn = *lsnp;
1N/A modified = 1;
1N/A } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
1N/A /* Undo the relink. */
1N/A pagep->next_pgno = argp->next;
1N/A pagep->prev_pgno = argp->prev;
1N/A
1N/A pagep->lsn = argp->lsn;
1N/A modified = 1;
1N/A }
1N/A if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
1N/A goto out;
1N/A
1N/Anext: if ((ret = memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
1N/A if (redo) {
1N/A (void)__db_pgerr(file_dbp, argp->next);
1N/A goto out;
1N/A }
1N/A goto prev;
1N/A }
1N/A modified = 0;
1N/A cmp_n = log_compare(lsnp, &LSN(pagep));
1N/A cmp_p = log_compare(&LSN(pagep), &argp->lsn_next);
1N/A if ((argp->opcode == DB_REM_PAGE && cmp_p == 0 && redo) ||
1N/A (argp->opcode == DB_ADD_PAGE && cmp_n == 0 && !redo)) {
1N/A /* Redo the remove or undo the add. */
1N/A pagep->prev_pgno = argp->prev;
1N/A
1N/A pagep->lsn = *lsnp;
1N/A modified = 1;
1N/A } else if ((argp->opcode == DB_REM_PAGE && cmp_n == 0 && !redo) ||
1N/A (argp->opcode == DB_ADD_PAGE && cmp_p == 0 && redo)) {
1N/A /* Undo the remove or redo the add. */
1N/A pagep->prev_pgno = argp->pgno;
1N/A
1N/A pagep->lsn = argp->lsn_next;
1N/A modified = 1;
1N/A }
1N/A if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
1N/A goto out;
1N/A if (argp->opcode == DB_ADD_PAGE)
1N/A goto done;
1N/A
1N/Aprev: if ((ret = memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
1N/A if (redo) {
1N/A (void)__db_pgerr(file_dbp, argp->prev);
1N/A goto out;
1N/A }
1N/A goto done;
1N/A }
1N/A modified = 0;
1N/A if (log_compare(&LSN(pagep), &argp->lsn_prev) == 0 && redo) {
1N/A /* Redo the relink. */
1N/A pagep->next_pgno = argp->next;
1N/A
1N/A pagep->lsn = *lsnp;
1N/A modified = 1;
1N/A } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
1N/A /* Undo the relink. */
1N/A pagep->next_pgno = argp->pgno;
1N/A
1N/A pagep->lsn = argp->lsn_prev;
1N/A modified = 1;
1N/A }
1N/A if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
1N/A goto out;
1N/A
1N/Adone: *lsnp = argp->prev_lsn;
1N/A ret = 0;
1N/A
1N/Aout: REC_CLOSE;
1N/A}
1N/A
1N/A/*
1N/A * PUBLIC: int __db_addpage_recover
1N/A * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
1N/A */
1N/Aint
1N/A__db_addpage_recover(logp, dbtp, lsnp, redo, info)
1N/A DB_LOG *logp;
1N/A DBT *dbtp;
1N/A DB_LSN *lsnp;
1N/A int redo;
1N/A void *info;
1N/A{
1N/A __db_addpage_args *argp;
1N/A DB *file_dbp;
1N/A DBC *dbc;
1N/A DB_MPOOLFILE *mpf;
1N/A PAGE *pagep;
1N/A u_int32_t change;
1N/A int cmp_n, cmp_p, ret;
1N/A
1N/A REC_PRINT(__db_addpage_print);
1N/A REC_INTRO(__db_addpage_read);
1N/A
1N/A /*
1N/A * We need to check two pages: the old one and the new one onto
1N/A * which we're going to add duplicates. Do the old one first.
1N/A */
1N/A if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0)
1N/A goto out;
1N/A
1N/A change = 0;
1N/A cmp_n = log_compare(lsnp, &LSN(pagep));
1N/A cmp_p = log_compare(&LSN(pagep), &argp->lsn);
1N/A if (cmp_p == 0 && redo) {
1N/A NEXT_PGNO(pagep) = argp->nextpgno;
1N/A
1N/A LSN(pagep) = *lsnp;
1N/A change = DB_MPOOL_DIRTY;
1N/A } else if (cmp_n == 0 && !redo) {
1N/A NEXT_PGNO(pagep) = PGNO_INVALID;
1N/A
1N/A LSN(pagep) = argp->lsn;
1N/A change = DB_MPOOL_DIRTY;
1N/A }
1N/A if ((ret = memp_fput(mpf, pagep, change)) != 0)
1N/A goto out;
1N/A
1N/A if ((ret = memp_fget(mpf, &argp->nextpgno, 0, &pagep)) != 0)
1N/A if (!redo) {
1N/A /*
1N/A * We are undoing and the page doesn't exist. That
1N/A * is equivalent to having a pagelsn of 0, so we
1N/A * would not have to undo anything. In this case,
1N/A * don't bother creating a page.
1N/A */
1N/A goto done;
1N/A } else
1N/A if ((ret = memp_fget(mpf,
1N/A &argp->nextpgno, DB_MPOOL_CREATE, &pagep)) != 0)
1N/A goto out;
1N/A
1N/A change = 0;
1N/A cmp_n = log_compare(lsnp, &LSN(pagep));
1N/A cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
1N/A if (cmp_p == 0 && redo) {
1N/A PREV_PGNO(pagep) = argp->pgno;
1N/A
1N/A LSN(pagep) = *lsnp;
1N/A change = DB_MPOOL_DIRTY;
1N/A } else if (cmp_n == 0 && !redo) {
1N/A PREV_PGNO(pagep) = PGNO_INVALID;
1N/A
1N/A LSN(pagep) = argp->nextlsn;
1N/A change = DB_MPOOL_DIRTY;
1N/A }
1N/A if ((ret = memp_fput(mpf, pagep, change)) != 0)
1N/A goto out;
1N/A
1N/Adone: *lsnp = argp->prev_lsn;
1N/A ret = 0;
1N/A
1N/Aout: REC_CLOSE;
1N/A}
1N/A
1N/A/*
1N/A * __db_debug_recover --
1N/A * Recovery function for debug.
1N/A *
1N/A * PUBLIC: int __db_debug_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
1N/A */
1N/Aint
1N/A__db_debug_recover(logp, dbtp, lsnp, redo, info)
1N/A DB_LOG *logp;
1N/A DBT *dbtp;
1N/A DB_LSN *lsnp;
1N/A int redo;
1N/A void *info;
1N/A{
1N/A __db_debug_args *argp;
1N/A int ret;
1N/A
1N/A COMPQUIET(redo, 0);
1N/A COMPQUIET(logp, NULL);
1N/A
1N/A REC_PRINT(__db_debug_print);
1N/A REC_NOOP_INTRO(__db_debug_read);
1N/A
1N/A *lsnp = argp->prev_lsn;
1N/A ret = 0;
1N/A
1N/A REC_NOOP_CLOSE;
1N/A}