?? logfile.java
字號(hào):
/*
* 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;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -