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

new experimental page store

上级 90db2694
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
* Initial Developer: H2 Group * Initial Developer: H2 Group
*/ */
package org.h2.index; package org.h2.index;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
...@@ -13,6 +12,8 @@ import org.h2.engine.Session; ...@@ -13,6 +12,8 @@ import org.h2.engine.Session;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.store.DataPageBinary; import org.h2.store.DataPageBinary;
import org.h2.store.PageStore;
import org.h2.util.IntArray;
/** /**
* A leaf page that contains data of one or multiple rows. * A leaf page that contains data of one or multiple rows.
...@@ -26,7 +27,8 @@ import org.h2.store.DataPageBinary; ...@@ -26,7 +27,8 @@ import org.h2.store.DataPageBinary;
* The format of an overflow page is: * The format of an overflow page is:
* <ul><li>0-3: parent page id (0 for root) * <ul><li>0-3: parent page id (0 for root)
* </li><li>4-4: page type * </li><li>4-4: page type
* </li><li>only if there is overflow: 5-8: next overflow page id * </li><li>if there is more data: 5-8: next overflow page id
* </li><li>otherwise: 5-6: remaining size
* </li><li>data * </li><li>data
* </li></ul> * </li></ul>
*/ */
...@@ -43,9 +45,14 @@ class PageDataLeaf extends PageData { ...@@ -43,9 +45,14 @@ class PageDataLeaf extends PageData {
Row[] rows; Row[] rows;
/** /**
* The page id of the first overflow page (0 for no overflow). * The page id of the first overflow page (0 if no overflow).
*/
int firstOverflowPageId;
/**
* The page ids of all overflow pages (null if no overflow).
*/ */
int overflowPageId; int[] overflowPageIds;
/** /**
* The start of the data area. * The start of the data area.
...@@ -54,6 +61,7 @@ class PageDataLeaf extends PageData { ...@@ -54,6 +61,7 @@ class PageDataLeaf extends PageData {
PageDataLeaf(PageScanIndex index, int pageId, int parentPageId, DataPageBinary data) { PageDataLeaf(PageScanIndex index, int pageId, int parentPageId, DataPageBinary data) {
super(index, pageId, parentPageId, data); super(index, pageId, parentPageId, data);
start = 7;
} }
void read() throws SQLException { void read() throws SQLException {
...@@ -64,7 +72,7 @@ class PageDataLeaf extends PageData { ...@@ -64,7 +72,7 @@ class PageDataLeaf extends PageData {
keys = new int[entryCount]; keys = new int[entryCount];
rows = new Row[entryCount]; rows = new Row[entryCount];
if (type == Page.TYPE_DATA_LEAF_WITH_OVERFLOW) { if (type == Page.TYPE_DATA_LEAF_WITH_OVERFLOW) {
overflowPageId = data.readInt(); firstOverflowPageId = data.readInt();
} }
for (int i = 0; i < entryCount; i++) { for (int i = 0; i < entryCount; i++) {
keys[i] = data.readInt(); keys[i] = data.readInt();
...@@ -81,15 +89,15 @@ class PageDataLeaf extends PageData { ...@@ -81,15 +89,15 @@ class PageDataLeaf extends PageData {
data.reset(); data.reset();
data.writeInt(parentPageId); data.writeInt(parentPageId);
int type; int type;
if (overflowPageId == 0) { if (firstOverflowPageId == 0) {
type = Page.TYPE_DATA_LEAF; type = Page.TYPE_DATA_LEAF;
} else { } else {
type = Page.TYPE_DATA_LEAF_WITH_OVERFLOW; type = Page.TYPE_DATA_LEAF_WITH_OVERFLOW;
} }
data.writeByte((byte) type); data.writeByte((byte) type);
data.writeShortInt(entryCount); data.writeShortInt(entryCount);
if (overflowPageId != 0) { if (firstOverflowPageId != 0) {
data.writeInt(overflowPageId); data.writeInt(firstOverflowPageId);
} }
for (int i = 0; i < entryCount; i++) { for (int i = 0; i < entryCount; i++) {
data.writeInt(keys[i]); data.writeInt(keys[i]);
...@@ -99,18 +107,39 @@ class PageDataLeaf extends PageData { ...@@ -99,18 +107,39 @@ class PageDataLeaf extends PageData {
data.setPos(offsets[i]); data.setPos(offsets[i]);
rows[i].write(data); rows[i].write(data);
} }
int pageSize = index.getPageStore().getPageSize(); PageStore store = index.getPageStore();
if (data.length() > pageSize) { int pageSize = store.getPageSize();
if (overflowPageId == 0) { store.writePage(pageId, data);
// don't need to write overflow if we just update the parent page id
if (data.length() > pageSize && overflowPageIds != null) {
if (firstOverflowPageId == 0) {
throw Message.getInternalError(); throw Message.getInternalError();
} }
int todoWriteOverflow; DataPageBinary overflow = store.createDataPage();
} else { int parent = pageId;
if (overflowPageId != 0) { int pos = pageSize;
throw Message.getInternalError(); int remaining = data.length() - pageSize;
for (int i = 0; i < overflowPageIds.length; i++) {
overflow.reset();
overflow.writeInt(parent);
int size;
if (remaining > pageSize - 7) {
overflow.writeByte((byte) Page.TYPE_DATA_OVERFLOW_WITH_MORE);
overflow.writeInt(overflowPageIds[i + 1]);
size = pageSize - overflow.length();
} else {
overflow.writeByte((byte) Page.TYPE_DATA_OVERFLOW_LAST);
size = remaining;
overflow.writeShortInt(remaining);
}
overflow.write(data.getBytes(), pos, size);
remaining -= size;
pos += size;
int id = overflowPageIds[i];
store.writePage(id, overflow);
parent = id;
} }
} }
index.getPageStore().writePage(pageId, data);
} }
/** /**
...@@ -121,7 +150,12 @@ class PageDataLeaf extends PageData { ...@@ -121,7 +150,12 @@ class PageDataLeaf extends PageData {
*/ */
int addRow(Row row) throws SQLException { int addRow(Row row) throws SQLException {
int rowLength = row.getByteCount(data); int rowLength = row.getByteCount(data);
int last = entryCount == 0 ? index.getPageStore().getPageSize() : offsets[entryCount - 1]; int pageSize = index.getPageStore().getPageSize();
int last = entryCount == 0 ? pageSize : offsets[entryCount - 1];
if (entryCount > 0 && last - rowLength < start + 6) {
int todoSplitAtLastInsertionPoint;
return (entryCount / 2) + 1;
}
int offset = last - rowLength; int offset = last - rowLength;
int[] newOffsets = new int[entryCount + 1]; int[] newOffsets = new int[entryCount + 1];
int[] newKeys = new int[entryCount + 1]; int[] newKeys = new int[entryCount + 1];
...@@ -149,13 +183,27 @@ class PageDataLeaf extends PageData { ...@@ -149,13 +183,27 @@ class PageDataLeaf extends PageData {
keys = newKeys; keys = newKeys;
rows = newRows; rows = newRows;
if (offset < start) { if (offset < start) {
if (entryCount > 0) { if (entryCount > 1) {
int todoSplitAtLastInsertionPoint; throw Message.getInternalError();
return entryCount / 2;
} }
offset = start + 6; // need to write the overflow page id
overflowPageId = index.getPageStore().allocatePage(); start += 4;
int todoWriteOverflow; int remaining = rowLength - (pageSize - start);
// fix offset
offset = start;
offsets[x] = offset;
IntArray array = new IntArray();
do {
int next = index.getPageStore().allocatePage();
array.add(next);
remaining -= pageSize - 7;
if (remaining > 0) {
remaining += 2;
}
} while (remaining > 0);
overflowPageIds = new int[array.size()];
array.toArray(overflowPageIds);
firstOverflowPageId = overflowPageIds[0];
} }
write(); write();
return 0; return 0;
...@@ -188,16 +236,40 @@ class PageDataLeaf extends PageData { ...@@ -188,16 +236,40 @@ class PageDataLeaf extends PageData {
/** /**
* Get the row at the given index. * Get the row at the given index.
* *
* @param index the index * @param at the index
* @return the row * @return the row
*/ */
Row getRowAt(int index) throws SQLException { Row getRowAt(int at) throws SQLException {
Row r = rows[index]; if (at >= rows.length) {
int test;
System.out.println("test");
}
Row r = rows[at];
if (r == null) { if (r == null) {
data.setPos(offsets[index]); if (firstOverflowPageId != 0) {
r = this.index.readRow(data); PageStore store = index.getPageStore();
r.setPos(keys[index]); int pageSize = store.getPageSize();
rows[index] = r; data.setPos(pageSize);
int next = firstOverflowPageId;
while (true) {
DataPageBinary page = store.readPage(next);
page.setPos(4);
int type = page.readByte();
if (type == Page.TYPE_DATA_OVERFLOW_LAST) {
int size = page.readShortInt();
data.write(page.getBytes(), 7, size);
break;
} else {
next = page.readInt();
int size = pageSize - 9;
data.write(page.getBytes(), 9, size);
}
}
}
data.setPos(offsets[at]);
r = index.readRow(data);
r.setPos(keys[at]);
rows[at] = r;
} }
return r; return r;
} }
...@@ -252,9 +324,6 @@ class PageDataLeaf extends PageData { ...@@ -252,9 +324,6 @@ class PageDataLeaf extends PageData {
Row getRow(Session session, int key) throws SQLException { Row getRow(Session session, int key) throws SQLException {
int index = find(key); int index = find(key);
if(index >= keys.length) {
System.out.println("stop");
}
return getRowAt(index); return getRowAt(index);
} }
......
...@@ -79,23 +79,25 @@ class PageDataNode extends PageData { ...@@ -79,23 +79,25 @@ class PageDataNode extends PageData {
} }
int addRow(Row row) throws SQLException { int addRow(Row row) throws SQLException {
int x = find(row.getPos()); while (true) {
PageData page = index.getPage(childPageIds[x]); int x = find(row.getPos());
int splitPoint = page.addRow(row); PageData page = index.getPage(childPageIds[x]);
if (splitPoint == 0) { int splitPoint = page.addRow(row);
return 0; if (splitPoint == 0) {
} break;
int pivot = page.getKey(splitPoint); }
PageData page2 = page.split(splitPoint); int pivot = page.getKey(splitPoint - 1);
page.write(); PageData page2 = page.split(splitPoint);
page2.write(); page.write();
addChild(x, page2.getPageId(), pivot); page2.write();
int maxEntries = (index.getPageStore().getPageSize() - 11) / 8; addChild(x, page2.getPageId(), pivot);
if (entryCount >= maxEntries) { int maxEntries = (index.getPageStore().getPageSize() - 11) / 8;
int todoSplitAtLastInsertionPoint; if (entryCount >= maxEntries) {
return entryCount / 2; int todoSplitAtLastInsertionPoint;
return entryCount / 2;
}
write();
} }
write();
return 0; return 0;
} }
...@@ -107,7 +109,6 @@ class PageDataNode extends PageData { ...@@ -107,7 +109,6 @@ class PageDataNode extends PageData {
PageData split(int splitPoint) throws SQLException { PageData split(int splitPoint) throws SQLException {
int newPageId = index.getPageStore().allocatePage(); int newPageId = index.getPageStore().allocatePage();
PageDataNode p2 = new PageDataNode(index, newPageId, parentPageId, index.getPageStore().createDataPage()); PageDataNode p2 = new PageDataNode(index, newPageId, parentPageId, index.getPageStore().createDataPage());
splitPoint++;
int firstChild = childPageIds[splitPoint]; int firstChild = childPageIds[splitPoint];
for (int i = splitPoint; i < entryCount;) { for (int i = splitPoint; i < entryCount;) {
p2.addChild(p2.entryCount, childPageIds[splitPoint + 1], keys[splitPoint]); p2.addChild(p2.entryCount, childPageIds[splitPoint + 1], keys[splitPoint]);
...@@ -175,7 +176,7 @@ class PageDataNode extends PageData { ...@@ -175,7 +176,7 @@ class PageDataNode extends PageData {
return null; return null;
} }
PageDataNode next = (PageDataNode) index.getPage(parentPageId); PageDataNode next = (PageDataNode) index.getPage(parentPageId);
return next.getNextPage(keys[entryCount - 1]); return next.getNextPage(key);
} }
PageData page = index.getPage(childPageIds[i]); PageData page = index.getPage(childPageIds[i]);
return page.getFirstLeaf(); return page.getFirstLeaf();
...@@ -202,7 +203,6 @@ class PageDataNode extends PageData { ...@@ -202,7 +203,6 @@ class PageDataNode extends PageData {
} }
boolean remove(int key) throws SQLException { boolean remove(int key) throws SQLException {
int todo;
int at = find(key); int at = find(key);
// merge is not implemented to allow concurrent usage of btrees // merge is not implemented to allow concurrent usage of btrees
// TODO maybe implement merge // TODO maybe implement merge
......
...@@ -30,14 +30,15 @@ public class PageScanIndex extends BaseIndex implements RowIndex { ...@@ -30,14 +30,15 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
private TableData tableData; private TableData tableData;
private int headPos; private int headPos;
// TODO cache the row count of all children (row count, group count)
// TODO remember last page with deleted keys (in the root page?), // TODO remember last page with deleted keys (in the root page?),
// and chain such pages // and chain such pages
// TODO order pages so that searching for a key // TODO order pages so that searching for a key
// doesn't seek backwards in the file // doesn't seek backwards in the file
// TODO use an undo log and maybe redo log (for performance)
// TODO file position, content checksums
private int nextKey; private int nextKey;
// TODO remember the row count (in the root page?)
public PageScanIndex(TableData table, int id, IndexColumn[] columns, IndexType indexType, int headPos) throws SQLException { public PageScanIndex(TableData table, int id, IndexColumn[] columns, IndexType indexType, int headPos) throws SQLException {
initBaseIndex(table, id, table.getName() + "_TABLE_SCAN", columns, indexType); initBaseIndex(table, id, table.getName() + "_TABLE_SCAN", columns, indexType);
if (database.isMultiVersion()) { if (database.isMultiVersion()) {
...@@ -64,10 +65,13 @@ public class PageScanIndex extends BaseIndex implements RowIndex { ...@@ -64,10 +65,13 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
public void add(Session session, Row row) throws SQLException { public void add(Session session, Row row) throws SQLException {
row.setPos((int) rowCount); row.setPos((int) rowCount);
PageData root = getPage(headPos); while (true) {
int splitPoint = root.addRow(row); PageData root = getPage(headPos);
if (splitPoint != 0) { int splitPoint = root.addRow(row);
int pivot = root.getKey(splitPoint); if (splitPoint == 0) {
break;
}
int pivot = root.getKey(splitPoint - 1);
PageData page1 = root; PageData page1 = root;
PageData page2 = root.split(splitPoint); PageData page2 = root.split(splitPoint);
int rootPageId = root.getPageId(); int rootPageId = root.getPageId();
...@@ -159,6 +163,7 @@ public class PageScanIndex extends BaseIndex implements RowIndex { ...@@ -159,6 +163,7 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
public void truncate(Session session) throws SQLException { public void truncate(Session session) throws SQLException {
int invalidateRowCount; int invalidateRowCount;
int freePages;
PageDataLeaf root = new PageDataLeaf(this, headPos, Page.ROOT, store.createDataPage()); PageDataLeaf root = new PageDataLeaf(this, headPos, Page.ROOT, store.createDataPage());
root.write(); root.write();
rowCount = 0; rowCount = 0;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论