提交 48ed8c60 authored 作者: Thomas Mueller's avatar Thomas Mueller

New experimental page store.

上级 c9b5b84e
......@@ -12,7 +12,6 @@ import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.store.DataPage;
import org.h2.store.DataPage;
import org.h2.store.PageStore;
import org.h2.util.IntArray;
......@@ -145,7 +144,7 @@ class PageDataLeaf extends PageData {
array.toArray(overflowPageIds);
firstOverflowPageId = overflowPageIds[0];
}
index.getPageStore().updateRecord(this);
index.getPageStore().updateRecord(this, data);
return 0;
}
......@@ -266,7 +265,7 @@ class PageDataLeaf extends PageData {
return true;
}
removeRow(i);
index.getPageStore().updateRecord(this);
index.getPageStore().updateRecord(this, data);
return false;
}
......
......@@ -12,7 +12,6 @@ import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.store.DataPage;
import org.h2.store.DataPage;
/**
* A leaf page that contains data of one or multiple rows.
......@@ -84,15 +83,15 @@ class PageDataNode extends PageData {
}
int pivot = page.getKey(splitPoint - 1);
PageData page2 = page.split(splitPoint);
index.getPageStore().updateRecord(page);
index.getPageStore().updateRecord(page2);
index.getPageStore().updateRecord(page, page.data);
index.getPageStore().updateRecord(page2, page2.data);
addChild(x, page2.getPageId(), pivot);
int maxEntries = (index.getPageStore().getPageSize() - 15) / 8;
if (entryCount >= maxEntries) {
int todoSplitAtLastInsertionPoint;
return entryCount / 2;
}
index.getPageStore().updateRecord(this);
index.getPageStore().updateRecord(this, data);
}
updateRowCount(1);
return 0;
......@@ -104,7 +103,7 @@ class PageDataNode extends PageData {
}
if (rowCountStored != UNKNOWN_ROWCOUNT) {
rowCountStored = UNKNOWN_ROWCOUNT;
index.getPageStore().updateRecord(this);
index.getPageStore().updateRecord(this, data);
}
}
......@@ -134,7 +133,7 @@ class PageDataNode extends PageData {
int child = childPageIds[i];
PageData p = index.getPage(child);
p.setParentPageId(getPos());
index.getPageStore().updateRecord(p);
index.getPageStore().updateRecord(p, p.data);
}
}
......@@ -232,7 +231,7 @@ class PageDataNode extends PageData {
return true;
}
removeRow(at);
index.getPageStore().updateRecord(this);
index.getPageStore().updateRecord(this, data);
return false;
}
......@@ -258,7 +257,7 @@ class PageDataNode extends PageData {
this.rowCount = rowCount;
if (rowCountStored != rowCount) {
rowCountStored = rowCount;
index.getPageStore().updateRecord(this);
index.getPageStore().updateRecord(this, data);
}
}
......
......@@ -55,11 +55,11 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
return;
}
this.store = database.getPageStorage();
if (headPos == Index.EMPTY_HEAD || headPos >= store.getPageCount()) {
// new table
if (headPos == Index.EMPTY_HEAD || store.isNew()) {
// new table, or the system table for a new database
headPos = store.allocatePage();
PageDataLeaf root = new PageDataLeaf(this, headPos, Page.ROOT, store.createDataPage());
store.updateRecord(root);
store.updateRecord(root, root.data);
} else {
lastKey = getPage(headPos).getLastKey();
rowCount = getPage(headPos).getRowCount();
......@@ -94,9 +94,9 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
page2.setParentPageId(headPos);
PageDataNode newRoot = new PageDataNode(this, rootPageId, Page.ROOT, store.createDataPage());
newRoot.init(page1, pivot, page2);
store.updateRecord(page1);
store.updateRecord(page2);
store.updateRecord(newRoot);
store.updateRecord(page1, page1.data);
store.updateRecord(page2, page2.data);
store.updateRecord(newRoot, null);
root = newRoot;
}
rowCount++;
......@@ -185,9 +185,10 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
public void truncate(Session session) throws SQLException {
trace("truncate");
store.removeRecord(headPos);
int todoLogOldData;
int freePages;
PageDataLeaf root = new PageDataLeaf(this, headPos, Page.ROOT, store.createDataPage());
store.updateRecord(root);
store.updateRecord(root, null);
rowCount = 0;
lastKey = 0;
}
......
......@@ -24,13 +24,13 @@ import org.h2.util.IntArray;
public class PageFreeList extends Record {
private final PageStore store;
private final DataPage page;
private final DataPage data;
private final IntArray array = new IntArray();
private int nextPage;
PageFreeList(PageStore store, int pageId, int nextPage) {
setPos(pageId);
this.page = store.createDataPage();
this.data = store.createDataPage();
this.store = store;
this.nextPage = nextPage;
}
......@@ -41,13 +41,14 @@ public class PageFreeList extends Record {
* @return the page
*/
int allocate() throws SQLException {
store.updateRecord(this, data);
int size = array.size();
if (size > 0) {
int x = array.get(size - 1);
array.remove(size - 1);
return x;
}
store.updateRecord(this);
store.removeRecord(getPos());
// no more free pages in this list:
// set the next page (may be 0, meaning no free pages)
store.setFreeListRootPage(nextPage, true, 0);
......@@ -63,9 +64,9 @@ public class PageFreeList extends Record {
* Read the page from the disk.
*/
void read() throws SQLException {
store.readPage(getPos(), page);
int p = page.readInt();
int t = page.readByte();
store.readPage(getPos(), data);
int p = data.readInt();
int t = data.readByte();
boolean last = (t & Page.FLAG_LAST) != 0;
t &= ~Page.FLAG_LAST;
if (t != Page.TYPE_FREE_LIST || p != 0) {
......@@ -77,13 +78,13 @@ public class PageFreeList extends Record {
int size;
if (last) {
nextPage = 0;
size = page.readInt();
size = data.readInt();
} else {
nextPage = page.readInt();
nextPage = data.readInt();
size = getMaxSize();
}
for (int i = 0; i < size; i++) {
array.add(page.readInt());
array.add(data.readInt());
}
}
......@@ -93,7 +94,7 @@ public class PageFreeList extends Record {
* @param pageId the page id to add
*/
void free(int pageId) throws SQLException {
store.updateRecord(this);
store.updateRecord(this, data);
if (array.size() < getMaxSize()) {
array.add(pageId);
} else {
......@@ -110,20 +111,20 @@ public class PageFreeList extends Record {
}
public void write(DataPage buff) throws SQLException {
page.reset();
page.writeInt(0);
data.reset();
data.writeInt(0);
int type = Page.TYPE_FREE_LIST;
if (nextPage == 0) {
type |= Page.FLAG_LAST;
}
page.writeByte((byte) type);
data.writeByte((byte) type);
if (nextPage != 0) {
page.writeInt(nextPage);
data.writeInt(nextPage);
} else {
page.writeInt(array.size());
data.writeInt(array.size());
}
for (int i = 0; i < array.size(); i++) {
page.writeInt(array.get(i));
data.writeInt(array.get(i));
}
}
......
......@@ -6,93 +6,71 @@
*/
package org.h2.store;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import org.h2.index.Page;
import org.h2.message.Message;
import org.h2.util.BitField;
/**
* Transaction log mechanism.
* The log is split in pages, the format is:
* <ul><li>0-3: parent page id
* </li><li>4-4: page type (LOG)
* </li><li>5-8: the next page (0 for end)
* </li><li>9-: data
* </li></ul>
* The data format is:
* <ul><li>0-0: type (0: end, 1: undo)
* <ul><li>0-0: type (0: undo)
* </li><li>1-4: page id
* </li><li>5-: data
* </li></ul>
*/
public class PageLog {
private static final int UNDO = 0;
private PageStore store;
private BitField undo = new BitField();
private int bufferPos;
private DataOutputStream out;
private int firstPage;
private int nextPage;
private DataPage data;
private DataPage output;
PageLog(PageStore store, int firstPage) {
this.store = store;
this.firstPage = firstPage;
data = store.createDataPage();
output = store.createDataPage();
}
// void open() throws SQLException {
// if (firstPage == 0) {
// return;
// }
// undo();
// prepareOutput();
// }
private void prepareOutput() throws SQLException {
output.reset();
output.writeInt(0);
output.writeByte((byte) Page.TYPE_LOG);
output.writeInt(store.allocatePage());
void openForWriting() {
out = new DataOutputStream(new PageOutputStream(store, 0, firstPage, Page.TYPE_LOG));
}
private void undo() throws SQLException {
int next = firstPage;
while (next != 0) {
data = store.readPage(firstPage);
data.setPos(4);
public void recover() throws SQLException {
DataInputStream in = new DataInputStream(new PageInputStream(store, 0, firstPage, Page.TYPE_LOG));
DataPage data = store.createDataPage();
try {
while (true) {
int x = in.read();
if (x < 0) {
break;
}
if (x == UNDO) {
int pageId = in.readInt();
in.read(data.getBytes(), 0, store.getPageSize());
store.writePage(pageId, data);
}
}
} catch (IOException e) {
throw Message.convertIOException(e, "recovering");
}
}
// void addUndo(int pageId) throws SQLException {
// if (undo.get(pageId)) {
// return;
// }
// undo.set(pageId);
// data.reset();
// data.writeByte((byte) 1);
// data.writeInt(pageId);
// DataPage p = store.readPage(pageId);
// data.write(p.getBytes(), 0, store.getPageSize());
// write(data.getBytes(), 0, data.length());
// }
private void write(byte[] data, int offset, int length) {
if (bufferPos + length > store.getPageSize()) {
while (length > 0) {
int len = Math.min(length, store.getPageSize() - bufferPos);
write(data, offset, len);
offset += len;
length -= len;
public void addUndo(int pageId, DataPage page) throws SQLException {
try {
if (undo.get(pageId)) {
return;
}
return;
out.write(UNDO);
out.writeInt(pageId);
out.write(page.getBytes(), 0, store.getPageSize());
undo.set(pageId);
} catch (IOException e) {
throw Message.convertIOException(e, "recovering");
}
System.arraycopy(data, offset, output.getBytes(), bufferPos, length);
bufferPos += length;
// if (bufferPos != BUFFER_SIZE) {
// return;
// }
}
}
......@@ -32,6 +32,7 @@ import org.h2.util.ObjectArray;
* </li><li>54-57: page number of the system table root
* </li><li>58-61: page number of the first free list page
* </li><li>62-65: number of free pages
* </li><li>66-69: log head page number
* </li></ul>
*/
public class PageStore implements CacheWriter {
......@@ -56,11 +57,19 @@ public class PageStore implements CacheWriter {
private int systemRootPageId;
private int freeListRootPageId;
private int freePageCount;
private int logRootPageId;
private PageLog log;
/**
* Number of pages (including free pages).
*/
private int pageCount;
/**
* True if this
*/
private boolean isNew;
private int writeCount;
private long fileLength;
......@@ -97,10 +106,15 @@ public class PageStore implements CacheWriter {
} else {
setPageSize(PAGE_SIZE_DEFAULT);
file = database.openFile(fileName, accessMode, false);
logRootPageId = allocatePage();
writeHeader();
isNew = true;
}
log = new PageLog(this, logRootPageId);
fileLength = file.length();
pageCount = (int) (fileLength / pageSize);
log.recover();
log.openForWriting();
} catch (SQLException e) {
close();
throw e;
......@@ -150,6 +164,16 @@ public class PageStore implements CacheWriter {
systemRootPageId = fileHeader.readInt();
freeListRootPageId = fileHeader.readInt();
freePageCount = fileHeader.readInt();
logRootPageId = fileHeader.readInt();
}
/**
* Check if this page store was just created.
*
* @return true if it was
*/
public boolean isNew() {
return isNew;
}
/**
......@@ -187,6 +211,7 @@ public class PageStore implements CacheWriter {
fileHeader.writeInt(systemRootPageId);
fileHeader.writeInt(freeListRootPageId);
fileHeader.writeInt(freePageCount);
fileHeader.writeInt(logRootPageId);
file.seek(FileStore.HEADER_LENGTH);
file.write(fileHeader.getBytes(), 0, FILE_HEADER_SIZE - FileStore.HEADER_LENGTH);
byte[] filler = new byte[pageSize - FILE_HEADER_SIZE];
......@@ -197,7 +222,7 @@ public class PageStore implements CacheWriter {
* Close the file.
*/
public void close() throws SQLException {
int todo;
int todoTruncateLog;
try {
flush();
if (file != null) {
......@@ -230,12 +255,14 @@ public class PageStore implements CacheWriter {
*
* @param record the record
*/
public void updateRecord(Record record) throws SQLException {
public void updateRecord(Record record, DataPage old) throws SQLException {
synchronized (database) {
record.setChanged(true);
int pos = record.getPos();
cache.update(pos, record);
int todoLogChanges;
if (old != null) {
log.addUndo(record.getPos(), old);
}
}
}
......@@ -382,7 +409,7 @@ public class PageStore implements CacheWriter {
this.freeListRootPageId = pageId;
if (!existing) {
PageFreeList free = new PageFreeList(this, pageId, next);
updateRecord(free);
updateRecord(free, null);
}
}
......
......@@ -56,7 +56,6 @@ public class TestPageStore extends TestBase {
store.setPageSize(1024);
store.open();
IntArray list = new IntArray();
int test;
int size = 270;
for (int i = 0; i < size; i++) {
int id = store.allocatePage();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论