Package org.chaidb.db.transaction.recover

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

/*
* 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.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.exception.ErrorCode;
import org.chaidb.db.helper.FileUtil;
import org.chaidb.db.log.Lsn;

import java.io.*;
import java.util.LinkedList;


/**
* @author Kurt Sung
*/
public class TxnQueue {
    /**
     * The maximum log buffer is 2M, this is for supporting 100 concurrent
     * transactions in 256M heap size. This will be configurable in the feature.
     */
    private static final int MAX_LOG_BUFFER_SIZE = 2 * 1024 * 1024; //2M

    /**
     * The maximum temp file size is 1G, this is for supporting FAT partition.
     * This will be configurable in the feature.
     */
    private static final long MAX_FILE_SIZE = 1000 * 1024 * 1024; //1G

    /**
     * transaction id of this queue
     */
    private final Integer txnId;

    /**
     * in outMode, just support poll method
     */
    private boolean outMode;

    /**
     * Buffer
     */
    private LinkedList list = new LinkedList();
    private int bufferSize;
    private int size = 0;

    /**
     * Swap file
     */
    private DataOutputStream out;
    private DataInputStream in;
    private int wfileId;
    private int rfileId;
    private long length; //length of current file

    /**
     * Attributes
     */
    private final String path;
    private final String filename; //name of current file
    private final Lsn firstLsn;

    public TxnQueue(Integer txnId, Lsn firstLsn, String path) {
        this.txnId = txnId;
        this.firstLsn = new Lsn(firstLsn);
        this.path = path;
        filename = path + File.separator + "txn_" + Integer.toHexString(txnId.intValue());
    }

    public Integer getTxnId() {
        return txnId;
    }

    public Lsn getFirstLsn() {
        return firstLsn;
    }

    /**
     * Get the count of all log records in this queue
     *
     * @return the count of log records
     */
    public int getSize() {
        return size;
    }

    /**
     * Offer the data of a record to the queue
     *
     * @param data
     * @throws ChaiDBException
     */
    public void offer(byte[] data) throws ChaiDBException {
        if (outMode) {
            System.err.println("Offer in read mode");

            return;
        }

        bufferSize += data.length;
        list.add(data);
        size++;

        if (bufferSize > MAX_LOG_BUFFER_SIZE) {
            try {
                flush();
            } catch (IOException e) {
                System.err.println("offer error");
                throw new ChaiDBException(ErrorCode.RECOVER_ERROR_BASE, e);
            }
        }
    }

    /**
     * Poll the data of next log record from the queue
     *
     * @return
     * @throws ChaiDBException
     */
    public byte[] poll() throws ChaiDBException {
        if (!outMode) {
            if (out != null) {
                pack();
            }

            outMode = true;
        }

        if (list.size() == 0) {
            try {
                load();
            } catch (IOException e) {
                System.err.println("poll error");
                throw new ChaiDBException(ErrorCode.RECOVER_ERROR_BASE, e);
            }
        }

        if (list.size() != 0) {
            size--;

            return (byte[]) list.remove(0);
        }

        return null;
    }

    private void load() throws IOException {
        if (in == null) {
            if (out != null) {
                out.close();
                out = null;
            }

            final File file = new File(getFullName(rfileId));

            if (!file.exists()) {
                return;
            }

            length = file.length();
            in = new DataInputStream(new BufferedInputStream(new FileInputStream(getFullName(rfileId))));
        }

        bufferSize = 0;

        while ((bufferSize < MAX_LOG_BUFFER_SIZE) && (length > 0)) {
            short len = in.readShort();
            byte[] data = new byte[len];
            in.read(data);
            list.add(data);
            bufferSize += data.length;
            length -= (2 + len);

            if (length == 0) {
                in.close();
                new File(getFullName(rfileId)).delete();
                in = null;

                if (rfileId < wfileId) {
                    rfileId++;
                    in = new DataInputStream(new BufferedInputStream(new FileInputStream(getFullName(rfileId))));
                    length = new File(getFullName(rfileId)).length();
                }
            }
        }
    }

    private void flush() throws IOException {
        File dir = new File(path);

        if (out == null) {
            if (!dir.exists() || !dir.isDirectory()) {
                dir.mkdirs();
            }

            File f = new File(getFullName(wfileId));

            if (f.exists()) {
                FileUtil.removeFileOrDirectory(f);
            }

            out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(getFullName(wfileId))));
        }

        int size = list.size();

        for (int i = 0; i < size; i++) {
            byte[] data = (byte[]) list.removeFirst();
            out.writeShort(data.length);
            out.write(data);
            length += (2 + data.length);
        }

        out.flush();
        list.clear();
        bufferSize = 0;

        if (length > MAX_FILE_SIZE) {
            out.close();
            wfileId++;

            File f = new File(getFullName(wfileId));

            if (f.exists()) {
                FileUtil.removeFileOrDirectory(f);
            }

            out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(getFullName(wfileId))));
            length = 0;
        }
    }

    private void pack() throws ChaiDBException {
        try {
            flush();
            out.close();
        } catch (IOException e) {
            System.err.println("pack error");
            throw new ChaiDBException(ErrorCode.RECOVER_ERROR_BASE, e);
        }
    }

    public void abandon() {
        try {
            if (out != null) {
                out.close();
            }

            if (in != null) {
                in.close();
            }
        } catch (IOException e) {
            ;
        }

        list.clear();
        size = 0;
        bufferSize = 0;
        wfileId = 0;
        rfileId = 0;

        for (int i = 0; i < wfileId; i++) {
            new File(getFullName(i)).delete();
        }
    }

    private String getFullName(int id) {
        return filename + "." + id;
    }
}
TOP

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

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.