提交 7c23654a authored 作者: Thomas Mueller's avatar Thomas Mueller

New experimental page store.

上级 225e8ba1
......@@ -2345,7 +2345,9 @@ public class Database implements DataHandler {
*/
public void checkpoint() throws SQLException {
if (SysProperties.PAGE_STORE) {
pageStore.checkpoint();
if (persistent) {
pageStore.checkpoint();
}
}
getLog().checkpoint();
getTempFileDeleter().deleteUnused();
......
......@@ -145,6 +145,13 @@ abstract class PageBtree extends Record {
*/
abstract void find(PageBtreeCursor cursor, SearchRow first, boolean bigger) throws SQLException;
/**
* Find the last row.
*
* @param cursor the cursor
*/
abstract void last(PageBtreeCursor cursor) throws SQLException;
/**
* Get the row at this position.
*
......@@ -190,6 +197,13 @@ abstract class PageBtree extends Record {
*/
abstract PageBtreeLeaf getFirstLeaf() throws SQLException;
/**
* Get the first child leaf page of a page.
*
* @return the page
*/
abstract PageBtreeLeaf getLastLeaf() throws SQLException;
/**
* Change the parent page id.
*
......
......@@ -62,7 +62,6 @@ public class PageBtreeCursor implements Cursor {
}
if (i >= current.getEntryCount()) {
current.nextPage(this);
i = 0;
if (current == null) {
return false;
}
......@@ -77,9 +76,19 @@ public class PageBtreeCursor implements Cursor {
return true;
}
public boolean previous() {
public boolean previous() throws SQLException {
if (current == null) {
return false;
}
if (i <= 0) {
current.previousPage(this);
if (current == null) {
return false;
}
}
currentSearchRow = current.getRow(i);
currentRow = null;
i--;
int todo;
return true;
}
......
......@@ -21,6 +21,7 @@ import org.h2.table.IndexColumn;
import org.h2.table.TableData;
import org.h2.value.Value;
import org.h2.value.ValueLob;
import org.h2.value.ValueNull;
/**
* This is the most common type of index, a b tree index.
......@@ -152,7 +153,7 @@ public class PageBtreeIndex extends BaseIndex {
}
public boolean canGetFirstOrLast() {
return false;
return true;
}
public Cursor findNext(Session session, SearchRow first, SearchRow last) throws SQLException {
......@@ -174,7 +175,34 @@ public class PageBtreeIndex extends BaseIndex {
}
public Cursor findFirstOrLast(Session session, boolean first) throws SQLException {
throw Message.getUnsupportedException("PAGE");
if (first) {
// TODO optimization: this loops through NULL elements
Cursor cursor = find(session, null, false, null);
while (cursor.next()) {
SearchRow row = cursor.getSearchRow();
Value v = row.getValue(columnIds[0]);
if (v != ValueNull.INSTANCE) {
return cursor;
}
}
return cursor;
}
PageBtree root = getPage(headPos);
PageBtreeCursor cursor = new PageBtreeCursor(session, this, null);
root.last(cursor);
cursor.previous();
// TODO optimization: this loops through NULL elements
do {
SearchRow row = cursor.getSearchRow();
if (row == null) {
break;
}
Value v = row.getValue(columnIds[0]);
if (v != ValueNull.INSTANCE) {
return cursor;
}
} while (cursor.previous());
return cursor;
}
public double getCost(Session session, int[] masks) {
......@@ -278,8 +306,6 @@ public class PageBtreeIndex extends BaseIndex {
if (trace.isDebugEnabled()) {
trace.debug("close");
}
int todoWhyRequired;
// store = null;
int writeRowCount;
}
......
......@@ -65,7 +65,7 @@ class PageBtreeLeaf extends PageBtree {
int pageSize = index.getPageStore().getPageSize();
int last = entryCount == 0 ? pageSize : offsets[entryCount - 1];
if (last - rowLength < start + OFFSET_LENGTH) {
if (entryCount > 0) {
if (entryCount > 1) {
int todoSplitAtLastInsertionPoint;
return (entryCount / 2) + 1;
}
......@@ -142,6 +142,10 @@ class PageBtreeLeaf extends PageBtree {
return this;
}
PageBtreeLeaf getLastLeaf() {
return this;
}
boolean remove(SearchRow row) throws SQLException {
int at = find(row, false, false);
if (index.compareRows(row, getRow(at)) != 0) {
......@@ -213,6 +217,10 @@ class PageBtreeLeaf extends PageBtree {
cursor.setCurrent(this, i);
}
void last(PageBtreeCursor cursor) {
cursor.setCurrent(this, entryCount - 1);
}
void remapChildren() {
}
......@@ -230,6 +238,20 @@ class PageBtreeLeaf extends PageBtree {
next.nextPage(cursor, getPos());
}
/**
* Set the cursor to the last row of the previous page.
*
* @param cursor the cursor
*/
void previousPage(PageBtreeCursor cursor) throws SQLException {
if (parentPageId == Page.ROOT) {
cursor.setCurrent(null, 0);
return;
}
PageBtreeNode next = (PageBtreeNode) index.getPage(parentPageId);
next.previousPage(cursor, getPos());
}
public String toString() {
return "page[" + getPos() + "] btree leaf table:" + index.getId() + " entries:" + entryCount;
}
......
......@@ -61,7 +61,7 @@ class PageBtreeNode extends PageBtree {
}
private int addChildTry(SearchRow row) throws SQLException {
if (entryCount == 0) {
if (entryCount < 2) {
return 0;
}
int rowLength = index.getRowSize(data, row, onlyPosition);
......@@ -86,9 +86,7 @@ class PageBtreeNode extends PageBtree {
int pageSize = index.getPageStore().getPageSize();
int last = entryCount == 0 ? pageSize : offsets[entryCount - 1];
if (last - rowLength < start + CHILD_OFFSET_PAIR_LENGTH) {
if (entryCount > 0) {
throw Message.throwInternalError();
}
// TODO remap all children
onlyPosition = true;
rowLength = index.getRowSize(data, row, onlyPosition);
}
......@@ -132,7 +130,7 @@ class PageBtreeNode extends PageBtree {
SearchRow pivot = page.getRow(splitPoint - 1);
int splitPoint2 = addChildTry(pivot);
if (splitPoint2 != 0) {
return splitPoint;
return splitPoint2;
}
PageBtree page2 = page.split(splitPoint);
addChild(x, page2.getPageId(), pivot);
......@@ -158,6 +156,10 @@ class PageBtreeNode extends PageBtree {
PageBtree split(int splitPoint) throws SQLException {
int newPageId = index.getPageStore().allocatePage();
PageBtreeNode p2 = new PageBtreeNode(index, newPageId, parentPageId, index.getPageStore().createDataPage());
if (onlyPosition) {
// TODO optimize: maybe not required
p2.onlyPosition = true;
}
int firstChild = childPageIds[splitPoint];
for (int i = splitPoint; i < entryCount;) {
p2.addChild(p2.entryCount, childPageIds[splitPoint + 1], rows[splitPoint]);
......@@ -166,6 +168,9 @@ class PageBtreeNode extends PageBtree {
int lastChild = childPageIds[splitPoint - 1];
removeChild(splitPoint - 1);
childPageIds[splitPoint - 1] = lastChild;
if (p2.childPageIds == null) {
p2.childPageIds = new int[1];
}
p2.childPageIds[0] = firstChild;
p2.remapChildren();
return p2;
......@@ -209,11 +214,21 @@ class PageBtreeNode extends PageBtree {
page.find(cursor, first, bigger);
}
void last(PageBtreeCursor cursor) throws SQLException {
int child = childPageIds[entryCount];
index.getPage(child).last(cursor);
}
PageBtreeLeaf getFirstLeaf() throws SQLException {
int child = childPageIds[0];
return index.getPage(child).getFirstLeaf();
}
PageBtreeLeaf getLastLeaf() throws SQLException {
int child = childPageIds[entryCount - 1];
return index.getPage(child).getLastLeaf();
}
boolean remove(SearchRow row) throws SQLException {
int at = find(row, false, false);
// merge is not implemented to allow concurrent usage
......@@ -353,6 +368,36 @@ class PageBtreeNode extends PageBtree {
cursor.setCurrent(leaf, 0);
}
/**
* Set the cursor to the last row of the previous page.
*
* @param cursor the cursor
* @param row the current row
*/
void previousPage(PageBtreeCursor cursor, int pageId) throws SQLException {
int i;
// TODO maybe keep the index in the child page (transiently)
for (i = childPageIds.length - 1; i >= 0; i--) {
if (childPageIds[i] == pageId) {
i--;
break;
}
}
if (i < 0) {
if (parentPageId == Page.ROOT) {
cursor.setCurrent(null, 0);
return;
}
PageBtreeNode previous = (PageBtreeNode) index.getPage(parentPageId);
previous.previousPage(cursor, getPos());
return;
}
PageBtree page = index.getPage(childPageIds[i]);
PageBtreeLeaf leaf = page.getLastLeaf();
cursor.setCurrent(leaf, leaf.entryCount - 1);
}
public String toString() {
return "page[" + getPos() + "] btree node table:" + index.getId() + " entries:" + entryCount;
}
......
......@@ -196,9 +196,6 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
public void remove(Session session, Row row) throws SQLException {
if (trace.isDebugEnabled()) {
trace.debug("remove " + row.getPos());
if (table.getId() == 0) {
System.out.println("table 0 remove");
}
}
if (tableData.getContainsLargeObject()) {
for (int i = 0; i < row.getColumnCount(); i++) {
......
......@@ -87,15 +87,9 @@ public class LogSystem {
*/
public void setMaxLogSize(long maxSize) {
this.maxLogSize = maxSize;
}
/**
* Get the maximum log file size.
*
* @return the maximum size
*/
public long getMaxLogSize() {
return maxLogSize;
if (pageStore != null) {
pageStore.setMaxLogSize(maxSize);
}
}
/**
......
......@@ -286,6 +286,10 @@ public class Message {
*/
public static SQLException convertIOException(IOException e, String message) {
if (message == null) {
Throwable t = e.getCause();
if (t != null && t instanceof SQLException) {
return (SQLException) t;
}
return getSQLException(ErrorCode.IO_EXCEPTION_1, new String[] { e.toString() }, e);
}
return getSQLException(ErrorCode.IO_EXCEPTION_2, new String[] { e.toString(), message }, e);
......
......@@ -389,18 +389,8 @@ public class PageLog {
return;
}
int firstDataPageToKeep = logIdPageMap.get(firstUncommittedLog);
trace.debug("log.removeUntil " + firstDataPageToKeep);
while (true) {
// TODO keep trunk page in the cache
PageStreamTrunk t = new PageStreamTrunk(store, firstTrunkPage);
t.read();
if (t.contains(firstDataPageToKeep)) {
store.setLogFirstPage(t.getPos(), firstDataPageToKeep);
break;
}
firstTrunkPage = t.getNextTrunk();
t.free();
}
firstTrunkPage = pageOut.removeUntil(firstTrunkPage, firstDataPageToKeep);
store.setLogFirstPage(firstTrunkPage, firstDataPageToKeep);
while (firstLogId < firstUncommittedLog) {
if (firstLogId > 0) {
// there is no entry for log 0
......@@ -473,4 +463,8 @@ public class PageLog {
return state;
}
public long getSize() {
return pageOut.getSize();
}
}
......@@ -30,6 +30,7 @@ public class PageOutputStream extends OutputStream {
private byte[] buffer = new byte[1];
private boolean needFlush;
private boolean writing;
private int pages;
/**
* Create a new page output stream.
......@@ -97,11 +98,13 @@ public class PageOutputStream extends OutputStream {
}
trunkNext = reservedPages.get(len);
trunk = new PageStreamTrunk(store, parent, trunkPageId, trunkNext, pageIds);
pages++;
trunk.write(null);
reservedPages.removeRange(0, len + 1);
nextData = trunk.getNextDataPage();
}
data = new PageStreamData(store, nextData, trunk.getPos());
pages++;
data.initWrite();
}
......@@ -174,4 +177,29 @@ public class PageOutputStream extends OutputStream {
initNextData();
}
/**
* Remove all pages until the given data page.
*
* @param firstTrunkPage the first trunk page
* @param firstDataPageToKeep the first data page to keep
* @return the trunk page of the data page to keep
*/
int removeUntil(int firstTrunkPage, int firstDataPageToKeep) throws SQLException {
trace.debug("log.removeUntil " + firstDataPageToKeep);
while (true) {
// TODO keep trunk page in the cache
PageStreamTrunk t = new PageStreamTrunk(store, firstTrunkPage);
t.read();
if (t.contains(firstDataPageToKeep)) {
return t.getPos();
}
firstTrunkPage = t.getNextTrunk();
pages -= t.free();
}
}
long getSize() {
return pages * store.getPageSize();
}
}
......@@ -126,16 +126,21 @@ public class PageStreamTrunk extends Record {
/**
* Free this page and all data pages.
*
* @return the number of pages freed
*/
void free() throws SQLException {
int free() throws SQLException {
DataPage empty = store.createDataPage();
store.freePage(getPos(), false, null);
int freed = 1;
for (int i = 0; i < pageCount; i++) {
int page = pageIds[i];
store.freePage(page, false, null);
freed++;
store.writePage(page, empty);
}
store.writePage(getPos(), empty);
return freed;
}
/**
......
......@@ -290,10 +290,13 @@ java org.h2.test.TestAll timer
// 2009-05-18: 18 tests fail with page store (first loop)
// 2009-05-30: 15 tests fail with page store (first loop)
// 2009-06-19: 10 tests fail with page store (first loop)
// 2009-06-24: 3 tests fail with page store (first loop)
// System.setProperty("h2.pageStore", "true");
/*
Console: Start Browser: if ip number changed, try localhost
test case for running out of disk space (using a special file system)
auto-build: prepare release
......
......@@ -13,6 +13,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.engine.Database;
......@@ -289,7 +290,7 @@ public class TestPowerOff extends TestBase {
}
conn.close();
} catch (SQLException e) {
if (e.getSQLState().equals("90098")) {
if (e.getSQLState().equals("" + ErrorCode.SIMULATED_POWER_OFF)) {
// this is ok
} else {
throw e;
......
......@@ -9,6 +9,7 @@ package org.h2.test.unit;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.constant.SysProperties;
import org.h2.test.TestBase;
import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Recover;
......@@ -43,7 +44,12 @@ public class TestRecovery extends TestBase {
conn = getConnection("recovery", "diff", "");
stat = conn.createStatement();
stat.execute("runscript from '" + baseDir + "/recovery.data.sql'");
String name = "recovery.data.sql";
if (SysProperties.PAGE_STORE) {
name = "recovery.h2.sql";
}
stat.execute("runscript from '" + baseDir + "/" + name + "'");
stat.execute("select * from test");
conn.close();
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论