提交 b3bd3a5b authored 作者: Thomas Mueller's avatar Thomas Mueller

Page store: adding data to new database is now faster.

上级 7a0eb586
......@@ -9,6 +9,7 @@ package org.h2.store;
import java.io.EOFException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import org.h2.compress.CompressLZF;
import org.h2.constant.ErrorCode;
......@@ -26,6 +27,7 @@ import org.h2.util.IntIntHashMap;
import org.h2.util.New;
import org.h2.util.ObjectArray;
import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* Transaction log mechanism. The stream contains a list of records. The data
......@@ -45,8 +47,9 @@ public class PageLog {
public static final int NOOP = 0;
/**
* An undo log entry.
* Format: page id: varInt, page.
* An undo log entry. Format: page id: varInt, size, page. Size 0 means
* uncompressed, size 1 means empty page, otherwise the size is the number
* of compressed bytes.
*/
public static final int UNDO = 1;
......@@ -255,6 +258,9 @@ public class PageLog {
int size = in.readVarInt();
if (size == 0) {
in.readFully(data.getBytes(), 0, store.getPageSize());
} else if (size == 1) {
// empty
Arrays.fill(data.getBytes(), 0, store.getPageSize(), (byte) 0);
} else {
in.readFully(compressBuffer, 0, size);
compress.expand(compressBuffer, 0, size, data.getBytes(), 0, store.getPageSize());
......@@ -423,6 +429,16 @@ public class PageLog {
return row;
}
/**
* Check if the undo entry was already written for the given page.
*
* @param pageId the page
* @return true if it was written
*/
boolean getUndo(int pageId) {
return undo.get(pageId);
}
/**
* Add an undo entry to the log. The page data is only written once until
* the next checkpoint.
......@@ -446,22 +462,26 @@ public class PageLog {
Data buffer = getBuffer();
buffer.writeByte((byte) UNDO);
buffer.writeVarInt(pageId);
int pageSize = store.getPageSize();
if (COMPRESS_UNDO) {
int size = compress.compress(page.getBytes(), pageSize, compressBuffer, 0);
if (size < pageSize) {
buffer.writeVarInt(size);
buffer.checkCapacity(size);
buffer.write(compressBuffer, 0, size);
if (page.getBytes()[0] == 0) {
buffer.writeVarInt(1);
} else {
int pageSize = store.getPageSize();
if (COMPRESS_UNDO) {
int size = compress.compress(page.getBytes(), pageSize, compressBuffer, 0);
if (size < pageSize) {
buffer.writeVarInt(size);
buffer.checkCapacity(size);
buffer.write(compressBuffer, 0, size);
} else {
buffer.writeVarInt(0);
buffer.checkCapacity(pageSize);
buffer.write(page.getBytes(), 0, pageSize);
}
} else {
buffer.writeVarInt(0);
buffer.checkCapacity(pageSize);
buffer.write(page.getBytes(), 0, pageSize);
}
} else {
buffer.writeVarInt(0);
buffer.checkCapacity(pageSize);
buffer.write(page.getBytes(), 0, pageSize);
}
write(buffer);
} catch (IOException e) {
......@@ -579,8 +599,19 @@ public class PageLog {
int columns = row.getColumnCount();
data.writeVarInt(columns);
data.checkCapacity(row.getByteCount(data));
for (int i = 0; i < columns; i++) {
data.writeValue(row.getValue(i));
if (session.isRedoLogBinaryEnabled()) {
for (int i = 0; i < columns; i++) {
data.writeValue(row.getValue(i));
}
} else {
for (int i = 0; i < columns; i++) {
Value v = row.getValue(i);
if (v.getType() == Value.BYTES) {
data.writeValue(ValueNull.INSTANCE);
} else {
data.writeValue(v);
}
}
}
Data buffer = getBuffer();
buffer.writeByte((byte) (add ? ADD : REMOVE));
......
......@@ -137,8 +137,8 @@ public class PageStore implements CacheWriter {
private static final int INCREMENT_PAGES = 128;
private static final int READ_VERSION = 2;
private static final int WRITE_VERSION = 2;
private static final int READ_VERSION = 3;
private static final int WRITE_VERSION = 3;
private static final int META_TYPE_SCAN_INDEX = 0;
private static final int META_TYPE_BTREE_INDEX = 1;
......@@ -203,6 +203,8 @@ public class PageStore implements CacheWriter {
*/
private int changeCount = 1;
private Data emptyPage;
/**
* Create a new page store object.
*
......@@ -632,6 +634,7 @@ public class PageStore implements CacheWriter {
throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, fileName);
}
pageSize = size;
emptyPage = createData();
pageSizeShift = shift;
}
......@@ -665,7 +668,7 @@ public class PageStore implements CacheWriter {
private void writeVariableHeader() throws SQLException {
Data page = createData();
page.writeInt(0);
page.writeLong(writeCount);
page.writeLong(getWriteCountTotal());
page.writeInt(logKey);
page.writeInt(logFirstTrunkPage);
page.writeInt(logFirstDataPage);
......@@ -739,10 +742,12 @@ public class PageStore implements CacheWriter {
database.checkWritingAllowed();
if (!recoveryRunning) {
int pos = record.getPos();
if (old == null) {
old = readPage(pos);
if (!log.getUndo(pos)) {
if (old == null) {
old = readPage(pos);
}
log.addUndo(pos, old);
}
log.addUndo(pos, old);
}
}
}
......@@ -847,7 +852,11 @@ public class PageStore implements CacheWriter {
* @return the page id
*/
public int allocatePage() throws SQLException {
return allocatePage(null, 0);
int pos = allocatePage(null, 0);
if (!recoveryRunning) {
log.addUndo(pos, emptyPage);
}
return pos;
}
private int allocatePage(BitField exclude, int first) throws SQLException {
......
......@@ -1015,6 +1015,8 @@ public class Recover extends Tool implements DataHandler {
byte[] data = new byte[pageSize];
if (size == 0) {
in.readFully(data, 0, pageSize);
} else if (size == 1) {
// empty
} else {
byte[] compressBuffer = new byte[size];
in.readFully(compressBuffer, 0, size);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论