Package org.chaidb.db.transaction.recover

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

/*
* 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.
*
*/

/* Generated by Together */

package org.chaidb.db.transaction.recover;

import org.apache.log4j.Logger;
import org.chaidb.db.Db;
import org.chaidb.db.DbEnvironment;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.exception.ErrorCode;
import org.chaidb.db.helper.Config;
import org.chaidb.db.helper.FileUtil;
import org.chaidb.db.index.btree.bufmgr.PageBufferManager;
import org.chaidb.db.log.LogRecord;
import org.chaidb.db.log.Lsn;
import org.chaidb.db.transaction.TransactionManager;

import java.io.*;
import java.util.HashMap;
import java.util.Stack;


public abstract class TransactionRecoverImpl implements TransactionRecover {
    private static PageBufferManager bpm = PageBufferManager.getInstance();
    protected static final String RECOVERY_TMP = DbEnvironment.DB_TEMP_PATH + File.separator + RECOVERY_TEMP_DIR;

    protected TransactionManager txnManager;
    protected HashMap redoTable;
    protected Stack redoStack, lsnStack;
    protected int stacks;

    /**
     * server log
     */
    private static final Logger logger = Logger.getLogger(TransactionRecoverImpl.class);

    /**
     * the max size of stack here, such as redoStack and lsnStack.
     */
    protected static final int STACK_MAXSIZE = 50000;

    /**
     * The flag to indicate on which stage is stay  of the recovery.
     */
    protected int status = INVALID_STAGE;

    /**
     * The length of log records to redo.
     */
    protected int redo_length = 0;

    /**
     * The length of log records divide five.
     */
    protected int redo_average = 0;


    /**
     * Current indicator which log record is doing in redo stage.
     */
    protected int redo_current = 0;

    //private static TransactionRecover txnRecover = null;

    public TransactionRecoverImpl(TransactionManager txnManager) {
        this.txnManager = txnManager;
        //this.txnManager.setRecover(this);
        redoTable = new HashMap();
        redoStack = new Stack();
        stacks = 0;
    }


    /**
     * Do recover.
     * recover flow: undo->release all btree resource touched by undo->
     * redo(release all resource touched by current txn)->close all btrees
     * ->insert a DB_FORCE checkpoint
     */
    public boolean doRecover() throws ChaiDBException {

        // Sets flags to recover, preventing someone from beginTxn during recover routine.
        Db.getTxnManager().setFlags(TransactionManager.TXN_IN_RECOVERY);
        try {
            long start = System.currentTimeMillis();

            File dir = new File(RECOVERY_TMP);
            if (dir.exists() && dir.isDirectory()) {
                FileUtil.removeFileOrDirectory(dir);
            }

            ////////////////////////////// UNDO OPERATION /////////////////////////////////
            try {
                if (!undo()) return false;
            } catch (Exception e) {
                this.status = INVALID_STAGE;
                logger.error(e);
                releaseBtrees();//close all btrees, release all btree resource of all abort txn
                throw new ChaiDBException(ErrorCode.RECOVER_ERROR_BASE, e.toString());
            } finally {
                bpm.releaseAllTxnResources();
            }

            ///////////////////////// REDO OPERATION //////////////////////////////////////////
            try {
                redo();
            } catch (Exception e) {
                this.status = INVALID_STAGE;
                logger.error(e);
                throw new ChaiDBException(ErrorCode.RECOVER_ERROR_BASE, e.toString());
            } finally {
                releaseBtrees();//close all btrees
            }

            this.status = INVALID_STAGE;
            txnManager.doCheckpoint(true);

            logger.info("Total time is " + (System.currentTimeMillis() - start) + "ms");

            //Clear up routine.
            redoTable.clear();
            redoStack.clear();
        } catch (ChaiDBException ie) {
            throw ie;
        } catch (Exception e) {
            logger.error(e);
            throw new ChaiDBException(ErrorCode.RECOVER_ERROR_BASE, e.toString());
        } finally {
            // Remove TXN_IN_RECOVERY flag from txn manager.
            txnManager.clearFlags(TransactionManager.TXN_IN_RECOVERY);
        }
        return true;
    }

    /*
     * Undo operation.
     * Implements by subclasses.
     */
    protected abstract boolean undo() throws ChaiDBException;


    /*
     * Redo operation.
     * @exception ChaiDBException Exception while doing redo operation.
     *
     */
    private void redo() throws ChaiDBException {
        LogRecord cursorLogRecord;
        boolean cont = true;
        int currentProcess = 0;
        int percent;
        while (cont) {
            long start1 = System.currentTimeMillis();

            while (redoStack.size() != 0) {
                cursorLogRecord = (LogRecord) redoStack.pop();
                if (this instanceof CatastrophicTxnRecoverImpl) {
                    redo_current++;
                    percent = redo_current / redo_average;
                    if (percent != currentProcess) {
                        currentProcess++;
                        if (currentProcess <= 5) System.out.print("\r" + (currentProcess + 5) + "0% completed.");
                    }
                }
                try {
                    cursorLogRecord.recover(LogRecord.REDO);
                } catch (ChaiDBException e) {
                    logger.error(e.toString());
                    continue;
                }
            }
            if (cont = getNextStack()) {
                logger.info("Change Stack, remains " + (--stacks) + " cost " + (System.currentTimeMillis() - start1) + "ms");
            }

        }
        if (this instanceof CatastrophicTxnRecoverImpl) {
            if (redo_length == 0) {
                for (int i = 6; i <= 10; i++) {
                    System.out.print("\r" + i + "0% completed.");
                }
            }
            System.out.println();
        }
    }

    protected String colon2sub(String olds) {
        return olds.replace(':', '-');
    }

    protected void saveStack(Lsn lsn) {
        ObjectOutputStream out = null;
        try {
            File dir = new File(RECOVERY_TMP);
            if (!dir.exists() || !dir.isDirectory()) dir.mkdirs();
            out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(RECOVERY_TMP + File.separator + "redo_" + colon2sub(lsn.toString()))));
            out.writeObject(redoStack);
            out.flush();
            out.close();
        } catch (IOException e) {
            //delete all file in temp dir
            File dir = new File(RECOVERY_TMP);
            File[] fileList = dir.listFiles();
            for (int i = 0; i < fileList.length; i++) {
                File tempFile = fileList[i];
                tempFile.delete();
            }
            logger.fatal(e);
            if (out != null) {
                try {
                    out.close();
                } catch (IOException ee) {
                    logger.error(ee);
                }
            }
            logger.fatal("Failed in saveStack of recovery process: lsn = " + lsn.toString() + ".  System will in inconsistant state");
            logger.fatal("recover failed because disk is full ");
            System.exit(-1);

        }
        redoStack = new Stack();
    }

    protected boolean getNextStack() {
        File dir = new File(RECOVERY_TMP);
        String[] fname;
        String tmp0, tmp1, tmp2;
        Lsn lsn = new Lsn();
        Lsn minLsn = new Lsn(Short.MAX_VALUE, Integer.MAX_VALUE);
        if (dir.exists() && dir.isDirectory()) {
            fname = dir.list();
            for (int i = 0; i < fname.length; i++)
                if (fname[i].startsWith("redo_")) {
                    tmp0 = fname[i].substring(5);
                    int index = tmp0.indexOf("-");
                    if (index > -1) {
                        tmp1 = tmp0.substring(0, index);
                        tmp2 = tmp0.substring(index + 1);
                        lsn.setFileId(Integer.parseInt(tmp1));
                        lsn.setOffset(Integer.parseInt(tmp2));
                        if (lsn.compare(minLsn) == -1) {
                            minLsn.setFileId(lsn.getFileId());
                            minLsn.setOffset(lsn.getOffset());
                        }
                    }
                }//end for
            if (fname.length == 0) return false;
            File f0;
            ObjectInputStream in = null;
            try {
                f0 = new File(RECOVERY_TMP + File.separator + "redo_" + colon2sub(minLsn.toString()));
                in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(f0)));
                redoStack = (Stack) in.readObject();
                in.close();
                return f0.delete();
            } catch (Exception e) {
                logger.error(e);
                if (in != null) try {
                    in.close();
                } catch (IOException ee) {
                    logger.error(ee);
                }
            }
        }
        return false;
    }


    /*
     * Releases the opened btrees.
     */
    private void releaseBtrees() {

        /* close all btrees */
        bpm.closeAllBTrees();
    }

}
TOP

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

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.