Package org.chaidb.db.transaction.recover

Source Code of org.chaidb.db.transaction.recover.CatastrophicTxnRecoverImpl

/*
* Copyright (C) 2006  http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
*/

package org.chaidb.db.transaction.recover;

import org.apache.log4j.Logger;
import org.chaidb.db.Db;
import org.chaidb.db.DBState;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.helper.Config;
import org.chaidb.db.log.*;
import org.chaidb.db.log.logrecord.TxnCkpLogRecord;
import org.chaidb.db.transaction.TransactionManager;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.util.Date;


/**
* This class implements catastrophic transaction recovery.
* It extends from abstract class TransactionRecoverImpl.
*
* @version 1.0
*/
public class CatastrophicTxnRecoverImpl extends TransactionRecoverImpl {

    private static final Logger logger = Logger.getLogger(CatastrophicTxnRecoverImpl.class);

    protected final static String ARCHIVE_DIR = "archive.dir";
    protected final static String BACKUP_DIR = "backup.dir";

    private Lsn smallestLsn = null;

    /**
     * The length of logic lsn.
     */
    private int logic_lsn_length = -1;


    /**
     * The average length of logic lsn(1/5).
     */
    private int logic_lsn_average = -1;

    /**
     * The current lsn at which operate undo.
     */
    private Lsn cursorLsn = null;


    /**
     * The last lsn from which start to undo.
     */
    private Lsn lastLsn = null;

    private Timestamp timestamp = null;

    private Lsn backupLastLsn = null;

    private Lsn pitCheckPoint = null;

    public Lsn getPitCheckPoint() {
        return pitCheckPoint;
    }

    public void setBackupLastLsn(Lsn backupLastLsn) {
        this.backupLastLsn = backupLastLsn;
    }

    public void setTimestamp(Timestamp timestamp) {
        this.timestamp = timestamp;
    }

    /**
     * Constructor.
     *
     * @param txnManager The transaction manager
     */
    public CatastrophicTxnRecoverImpl(TransactionManager txnManager) {
        super(txnManager);
    }


    /**
     * Calculate the logic length between preLsn and nextLsn.
     *
     * @param prevLsn The previous lsn.
     * @param nextLsn The next lsn.
     * @return The logic length.
     */
    private int calLogicLength(Lsn prevLsn, Lsn nextLsn) {
        if (nextLsn.getFileId() == prevLsn.getFileId()) {
            return LogManagerImpl.LOG_FILE_MAX_SIZE * (nextLsn.getFileId() - prevLsn.getFileId()) + (nextLsn.getOffset() - prevLsn.getOffset());
        } else {
            return LogManagerImpl.LOG_FILE_MAX_SIZE * (nextLsn.getFileId() - prevLsn.getFileId()) + (LogManagerImpl.LOG_FILE_MAX_SIZE - prevLsn.getOffset());
        }
    }


    /*
     * Undo operation.
     * @exception ChaiDBException Exception while doing undo operation.
     */
    protected boolean undo() throws ChaiDBException {
        this.status = UNDO_STAGE;
        LogRecord cursorLogRecord = null;
        ////////////////////////////// UNDO OPERATION /////////////////////////////////
        //Gets the lastest lsn in lsn.idb file.
        /* Begin to get last lsn from LogManager*/
        cursorLsn = txnManager.getLogManager().getLastLsnInFlush();
        lastLsn = new Lsn(cursorLsn.getFileId(), cursorLsn.getOffset()); //Keep last lsn.
        /* End to get last lsn from LogManager*/
        //it can be changed to do incompleted recovery.
        logic_lsn_length = calLogicLength(smallestLsn, cursorLsn); //calculate the logic length need do recovery.
        logic_lsn_average = logic_lsn_length / 5;
        int currentProcess = 0;
        int percent = 0;

        boolean scan = false;
        if (timestamp != null && backupLastLsn != null) {
            scan = true;
        }
        Timestamp rtime = new Timestamp(0);
        boolean setCp = false;

        //  for (int i=0; cursorLsn.getOffset() != LogManager.FIRSTREC_PREVOFFSET ;i++)
        while ((cursorLsn.compare(smallestLsn) >= 0) && (cursorLsn.getOffset() != LogManager.FIRSTREC_PREVOFFSET)) {
            if (scan && cursorLsn.compare(backupLastLsn) < 0) {
                System.err.println("\nCan't find checkpoint from the given timestamp. Please try to \n" + "perform PIT recovery again and input a later timestamp or restore \n" + "to certain state of the backup.");
                return false;
            }

            percent = calLogicLength(cursorLsn, lastLsn) / logic_lsn_average;
            if (percent != currentProcess) {
                currentProcess++;
                if (currentProcess <= 5) {
                    System.out.print("\r" + currentProcess + "0% completed.");
                }
            }
            try {
                cursorLogRecord = txnManager.getLogManager().get(cursorLsn, smallestLsn);
            } catch (ChaiDBException e) {
                logger.error(e);
                throw e;
            }

            switch (cursorLogRecord.getType()) {
                case LogRecord.LOG_TXN_CHILD:
                    break;
                case LogRecord.LOG_TXN_CHECKPOINT:
//                    break;
                case LogRecord.LOG_TXN_FUZZY_CHECKPOINT://V3.1 fuzzy checkpoint
                    if (scan) {
//                        if (cursorLsn.compare(backupLastLsn) < 0) {
//                            System.err.println(
//                                    "\nCan't find checkpoint from the given timestamp. Please try to \n" +
//                                    "restore again and input another timestamp or skip PIT recovery.");
//                            return false;
//                        }
                        rtime.setTime(((TxnCkpLogRecord) cursorLogRecord).getTimeStamp());
                        //there are 3 conditions which we locate the checkpoint
                        //1. checkpoint is before the timestamp
                        //2. checkpoint is after backupLastLsn
                        //3. checkpoint is after the timestamp but diff is less than half
                        //    of checkpoint inteval.
                        if (rtime.after(timestamp) && cursorLsn.compare(backupLastLsn) > 0) {
                            long dt = (rtime.getTime() - timestamp.getTime()) / 1000;
                            if (dt < 0) {
                                dt = -dt;
                            }
                            int chkmins = Config.getConfig("checkpoint.mins", 5);

                            if (dt > (chkmins * 60 / 2)) {
                                break;
                            }
                        }
                        pitCheckPoint = cursorLsn;
                        recoverToCheckpoint(cursorLogRecord);
                        scan = false;
                    }
                    if (!setCp) {
                        txnManager.setLastCkp(cursorLsn);
                        setCp = true;
                    }
                    break;
                default:
                    if (scan == false) {
                        //adding TxnRegopLogRecord to redostack,and do its redo function for release txn resource of btree
                        if (cursorLogRecord.getType() == LogRecord.LOG_TXN_REGOP) {
                            Integer txnid = new Integer(cursorLogRecord.getTxnId());
                            redoTable.put(txnid, txnid);
                        }

                        boolean doUNDO = false;
                        if (!redoTable.containsKey(new Integer(cursorLogRecord.getTxnId()))) {
                            doUNDO = true;
                        }

                        if (cursorLogRecord.getType() == LogRecord.LOG_DELETE_FILES) {
                            if (!redoTable.containsKey(new Integer(cursorLogRecord.getTxnId()))) {
                                Integer txnid = new Integer(cursorLogRecord.getTxnId());
                                redoTable.put(txnid, txnid);
                            }
                            doUNDO = false;
                        }

                        if (doUNDO) {
                            try {
                                cursorLogRecord.recover(LogRecord.UNDO);
                            } catch (ChaiDBException ie111) {
                                logger.error(ie111.getMessage());
                                continue;
                            }

                        } else { //push into redo stack
                            redoStack.push(cursorLogRecord);
                            redo_length++;
                            if (redoStack.size() == STACK_MAXSIZE) {
                                logger.info("Stack change. " + redoStack.size());
                                saveStack(cursorLsn);
                                logger.info(", New=" + redoStack.size() + " Stack" + (++stacks));
                            }
                        }
                    }
            }
            cursorLsn = new Lsn(cursorLsn.getFileId(), cursorLogRecord.getHeader().getPrevOffset());
        }///End for
        if (currentProcess < 5) {
            for (int i = currentProcess + 1; i <= 5; i++) {
                System.out.print("\r" + i + "0% completed.");
            }
        }
        redo_average = redo_length / 5;
        /* commented by marriane 2002-1-9 couldn't close btree because it need
           to do redo and release resource later.*/
        /*    try{
                releaseBtrees();
            }catch(ChaiDBException e){
                throw e;
            }
         */
        return true;
    }

    private void recoverToCheckpoint(LogRecord cursorLogRecord) throws ChaiDBException {
        DateFormat df = DateFormat.getDateTimeInstance();
        Date date = new Date(((TxnCkpLogRecord) cursorLogRecord).getTimeStamp());

        System.err.println("Found a checkpoint at: " + df.format(date));
        int offset = cursorLsn.getOffset() + cursorLogRecord.getHeader().getLength();
        int fileId = cursorLsn.getFileId();
        if (offset >= LogManagerImpl.LOG_FILE_MAX_SIZE) {
            fileId++;
            offset = 0;
        }
        LogManager logManager = Db.getLogManager();
        try {
            // modify chaidb.state
            logManager.closeLogFile();
            // truncate log file
            DefaultLogFile.getInstance().appendLastLsnToEnd(fileId, offset, cursorLsn);
        } catch (ChaiDBException e) {
            logger.error(e);
        }
        logManager.setCheckpointValueFromDisk();
        logManager.setCurLsn(new Lsn(fileId, offset), cursorLsn.getOffset());
        logManager.setLastLsnInFlush(cursorLsn);
        logManager.setLastCheckpointLsn(cursorLsn);
        txnManager.setLastCkp(cursorLsn);
        try {
            DBState.getInstance().setLatestLogFileId((short) fileId);
        } catch (Exception e) {
            logger.error(e);
        }
    }


    /**
     * set the ending point of undo, i.e. the starting point of redo.
     * added by haman lee in 2002-4-4
     */
    public void setSmallestLsn(Lsn lsn) {
        smallestLsn = lsn;
    }

}
TOP

Related Classes of org.chaidb.db.transaction.recover.CatastrophicTxnRecoverImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.