⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 logfile.java

📁 非常棒的java数据库
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
 * (http://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.log;

import java.io.IOException;
import java.sql.SQLException;

import org.h2.api.DatabaseEventListener;
import org.h2.constant.ErrorCode;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.message.Trace;
import org.h2.store.DataPage;
import org.h2.store.DiskFile;
import org.h2.store.FileStore;
import org.h2.store.Record;
import org.h2.store.Storage;
import org.h2.util.FileUtils;
import org.h2.util.MathUtils;
import org.h2.util.ObjectArray;

/**
 * Each transaction log file contains a number of log records.
 *
 * Header format:
 * <pre>
 * int logId (<0 means ignore: rolled back already)
 * int firstUncommittedLogRecordId (-1 if none)
 * int firstUnwrittenLogRecordId (-1 if none)
 * </pre>
 *
 * Record format:
 * <pre>
 * int block size
 * byte 'D' (delete) / 'I' (insert) / 'C' (commit) / 
 *      'R' (rollback) / 'P' (prepare commit) / 'T' (truncate)
 * int session
 * [delete/insert only:]
 * int storage
 * int record.pos
 * int record.blockCount
 * [prepare commit only:]
 * string transaction
 * </pre>
 */
public class LogFile {

    private static final int BUFFER_SIZE = 8 * 1024;
    public static final int BLOCK_SIZE = 16;

    private LogSystem logSystem;
    private Database database;
    private int id;
    private String fileNamePrefix;
    private String fileName;
    private FileStore file;
    private int bufferPos;
    private byte[] buffer;
    private ObjectArray unwritten;
    private DataPage rowBuff;
    private int pos = LogSystem.LOG_WRITTEN;
    private int firstUncommittedPos = LogSystem.LOG_WRITTEN;
    private int firstUnwrittenPos = LogSystem.LOG_WRITTEN;

    LogFile(LogSystem log, int id, String fileNamePrefix) throws SQLException {
        this.logSystem = log;
        this.database = log.getDatabase();
        this.id = id;
        this.fileNamePrefix = fileNamePrefix;
        fileName = getFileName();
        file = log.getDatabase().openFile(fileName, log.getAccessMode(), false);
        rowBuff = log.getRowBuffer();
        buffer = new byte[BUFFER_SIZE];
        unwritten = new ObjectArray();
        try {
            readHeader();
            if (!log.getDatabase().getReadOnly()) {
                writeHeader();
            }
            pos = getBlock();
            firstUncommittedPos = pos;
        } catch (SQLException e) {
            close(false);
            throw e;
        }
    }

    static LogFile openIfLogFile(LogSystem log, String fileNamePrefix, String fileName) throws SQLException {
        if (!fileName.endsWith(Constants.SUFFIX_LOG_FILE)) {
            return null;
        }
        if (!FileUtils.fileStartsWith(fileName, fileNamePrefix + ".")) {
            return null;
        }
        String s = fileName.substring(fileNamePrefix.length() + 1, fileName.length()
                - Constants.SUFFIX_LOG_FILE.length());
        for (int i = 0; i < s.length(); i++) {
            if (!Character.isDigit(s.charAt(i))) {
                return null;
            }
        }
        int id = Integer.parseInt(s);
        if (!FileUtils.exists(fileName)) {
            // the file could have been deleted by now (by the DelayedFileDeleter)
            return null;
        }
        return new LogFile(log, id, fileNamePrefix);
    }

    public String getFileName() {
        return fileNamePrefix + "." + id + Constants.SUFFIX_LOG_FILE;
    }

    public int getId() {
        return id;
    }

    private int getBlock() throws SQLException {
        if (file == null) {
            throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF);
        }
        return (int) (file.getFilePointer() / BLOCK_SIZE);
    }

    private void writeBuffer(DataPage buff, Record rec) throws SQLException {
        if (file == null) {
            throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF);
        }
        int size = MathUtils.roundUp(buff.length() + buff.getFillerLength(), BLOCK_SIZE);
        int blockCount = size / BLOCK_SIZE;
        buff.fill(size);
        buff.setInt(0, blockCount);
        buff.updateChecksum();
        // IOLogger.getInstance().logWrite(this.fileName, 
        //     file.getFilePointer(), buff.length());
        if (rec != null) {
            unwritten.add(rec);
        }
        if (buff.length() + bufferPos > buffer.length) {
            // the buffer is full
            flush();
        }
        if (buff.length() >= buffer.length) {
            // special case really long write request: write it without buffering
            file.write(buff.getBytes(), 0, buff.length());
            pos = getBlock();
            return;
        }
        System.arraycopy(buff.getBytes(), 0, buffer, bufferPos, buff.length());
        bufferPos += buff.length();
        pos = getBlock() + (bufferPos / BLOCK_SIZE);
    }

    void commit(Session session) throws SQLException {
        DataPage buff = rowBuff;
        buff.reset();
        buff.writeInt(0);
        buff.writeByte((byte) 'C');
        buff.writeInt(session.getId());
        writeBuffer(buff, null);
        if (logSystem.getFlushOnEachCommit()) {
            flush();
        }
    }

    void prepareCommit(Session session, String transaction) throws SQLException {
        DataPage buff = rowBuff;
        buff.reset();
        buff.writeInt(0);
        buff.writeByte((byte) 'P');
        buff.writeInt(session.getId());
        buff.writeString(transaction);
        writeBuffer(buff, null);
        if (logSystem.getFlushOnEachCommit()) {
            flush();
        }
    }

    private DataPage readPage() throws SQLException {
        byte[] buff = new byte[BLOCK_SIZE];
        file.readFully(buff, 0, BLOCK_SIZE);
        DataPage s = DataPage.create(database, buff);
        int blocks = Math.abs(s.readInt());
        if (blocks > 1) {
            byte[] b2 = new byte[blocks * BLOCK_SIZE];
            System.arraycopy(buff, 0, b2, 0, BLOCK_SIZE);
            buff = b2;
            file.readFully(buff, BLOCK_SIZE, blocks * BLOCK_SIZE - BLOCK_SIZE);
            s = DataPage.create(database, buff);
            s.check(blocks * BLOCK_SIZE);
        } else {
            s.reset();
        }
        return s;
    }

    /**
     * Redo or undo one item in the log file.
     *
     * @param undo true if the operation should be undone
     * @param readOnly if the file is read only
     * @return true if there are potentially more operations
     */
    private boolean redoOrUndo(boolean undo, boolean readOnly) throws SQLException {
        int pos = getBlock();
        DataPage in = readPage();
        int blocks = in.readInt();
        if (blocks < 0) {
            return true;
        } else if (blocks == 0) {
            truncate(pos);
            return false;
        }
        char type = (char) in.readByte();
        int sessionId = in.readInt();
        if (type == 'P') {
            if (undo) {
                throw Message.getInternalError("can't undo prepare commit");
            }
            String transaction = in.readString();
            logSystem.setPreparedCommitForSession(this, sessionId, pos, transaction, blocks);
            return true;
        } else if (type == 'C') {
            if (undo) {
                throw Message.getInternalError("can't undo commit");
            }
            logSystem.setLastCommitForSession(sessionId, id, pos);
            return true;
        } else if (type == 'R') {
            if (undo) {
                throw Message.getInternalError("can't undo rollback");
            }
            return true;
        } else if (type == 'S') {
            if (undo) {
                throw Message.getInternalError("can't undo summary");
            }
        }
        if (readOnly && type != 'S') {
            return true;
        }
        if (undo) {
            if (logSystem.isSessionCommitted(sessionId, id, pos)) {
                logSystem.removeSession(sessionId);
                return true;
            }
        } else {
            if (type != 'S') {
                if (!readOnly) {
                    logSystem.addUndoLogRecord(this, pos, sessionId);
                }
            }
        }
        int storageId = in.readInt();
        Storage storage = logSystem.getStorageForRecovery(storageId);
        DataPage rec = null;
        int recordId = in.readInt();
        int blockCount = in.readInt();
        if (type != 'T') {
            rec = in.readDataPageNoSize();
        }
        switch(type) {
        case 'S': {
            int fileType = in.readByte();
            boolean diskFile;
            if (fileType == 'D') {
                diskFile = true;
            } else if (fileType == 'I') {
                diskFile = false;
            } else {
                // unknown type, maybe linear index file (future)
                break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -