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

Page store bugfixes.

上级 5fc5187b
...@@ -213,7 +213,8 @@ public abstract class PageBtree extends Page { ...@@ -213,7 +213,8 @@ public abstract class PageBtree extends Page {
* *
* @param id the new parent page id * @param id the new parent page id
*/ */
void setParentPageId(int id) { void setParentPageId(int id) throws SQLException {
index.getPageStore().logUndo(this, data);
written = false; written = false;
parentPageId = id; parentPageId = id;
} }
......
...@@ -14,7 +14,6 @@ import org.h2.message.Message; ...@@ -14,7 +14,6 @@ import org.h2.message.Message;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.store.Data; import org.h2.store.Data;
import org.h2.store.DataPage;
import org.h2.store.PageStore; import org.h2.store.PageStore;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
...@@ -53,7 +52,8 @@ public class PageBtreeIndex extends PageIndex { ...@@ -53,7 +52,8 @@ public class PageBtreeIndex extends PageIndex {
// must ensure this page is not used for other things // must ensure this page is not used for other things
store.addMeta(this, session); store.addMeta(this, session);
PageBtreeLeaf root = PageBtreeLeaf.create(this, rootPageId, PageBtree.ROOT); PageBtreeLeaf root = PageBtreeLeaf.create(this, rootPageId, PageBtree.ROOT);
store.updateRecord(root, true, root.data); store.logUndo(root, null);
store.updateRecord(root);
} else { } else {
rootPageId = store.getRootPageId(id); rootPageId = store.getRootPageId(id);
PageBtree root = getPage(rootPageId); PageBtree root = getPage(rootPageId);
...@@ -61,11 +61,6 @@ public class PageBtreeIndex extends PageIndex { ...@@ -61,11 +61,6 @@ public class PageBtreeIndex extends PageIndex {
if (rowCount == 0 && store.isRecoveryRunning()) { if (rowCount == 0 && store.isRecoveryRunning()) {
needRebuild = true; needRebuild = true;
} }
if (!database.isReadOnly()) {
// could have been created before, but never committed
// TODO test if really required
store.updateRecord(root, false, null);
}
} }
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("opened " + getName() +" rows:"+ rowCount); trace.debug("opened " + getName() +" rows:"+ rowCount);
...@@ -88,18 +83,21 @@ public class PageBtreeIndex extends PageIndex { ...@@ -88,18 +83,21 @@ public class PageBtreeIndex extends PageIndex {
trace.debug("split " + splitPoint); trace.debug("split " + splitPoint);
} }
SearchRow pivot = root.getRow(splitPoint - 1); SearchRow pivot = root.getRow(splitPoint - 1);
store.logUndo(root, root.data);
PageBtree page1 = root; PageBtree page1 = root;
PageBtree page2 = root.split(splitPoint); PageBtree page2 = root.split(splitPoint);
store.logUndo(page2, null);
int rootPageId = root.getPos(); int rootPageId = root.getPos();
int id = store.allocatePage(); int id = store.allocatePage();
page1.setPageId(id); page1.setPageId(id);
page1.setParentPageId(rootPageId); page1.setParentPageId(rootPageId);
page2.setParentPageId(rootPageId); page2.setParentPageId(rootPageId);
PageBtreeNode newRoot = PageBtreeNode.create(this, rootPageId, PageBtree.ROOT); PageBtreeNode newRoot = PageBtreeNode.create(this, rootPageId, PageBtree.ROOT);
store.logUndo(newRoot, null);
newRoot.init(page1, pivot, page2); newRoot.init(page1, pivot, page2);
store.updateRecord(page1, true, page1.data); store.updateRecord(page1);
store.updateRecord(page2, true, page2.data); store.updateRecord(page2);
store.updateRecord(newRoot, true, null); store.updateRecord(newRoot);
root = newRoot; root = newRoot;
} }
rowCount++; rowCount++;
...@@ -131,6 +129,9 @@ public class PageBtreeIndex extends PageIndex { ...@@ -131,6 +129,9 @@ public class PageBtreeIndex extends PageIndex {
PageBtree p = (PageBtree) store.getPage(id); PageBtree p = (PageBtree) store.getPage(id);
if (p == null) { if (p == null) {
PageBtreeLeaf empty = PageBtreeLeaf.create(this, id, PageBtree.ROOT); PageBtreeLeaf empty = PageBtreeLeaf.create(this, id, PageBtree.ROOT);
// could have been created before, but never committed
store.logUndo(empty, null);
store.updateRecord(empty);
return empty; return empty;
} }
return p; return p;
...@@ -242,10 +243,11 @@ public class PageBtreeIndex extends PageIndex { ...@@ -242,10 +243,11 @@ public class PageBtreeIndex extends PageIndex {
private void removeAllRows() throws SQLException { private void removeAllRows() throws SQLException {
PageBtree root = getPage(rootPageId); PageBtree root = getPage(rootPageId);
store.logUndo(root, root.data);
root.freeChildren(); root.freeChildren();
root = PageBtreeLeaf.create(this, rootPageId, PageBtree.ROOT); root = PageBtreeLeaf.create(this, rootPageId, PageBtree.ROOT);
store.removeRecord(rootPageId); store.removeRecord(rootPageId);
store.updateRecord(root, true, null); store.updateRecord(root);
rowCount = 0; rowCount = 0;
} }
...@@ -334,7 +336,7 @@ public class PageBtreeIndex extends PageIndex { ...@@ -334,7 +336,7 @@ public class PageBtreeIndex extends PageIndex {
* @return the number of bytes * @return the number of bytes
*/ */
int getRowSize(Data dummy, SearchRow row, boolean onlyPosition) throws SQLException { int getRowSize(Data dummy, SearchRow row, boolean onlyPosition) throws SQLException {
int rowsize = DataPage.LENGTH_INT; int rowsize = dummy.getVarLongLen(row.getKey());
if (!onlyPosition) { if (!onlyPosition) {
for (Column col : columns) { for (Column col : columns) {
Value v = row.getValue(col.getColumnId()); Value v = row.getValue(col.getColumnId());
......
...@@ -59,8 +59,9 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -59,8 +59,9 @@ public class PageBtreeLeaf extends PageBtree {
* @param parentPageId the parent * @param parentPageId the parent
* @return the page * @return the page
*/ */
static PageBtreeLeaf create(PageBtreeIndex index, int pageId, int parentPageId) { static PageBtreeLeaf create(PageBtreeIndex index, int pageId, int parentPageId) throws SQLException {
PageBtreeLeaf p = new PageBtreeLeaf(index, pageId, index.getPageStore().createData()); PageBtreeLeaf p = new PageBtreeLeaf(index, pageId, index.getPageStore().createData());
index.getPageStore().logUndo(p, p.data);
p.parentPageId = parentPageId; p.parentPageId = parentPageId;
p.writeHead(); p.writeHead();
p.start = p.data.length(); p.start = p.data.length();
...@@ -119,6 +120,7 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -119,6 +120,7 @@ public class PageBtreeLeaf extends PageBtree {
throw Message.throwInternalError(); throw Message.throwInternalError();
} }
} }
index.getPageStore().logUndo(this, data);
written = false; written = false;
int offset = last - rowLength; int offset = last - rowLength;
int[] newOffsets = new int[entryCount + 1]; int[] newOffsets = new int[entryCount + 1];
...@@ -145,12 +147,13 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -145,12 +147,13 @@ public class PageBtreeLeaf extends PageBtree {
newRows[x] = row; newRows[x] = row;
offsets = newOffsets; offsets = newOffsets;
rows = newRows; rows = newRows;
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
return -1; return -1;
} }
private void removeRow(int i) throws SQLException { private void removeRow(int i) throws SQLException {
readAllRows(); readAllRows();
index.getPageStore().logUndo(this, data);
entryCount--; entryCount--;
written = false; written = false;
if (entryCount <= 0) { if (entryCount <= 0) {
...@@ -177,8 +180,7 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -177,8 +180,7 @@ public class PageBtreeLeaf extends PageBtree {
PageBtree split(int splitPoint) throws SQLException { PageBtree split(int splitPoint) throws SQLException {
int newPageId = index.getPageStore().allocatePage(); int newPageId = index.getPageStore().allocatePage();
PageBtreeLeaf p2 = new PageBtreeLeaf(index, newPageId, index.getPageStore().createData()); PageBtreeLeaf p2 = PageBtreeLeaf.create(index, newPageId, parentPageId);
p2.parentPageId = parentPageId;
for (int i = splitPoint; i < entryCount;) { for (int i = splitPoint; i < entryCount;) {
p2.addRowTry(getRow(splitPoint)); p2.addRowTry(getRow(splitPoint));
removeRow(splitPoint); removeRow(splitPoint);
...@@ -204,8 +206,9 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -204,8 +206,9 @@ public class PageBtreeLeaf extends PageBtree {
// the page is now empty // the page is now empty
return row; return row;
} }
index.getPageStore().logUndo(this, data);
removeRow(at); removeRow(at);
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
if (at == entryCount) { if (at == entryCount) {
// the last row changed // the last row changed
return getRow(at - 1); return getRow(at - 1);
...@@ -314,15 +317,17 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -314,15 +317,17 @@ public class PageBtreeLeaf extends PageBtree {
public void moveTo(Session session, int newPos) throws SQLException { public void moveTo(Session session, int newPos) throws SQLException {
PageStore store = index.getPageStore(); PageStore store = index.getPageStore();
PageBtreeLeaf p2 = new PageBtreeLeaf(index, newPos, store.createData());
readAllRows(); readAllRows();
PageBtreeLeaf p2 = PageBtreeLeaf.create(index, newPos, parentPageId);
store.logUndo(this, data);
store.logUndo(p2, null);
p2.rows = rows; p2.rows = rows;
p2.entryCount = entryCount; p2.entryCount = entryCount;
p2.offsets = offsets; p2.offsets = offsets;
p2.onlyPosition = onlyPosition; p2.onlyPosition = onlyPosition;
p2.parentPageId = parentPageId; p2.parentPageId = parentPageId;
p2.start = start; p2.start = start;
store.updateRecord(p2, false, null); store.updateRecord(p2);
if (parentPageId == ROOT) { if (parentPageId == ROOT) {
index.setRootPageId(session, newPos); index.setRootPageId(session, newPos);
} else { } else {
......
...@@ -71,8 +71,9 @@ public class PageBtreeNode extends PageBtree { ...@@ -71,8 +71,9 @@ public class PageBtreeNode extends PageBtree {
* @param parentPageId the parent page id * @param parentPageId the parent page id
* @return the page * @return the page
*/ */
static PageBtreeNode create(PageBtreeIndex index, int pageId, int parentPageId) { static PageBtreeNode create(PageBtreeIndex index, int pageId, int parentPageId) throws SQLException {
PageBtreeNode p = new PageBtreeNode(index, pageId, index.getPageStore().createData()); PageBtreeNode p = new PageBtreeNode(index, pageId, index.getPageStore().createData());
index.getPageStore().logUndo(p, p.data);
p.parentPageId = parentPageId; p.parentPageId = parentPageId;
p.writeHead(); p.writeHead();
// 4 bytes for the rightmost child page id // 4 bytes for the rightmost child page id
...@@ -194,6 +195,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -194,6 +195,7 @@ public class PageBtreeNode extends PageBtree {
break; break;
} }
SearchRow pivot = page.getRow(splitPoint - 1); SearchRow pivot = page.getRow(splitPoint - 1);
index.getPageStore().logUndo(this, data);
int splitPoint2 = addChildTry(pivot); int splitPoint2 = addChildTry(pivot);
if (splitPoint2 != -1) { if (splitPoint2 != -1) {
return splitPoint2; return splitPoint2;
...@@ -201,9 +203,9 @@ public class PageBtreeNode extends PageBtree { ...@@ -201,9 +203,9 @@ public class PageBtreeNode extends PageBtree {
PageBtree page2 = page.split(splitPoint); PageBtree page2 = page.split(splitPoint);
readAllRows(); readAllRows();
addChild(x, page2.getPos(), pivot); addChild(x, page2.getPos(), pivot);
index.getPageStore().updateRecord(page, true, page.data); index.getPageStore().updateRecord(page);
index.getPageStore().updateRecord(page2, true, page2.data); index.getPageStore().updateRecord(page2);
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
} }
updateRowCount(1); updateRowCount(1);
written = false; written = false;
...@@ -218,8 +220,8 @@ public class PageBtreeNode extends PageBtree { ...@@ -218,8 +220,8 @@ public class PageBtreeNode extends PageBtree {
PageBtree split(int splitPoint) throws SQLException { PageBtree split(int splitPoint) throws SQLException {
int newPageId = index.getPageStore().allocatePage(); int newPageId = index.getPageStore().allocatePage();
PageBtreeNode p2 = new PageBtreeNode(index, newPageId, index.getPageStore().createData()); PageBtreeNode p2 = PageBtreeNode.create(index, newPageId, parentPageId);
p2.parentPageId = parentPageId; index.getPageStore().logUndo(this, data);
if (onlyPosition) { if (onlyPosition) {
// TODO optimize: maybe not required // TODO optimize: maybe not required
p2.onlyPosition = true; p2.onlyPosition = true;
...@@ -245,7 +247,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -245,7 +247,7 @@ public class PageBtreeNode extends PageBtree {
for (int child : childPageIds) { for (int child : childPageIds) {
PageBtree p = index.getPage(child); PageBtree p = index.getPage(child);
p.setParentPageId(getPos()); p.setParentPageId(getPos());
index.getPageStore().updateRecord(p, true, p.data); index.getPageStore().updateRecord(p);
} }
} }
...@@ -301,6 +303,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -301,6 +303,7 @@ public class PageBtreeNode extends PageBtree {
// TODO maybe implement merge // TODO maybe implement merge
PageBtree page = index.getPage(childPageIds[at]); PageBtree page = index.getPage(childPageIds[at]);
SearchRow last = page.remove(row); SearchRow last = page.remove(row);
index.getPageStore().logUndo(this, data);
updateRowCount(-1); updateRowCount(-1);
written = false; written = false;
if (last == null) { if (last == null) {
...@@ -320,7 +323,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -320,7 +323,7 @@ public class PageBtreeNode extends PageBtree {
last = null; last = null;
} }
removeChild(at); removeChild(at);
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
return last; return last;
} }
// the last row is in the last child // the last row is in the last child
...@@ -336,7 +339,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -336,7 +339,7 @@ public class PageBtreeNode extends PageBtree {
int temp = childPageIds[at]; int temp = childPageIds[at];
childPageIds[at] = childPageIds[at + 1]; childPageIds[at] = childPageIds[at + 1];
childPageIds[at + 1] = temp; childPageIds[at + 1] = temp;
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
return null; return null;
} }
...@@ -503,7 +506,8 @@ public class PageBtreeNode extends PageBtree { ...@@ -503,7 +506,8 @@ public class PageBtreeNode extends PageBtree {
public void moveTo(Session session, int newPos) throws SQLException { public void moveTo(Session session, int newPos) throws SQLException {
PageStore store = index.getPageStore(); PageStore store = index.getPageStore();
PageBtreeNode p2 = new PageBtreeNode(index, newPos, store.createData()); store.logUndo(this, data);
PageBtreeNode p2 = PageBtreeNode.create(index, newPos, parentPageId);
readAllRows(); readAllRows();
p2.childPageIds = childPageIds; p2.childPageIds = childPageIds;
p2.rows = rows; p2.rows = rows;
...@@ -512,7 +516,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -512,7 +516,7 @@ public class PageBtreeNode extends PageBtree {
p2.onlyPosition = onlyPosition; p2.onlyPosition = onlyPosition;
p2.parentPageId = parentPageId; p2.parentPageId = parentPageId;
p2.start = start; p2.start = start;
store.updateRecord(p2, false, null); store.updateRecord(p2);
if (parentPageId == ROOT) { if (parentPageId == ROOT) {
index.setRootPageId(session, newPos); index.setRootPageId(session, newPos);
} else { } else {
...@@ -522,7 +526,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -522,7 +526,7 @@ public class PageBtreeNode extends PageBtree {
for (int i = 0; i < childPageIds.length; i++) { for (int i = 0; i < childPageIds.length; i++) {
PageBtree p = (PageBtree) store.getPage(childPageIds[i]); PageBtree p = (PageBtree) store.getPage(childPageIds[i]);
p.setParentPageId(newPos); p.setParentPageId(newPos);
store.updateRecord(p, true, p.data); store.updateRecord(p);
} }
store.freePage(getPos(), true, data); store.freePage(getPos(), true, data);
} }
...@@ -536,9 +540,10 @@ public class PageBtreeNode extends PageBtree { ...@@ -536,9 +540,10 @@ public class PageBtreeNode extends PageBtree {
void moveChild(int oldPos, int newPos) throws SQLException { void moveChild(int oldPos, int newPos) throws SQLException {
for (int i = 0; i < childPageIds.length; i++) { for (int i = 0; i < childPageIds.length; i++) {
if (childPageIds[i] == oldPos) { if (childPageIds[i] == oldPos) {
index.getPageStore().logUndo(this, data);
written = false; written = false;
childPageIds[i] = newPos; childPageIds[i] = newPos;
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
return; return;
} }
} }
......
...@@ -172,7 +172,8 @@ abstract class PageData extends Page { ...@@ -172,7 +172,8 @@ abstract class PageData extends Page {
* *
* @param id the new parent page id * @param id the new parent page id
*/ */
void setParentPageId(int id) { void setParentPageId(int id) throws SQLException {
index.getPageStore().logUndo(this, data);
parentPageId = id; parentPageId = id;
if (written) { if (written) {
data.setInt(START_PARENT, parentPageId); data.setInt(START_PARENT, parentPageId);
......
...@@ -65,17 +65,12 @@ public class PageDataIndex extends PageIndex implements RowIndex { ...@@ -65,17 +65,12 @@ public class PageDataIndex extends PageIndex implements RowIndex {
rootPageId = store.allocatePage(); rootPageId = store.allocatePage();
store.addMeta(this, session); store.addMeta(this, session);
PageDataLeaf root = PageDataLeaf.create(this, rootPageId, PageData.ROOT); PageDataLeaf root = PageDataLeaf.create(this, rootPageId, PageData.ROOT);
store.updateRecord(root, true, root.data); store.updateRecord(root);
} else { } else {
rootPageId = store.getRootPageId(id); rootPageId = store.getRootPageId(id);
PageData root = getPage(rootPageId, 0); PageData root = getPage(rootPageId, 0);
lastKey = root.getLastKey(); lastKey = root.getLastKey();
rowCount = root.getRowCount(); rowCount = root.getRowCount();
// could have been created before, but never committed
if (!database.isReadOnly()) {
// TODO check if really required
store.updateRecord(root, false, null);
}
} }
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("opened " + getName() + " rows:" + rowCount); trace.debug("opened " + getName() + " rows:" + rowCount);
...@@ -166,9 +161,9 @@ public class PageDataIndex extends PageIndex implements RowIndex { ...@@ -166,9 +161,9 @@ public class PageDataIndex extends PageIndex implements RowIndex {
page2.setParentPageId(rootPageId); page2.setParentPageId(rootPageId);
PageDataNode newRoot = PageDataNode.create(this, rootPageId, PageData.ROOT); PageDataNode newRoot = PageDataNode.create(this, rootPageId, PageData.ROOT);
newRoot.init(page1, pivot, page2); newRoot.init(page1, pivot, page2);
store.updateRecord(page1, true, page1.data); store.updateRecord(page1);
store.updateRecord(page2, true, page2.data); store.updateRecord(page2);
store.updateRecord(newRoot, true, null); store.updateRecord(newRoot);
root = newRoot; root = newRoot;
} }
row.setDeleted(false); row.setDeleted(false);
...@@ -208,6 +203,9 @@ public class PageDataIndex extends PageIndex implements RowIndex { ...@@ -208,6 +203,9 @@ public class PageDataIndex extends PageIndex implements RowIndex {
PageData p = (PageData) store.getPage(id); PageData p = (PageData) store.getPage(id);
if (p == null) { if (p == null) {
PageDataLeaf empty = PageDataLeaf.create(this, id, parent); PageDataLeaf empty = PageDataLeaf.create(this, id, parent);
// could have been created before, but never committed
store.logUndo(empty, null);
store.updateRecord(empty);
return empty; return empty;
} }
if (p.index.rootPageId != rootPageId) { if (p.index.rootPageId != rootPageId) {
...@@ -351,7 +349,7 @@ public class PageDataIndex extends PageIndex implements RowIndex { ...@@ -351,7 +349,7 @@ public class PageDataIndex extends PageIndex implements RowIndex {
root.freeChildren(); root.freeChildren();
root = PageDataLeaf.create(this, rootPageId, PageData.ROOT); root = PageDataLeaf.create(this, rootPageId, PageData.ROOT);
store.removeRecord(rootPageId); store.removeRecord(rootPageId);
store.updateRecord(root, true, null); store.updateRecord(root);
rowCount = 0; rowCount = 0;
lastKey = 0; lastKey = 0;
} }
......
...@@ -81,8 +81,9 @@ public class PageDataLeaf extends PageData { ...@@ -81,8 +81,9 @@ public class PageDataLeaf extends PageData {
* @param parentPageId the parent * @param parentPageId the parent
* @return the page * @return the page
*/ */
static PageDataLeaf create(PageDataIndex index, int pageId, int parentPageId) { static PageDataLeaf create(PageDataIndex index, int pageId, int parentPageId) throws SQLException {
PageDataLeaf p = new PageDataLeaf(index, pageId, index.getPageStore().createData()); PageDataLeaf p = new PageDataLeaf(index, pageId, index.getPageStore().createData());
index.getPageStore().logUndo(p, p.data);
p.parentPageId = parentPageId; p.parentPageId = parentPageId;
p.columnCount = index.getTable().getColumns().length; p.columnCount = index.getTable().getColumns().length;
p.writeHead(); p.writeHead();
...@@ -140,6 +141,7 @@ public class PageDataLeaf extends PageData { ...@@ -140,6 +141,7 @@ public class PageDataLeaf extends PageData {
} }
int addRowTry(Row row) throws SQLException { int addRowTry(Row row) throws SQLException {
index.getPageStore().logUndo(this, data);
int rowLength = getRowLength(row); int rowLength = getRowLength(row);
int pageSize = index.getPageStore().getPageSize(); int pageSize = index.getPageStore().getPageSize();
int last = entryCount == 0 ? pageSize : offsets[entryCount - 1]; int last = entryCount == 0 ? pageSize : offsets[entryCount - 1];
...@@ -159,6 +161,7 @@ public class PageDataLeaf extends PageData { ...@@ -159,6 +161,7 @@ public class PageDataLeaf extends PageData {
} }
return x; return x;
} }
index.getPageStore().logUndo(this, data);
int offset = last - rowLength; int offset = last - rowLength;
int[] newOffsets = new int[entryCount + 1]; int[] newOffsets = new int[entryCount + 1];
long[] newKeys = new long[entryCount + 1]; long[] newKeys = new long[entryCount + 1];
...@@ -195,7 +198,7 @@ public class PageDataLeaf extends PageData { ...@@ -195,7 +198,7 @@ public class PageDataLeaf extends PageData {
offsets = newOffsets; offsets = newOffsets;
keys = newKeys; keys = newKeys;
rows = newRows; rows = newRows;
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
if (offset < start) { if (offset < start) {
if (entryCount > 1) { if (entryCount > 1) {
Message.throwInternalError(); Message.throwInternalError();
...@@ -231,7 +234,7 @@ public class PageDataLeaf extends PageData { ...@@ -231,7 +234,7 @@ public class PageDataLeaf extends PageData {
next = index.getPageStore().allocatePage(); next = index.getPageStore().allocatePage();
} }
PageDataOverflow overflow = PageDataOverflow.create(index.getPageStore(), page, type, previous, next, all, dataOffset, size); PageDataOverflow overflow = PageDataOverflow.create(index.getPageStore(), page, type, previous, next, all, dataOffset, size);
index.getPageStore().updateRecord(overflow, true, null); index.getPageStore().updateRecord(overflow);
dataOffset += size; dataOffset += size;
remaining -= size; remaining -= size;
previous = page; previous = page;
...@@ -242,6 +245,7 @@ public class PageDataLeaf extends PageData { ...@@ -242,6 +245,7 @@ public class PageDataLeaf extends PageData {
} }
private void removeRow(int i) throws SQLException { private void removeRow(int i) throws SQLException {
index.getPageStore().logUndo(this, data);
written = false; written = false;
readAllRows(); readAllRows();
Row r = rows[i]; Row r = rows[i];
...@@ -361,7 +365,7 @@ public class PageDataLeaf extends PageData { ...@@ -361,7 +365,7 @@ public class PageDataLeaf extends PageData {
} }
PageDataOverflow overflow = index.getPageOverflow(firstOverflowPageId); PageDataOverflow overflow = index.getPageOverflow(firstOverflowPageId);
overflow.setParentPageId(getPos()); overflow.setParentPageId(getPos());
index.getPageStore().updateRecord(overflow, true, null); index.getPageStore().updateRecord(overflow);
} }
boolean remove(long key) throws SQLException { boolean remove(long key) throws SQLException {
...@@ -369,12 +373,13 @@ public class PageDataLeaf extends PageData { ...@@ -369,12 +373,13 @@ public class PageDataLeaf extends PageData {
if (keys[i] != key) { if (keys[i] != key) {
throw Message.getSQLException(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, index.getSQL() + ": " + key); throw Message.getSQLException(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, index.getSQL() + ": " + key);
} }
index.getPageStore().logUndo(this, data);
if (entryCount == 1) { if (entryCount == 1) {
freeChildren(); freeChildren();
return true; return true;
} }
removeRow(i); removeRow(i);
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
return false; return false;
} }
...@@ -476,6 +481,7 @@ public class PageDataLeaf extends PageData { ...@@ -476,6 +481,7 @@ public class PageDataLeaf extends PageData {
public void moveTo(Session session, int newPos) throws SQLException { public void moveTo(Session session, int newPos) throws SQLException {
PageStore store = index.getPageStore(); PageStore store = index.getPageStore();
store.logUndo(this, data);
PageDataLeaf p2 = PageDataLeaf.create(index, newPos, parentPageId); PageDataLeaf p2 = PageDataLeaf.create(index, newPos, parentPageId);
readAllRows(); readAllRows();
p2.keys = keys; p2.keys = keys;
...@@ -490,10 +496,10 @@ public class PageDataLeaf extends PageData { ...@@ -490,10 +496,10 @@ public class PageDataLeaf extends PageData {
p2.offsets = offsets; p2.offsets = offsets;
p2.parentPageId = parentPageId; p2.parentPageId = parentPageId;
p2.start = start; p2.start = start;
store.updateRecord(p2, false, null);
p2.remapChildren(); p2.remapChildren();
p2.write(); p2.write();
p2.data.truncate(index.getPageStore().getPageSize()); p2.data.truncate(index.getPageStore().getPageSize());
store.updateRecord(p2);
store.freePage(getPos(), true, data); store.freePage(getPos(), true, data);
if (parentPageId == ROOT) { if (parentPageId == ROOT) {
index.setRootPageId(session, newPos); index.setRootPageId(session, newPos);
...@@ -504,12 +510,13 @@ public class PageDataLeaf extends PageData { ...@@ -504,12 +510,13 @@ public class PageDataLeaf extends PageData {
} }
void setOverflow(int overflow) throws SQLException { void setOverflow(int overflow) throws SQLException {
index.getPageStore().logUndo(this, data);
firstOverflowPageId = overflow; firstOverflowPageId = overflow;
if (written) { if (written) {
writeHead(); writeHead();
data.writeInt(firstOverflowPageId); data.writeInt(firstOverflowPageId);
} }
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
} }
public int getMemorySize() { public int getMemorySize() {
......
...@@ -62,8 +62,9 @@ public class PageDataNode extends PageData { ...@@ -62,8 +62,9 @@ public class PageDataNode extends PageData {
* @param parentPageId the parent * @param parentPageId the parent
* @return the page * @return the page
*/ */
static PageDataNode create(PageDataIndex index, int pageId, int parentPageId) { static PageDataNode create(PageDataIndex index, int pageId, int parentPageId) throws SQLException {
PageDataNode p = new PageDataNode(index, pageId, index.getPageStore().createData()); PageDataNode p = new PageDataNode(index, pageId, index.getPageStore().createData());
index.getPageStore().logUndo(p, p.data);
p.parentPageId = parentPageId; p.parentPageId = parentPageId;
p.writeHead(); p.writeHead();
// 4 bytes for the rightmost child page id // 4 bytes for the rightmost child page id
...@@ -110,7 +111,8 @@ public class PageDataNode extends PageData { ...@@ -110,7 +111,8 @@ public class PageDataNode extends PageData {
written = true; written = true;
} }
private void addChild(int x, int childPageId, long key) { private void addChild(int x, int childPageId, long key) throws SQLException {
index.getPageStore().logUndo(this, data);
written = false; written = false;
long[] newKeys = new long[entryCount + 1]; long[] newKeys = new long[entryCount + 1];
int[] newChildPageIds = new int[entryCount + 2]; int[] newChildPageIds = new int[entryCount + 2];
...@@ -133,6 +135,7 @@ public class PageDataNode extends PageData { ...@@ -133,6 +135,7 @@ public class PageDataNode extends PageData {
} }
int addRowTry(Row row) throws SQLException { int addRowTry(Row row) throws SQLException {
index.getPageStore().logUndo(this, data);
int keyOffsetPairLen = 4 + data.getVarLongLen(row.getKey()); int keyOffsetPairLen = 4 + data.getVarLongLen(row.getKey());
while (true) { while (true) {
int x = find(row.getKey()); int x = find(row.getKey());
...@@ -146,10 +149,10 @@ public class PageDataNode extends PageData { ...@@ -146,10 +149,10 @@ public class PageDataNode extends PageData {
} }
long pivot = splitPoint == 0 ? row.getKey() : page.getKey(splitPoint - 1); long pivot = splitPoint == 0 ? row.getKey() : page.getKey(splitPoint - 1);
PageData page2 = page.split(splitPoint); PageData page2 = page.split(splitPoint);
index.getPageStore().updateRecord(page, true, page.data); index.getPageStore().updateRecord(page);
index.getPageStore().updateRecord(page2, true, page2.data); index.getPageStore().updateRecord(page2);
addChild(x, page2.getPos(), pivot); addChild(x, page2.getPos(), pivot);
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
} }
updateRowCount(1); updateRowCount(1);
return -1; return -1;
...@@ -161,10 +164,11 @@ public class PageDataNode extends PageData { ...@@ -161,10 +164,11 @@ public class PageDataNode extends PageData {
} }
if (rowCountStored != UNKNOWN_ROWCOUNT) { if (rowCountStored != UNKNOWN_ROWCOUNT) {
rowCountStored = UNKNOWN_ROWCOUNT; rowCountStored = UNKNOWN_ROWCOUNT;
index.getPageStore().logUndo(this, data);
if (written) { if (written) {
writeHead(); writeHead();
} }
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
} }
} }
...@@ -194,7 +198,7 @@ public class PageDataNode extends PageData { ...@@ -194,7 +198,7 @@ public class PageDataNode extends PageData {
for (int child : childPageIds) { for (int child : childPageIds) {
PageData p = index.getPage(child, -1); PageData p = index.getPage(child, -1);
p.setParentPageId(getPos()); p.setParentPageId(getPos());
index.getPageStore().updateRecord(p, true, p.data); index.getPageStore().updateRecord(p);
} }
} }
...@@ -259,7 +263,7 @@ public class PageDataNode extends PageData { ...@@ -259,7 +263,7 @@ public class PageDataNode extends PageData {
return true; return true;
} }
removeChild(at); removeChild(at);
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
return false; return false;
} }
...@@ -297,10 +301,11 @@ public class PageDataNode extends PageData { ...@@ -297,10 +301,11 @@ public class PageDataNode extends PageData {
this.rowCount = rowCount; this.rowCount = rowCount;
if (rowCountStored != rowCount) { if (rowCountStored != rowCount) {
rowCountStored = rowCount; rowCountStored = rowCount;
index.getPageStore().logUndo(this, data);
if (written) { if (written) {
writeHead(); writeHead();
} }
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
} }
} }
...@@ -353,7 +358,8 @@ public class PageDataNode extends PageData { ...@@ -353,7 +358,8 @@ public class PageDataNode extends PageData {
written = true; written = true;
} }
private void removeChild(int i) { private void removeChild(int i) throws SQLException {
index.getPageStore().logUndo(this, data);
written = false; written = false;
entryCount--; entryCount--;
int removedKeyIndex = i < keys.length ? i : i - 1; int removedKeyIndex = i < keys.length ? i : i - 1;
...@@ -379,6 +385,7 @@ public class PageDataNode extends PageData { ...@@ -379,6 +385,7 @@ public class PageDataNode extends PageData {
public void moveTo(Session session, int newPos) throws SQLException { public void moveTo(Session session, int newPos) throws SQLException {
PageStore store = index.getPageStore(); PageStore store = index.getPageStore();
store.logUndo(this, data);
PageDataNode p2 = PageDataNode.create(index, newPos, parentPageId); PageDataNode p2 = PageDataNode.create(index, newPos, parentPageId);
p2.rowCountStored = rowCountStored; p2.rowCountStored = rowCountStored;
p2.rowCount = rowCount; p2.rowCount = rowCount;
...@@ -386,7 +393,7 @@ public class PageDataNode extends PageData { ...@@ -386,7 +393,7 @@ public class PageDataNode extends PageData {
p2.keys = keys; p2.keys = keys;
p2.entryCount = entryCount; p2.entryCount = entryCount;
p2.length = length; p2.length = length;
store.updateRecord(p2, false, null); store.updateRecord(p2);
if (parentPageId == ROOT) { if (parentPageId == ROOT) {
index.setRootPageId(session, newPos); index.setRootPageId(session, newPos);
} else { } else {
...@@ -396,7 +403,7 @@ public class PageDataNode extends PageData { ...@@ -396,7 +403,7 @@ public class PageDataNode extends PageData {
for (int i = 0; i < childPageIds.length; i++) { for (int i = 0; i < childPageIds.length; i++) {
PageData p = (PageData) store.getPage(childPageIds[i]); PageData p = (PageData) store.getPage(childPageIds[i]);
p.setParentPageId(newPos); p.setParentPageId(newPos);
store.updateRecord(p, true, p.data); store.updateRecord(p);
} }
store.freePage(getPos(), true, data); store.freePage(getPos(), true, data);
} }
...@@ -410,9 +417,10 @@ public class PageDataNode extends PageData { ...@@ -410,9 +417,10 @@ public class PageDataNode extends PageData {
void moveChild(int oldPos, int newPos) throws SQLException { void moveChild(int oldPos, int newPos) throws SQLException {
for (int i = 0; i < childPageIds.length; i++) { for (int i = 0; i < childPageIds.length; i++) {
if (childPageIds[i] == oldPos) { if (childPageIds[i] == oldPos) {
index.getPageStore().logUndo(this, data);
written = false; written = false;
childPageIds[i] = newPos; childPageIds[i] = newPos;
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this);
return; return;
} }
} }
......
...@@ -106,9 +106,10 @@ public class PageDataOverflow extends Page { ...@@ -106,9 +106,10 @@ public class PageDataOverflow extends Page {
* @param size the number of bytes * @param size the number of bytes
* @return the page * @return the page
*/ */
static PageDataOverflow create(PageStore store, int page, int type, int parentPageId, int next, Data all, int offset, int size) { static PageDataOverflow create(PageStore store, int page, int type, int parentPageId, int next, Data all, int offset, int size) throws SQLException {
Data data = store.createData(); Data data = store.createData();
PageDataOverflow p = new PageDataOverflow(store, page, data); PageDataOverflow p = new PageDataOverflow(store, page, data);
store.logUndo(p, data);
data.writeByte((byte) type); data.writeByte((byte) type);
data.writeShortInt(0); data.writeShortInt(0);
data.writeInt(parentPageId); data.writeInt(parentPageId);
...@@ -207,16 +208,19 @@ public class PageDataOverflow extends Page { ...@@ -207,16 +208,19 @@ public class PageDataOverflow extends Page {
return store.getPageSize() >> 1; return store.getPageSize() >> 1;
} }
void setParentPageId(int parent) { void setParentPageId(int parent) throws SQLException {
store.logUndo(this, data);
this.parentPageId = parent; this.parentPageId = parent;
} }
public void moveTo(Session session, int newPos) throws SQLException { public void moveTo(Session session, int newPos) throws SQLException {
store.logUndo(this, data);
PageDataOverflow p2 = PageDataOverflow.create(store, newPos, type, parentPageId, nextPage, data, start, size); PageDataOverflow p2 = PageDataOverflow.create(store, newPos, type, parentPageId, nextPage, data, start, size);
store.updateRecord(p2, false, null); store.updateRecord(p2);
if (nextPage != 0) { if (nextPage != 0) {
PageDataOverflow p3 = (PageDataOverflow) store.getPage(nextPage); PageDataOverflow p3 = (PageDataOverflow) store.getPage(nextPage);
p3.setParentPageId(newPos); p3.setParentPageId(newPos);
store.updateRecord(p3);
} }
Page p = store.getPage(parentPageId); Page p = store.getPage(parentPageId);
if (p == null) { if (p == null) {
...@@ -229,13 +233,14 @@ public class PageDataOverflow extends Page { ...@@ -229,13 +233,14 @@ public class PageDataOverflow extends Page {
PageDataLeaf p1 = (PageDataLeaf) p; PageDataLeaf p1 = (PageDataLeaf) p;
p1.setOverflow(newPos); p1.setOverflow(newPos);
} }
store.updateRecord(p);
store.freePage(getPos(), true, data); store.freePage(getPos(), true, data);
} }
private void setNext(int nextPage) throws SQLException { private void setNext(int nextPage) throws SQLException {
store.logUndo(this, data);
this.nextPage = nextPage; this.nextPage = nextPage;
data.setInt(START_NEXT_OVERFLOW, nextPage); data.setInt(START_NEXT_OVERFLOW, nextPage);
store.updateRecord(this, true, data);
} }
} }
...@@ -86,8 +86,9 @@ public class PageFreeList extends Page { ...@@ -86,8 +86,9 @@ public class PageFreeList extends Page {
return -1; return -1;
} }
} else { } else {
store.logUndo(this, data);
used.set(free); used.set(free);
store.updateRecord(this, true, data); store.updateRecord(this);
return free + getPos(); return free + getPos();
} }
} }
...@@ -118,8 +119,9 @@ public class PageFreeList extends Page { ...@@ -118,8 +119,9 @@ public class PageFreeList extends Page {
int allocate(int pageId) throws SQLException { int allocate(int pageId) throws SQLException {
int idx = pageId - getPos(); int idx = pageId - getPos();
if (idx >= 0 && !used.get(idx)) { if (idx >= 0 && !used.get(idx)) {
store.logUndo(this, data);
used.set(idx); used.set(idx);
store.updateRecord(this, true, data); store.updateRecord(this);
} }
return pageId; return pageId;
} }
...@@ -131,8 +133,9 @@ public class PageFreeList extends Page { ...@@ -131,8 +133,9 @@ public class PageFreeList extends Page {
*/ */
void free(int pageId) throws SQLException { void free(int pageId) throws SQLException {
full = false; full = false;
store.logUndo(this, data);
used.clear(pageId - getPos()); used.clear(pageId - getPos());
store.updateRecord(this, true, data); store.updateRecord(this);
} }
/** /**
......
...@@ -12,6 +12,7 @@ import java.io.OutputStream; ...@@ -12,6 +12,7 @@ import java.io.OutputStream;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import org.h2.compress.CompressLZF; import org.h2.compress.CompressLZF;
import org.h2.constant.SysProperties;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.log.InDoubtTransaction; import org.h2.log.InDoubtTransaction;
import org.h2.log.LogSystem; import org.h2.log.LogSystem;
...@@ -431,6 +432,9 @@ public class PageLog { ...@@ -431,6 +432,9 @@ public class PageLog {
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("log undo " + pageId); trace.debug("log undo " + pageId);
} }
if (SysProperties.CHECK && page == null) {
Message.throwInternalError("Undo entry not written");
}
undo.set(pageId); undo.set(pageId);
undoAll.set(pageId); undoAll.set(pageId);
outBuffer.writeByte((byte) UNDO); outBuffer.writeByte((byte) UNDO);
...@@ -612,8 +616,10 @@ public class PageLog { ...@@ -612,8 +616,10 @@ public class PageLog {
*/ */
void flush() throws SQLException { void flush() throws SQLException {
try { try {
if (pageOut != null) {
flushBuffer(); flushBuffer();
pageOut.flush(); pageOut.flush();
}
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, null); throw Message.convertIOException(e, null);
} }
......
...@@ -13,6 +13,7 @@ import java.util.HashMap; ...@@ -13,6 +13,7 @@ import java.util.HashMap;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.CreateTableData;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -690,14 +691,37 @@ public class PageStore implements CacheWriter { ...@@ -690,14 +691,37 @@ public class PageStore implements CacheWriter {
} }
} }
/**
* Write an undo log entry if required.
*
* @param record the page
* @param old the old data (if known) or null
*/
public void logUndo(Record record, Data old) throws SQLException {
synchronized (database) {
if (trace.isDebugEnabled()) {
if (!record.isChanged()) {
trace.debug("logUndo " + record.toString());
}
}
checkOpen();
database.checkWritingAllowed();
if (!recoveryRunning) {
int pos = record.getPos();
if (old == null) {
old = readPage(pos);
}
log.addUndo(pos, old);
}
}
}
/** /**
* Update a record. * Update a record.
* *
* @param record the record * @param record the record
* @param logUndo if an undo entry need to be logged
* @param old the old data (if known)
*/ */
public void updateRecord(Record record, boolean logUndo, Data old) throws SQLException { public void updateRecord(Record record) throws SQLException {
synchronized (database) { synchronized (database) {
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
if (!record.isChanged()) { if (!record.isChanged()) {
...@@ -708,14 +732,12 @@ public class PageStore implements CacheWriter { ...@@ -708,14 +732,12 @@ public class PageStore implements CacheWriter {
database.checkWritingAllowed(); database.checkWritingAllowed();
record.setChanged(true); record.setChanged(true);
int pos = record.getPos(); int pos = record.getPos();
if (SysProperties.CHECK && !recoveryRunning) {
// ensure the undo entry is already written
log.addUndo(pos, null);
}
allocatePage(pos); allocatePage(pos);
cache.update(pos, record); cache.update(pos, record);
if (logUndo && !recoveryRunning) {
if (old == null) {
old = readPage(pos);
}
log.addUndo(pos, old);
}
} }
} }
...@@ -840,7 +862,12 @@ public class PageStore implements CacheWriter { ...@@ -840,7 +862,12 @@ public class PageStore implements CacheWriter {
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
// trace.debug("freePage " + pageId); // trace.debug("freePage " + pageId);
} }
int todoRemoveOld;
synchronized (database) { synchronized (database) {
if (SysProperties.CHECK && !recoveryRunning && logUndo) {
// ensure the undo entry is already written
log.addUndo(pageId, null);
}
cache.remove(pageId); cache.remove(pageId);
freePage(pageId); freePage(pageId);
if (recoveryRunning) { if (recoveryRunning) {
......
...@@ -194,13 +194,14 @@ public class PageStreamTrunk extends Page { ...@@ -194,13 +194,14 @@ public class PageStreamTrunk extends Page {
* @param newPos the new position * @param newPos the new position
*/ */
void moveChild(int oldPos, int newPos) throws SQLException { void moveChild(int oldPos, int newPos) throws SQLException {
store.logUndo(this, data);
for (int i = 0; i < pageIds.length; i++) { for (int i = 0; i < pageIds.length; i++) {
if (pageIds[i] == oldPos) { if (pageIds[i] == oldPos) {
pageIds[i] = newPos; pageIds[i] = newPos;
break; break;
} }
} }
store.updateRecord(this, true, data); store.updateRecord(this);
} }
public void moveTo(Session session, int newPos) { public void moveTo(Session session, int newPos) {
......
...@@ -129,21 +129,24 @@ public class CacheLRU implements Cache { ...@@ -129,21 +129,24 @@ public class CacheLRU implements Cache {
ObjectArray<CacheObject> changed = ObjectArray.newInstance(); ObjectArray<CacheObject> changed = ObjectArray.newInstance();
int mem = sizeMemory; int mem = sizeMemory;
int rc = recordCount; int rc = recordCount;
boolean flushed = false;
CacheObject next = head.next; CacheObject next = head.next;
while (mem * 4 > maxSize * 3 && rc > Constants.CACHE_MIN_RECORDS) { while (mem * 4 > maxSize * 3 && rc > Constants.CACHE_MIN_RECORDS) {
CacheObject check = next; CacheObject check = next;
next = check.next; next = check.next;
i++; i++;
if (i == recordCount) { if (i >= recordCount) {
if (!flushed) {
writer.flushLog(); writer.flushLog();
} flushed = true;
if (i >= recordCount * 2) { i = 0;
} else {
// can't remove any record, because the log is not written yet // can't remove any record, because the log is not written yet
// hopefully this does not happen too much, but it could happen // hopefully this does not happen frequently, but it can happen
// theoretically
writer.getTrace().info("Cannot remove records, cache size too small?"); writer.getTrace().info("Cannot remove records, cache size too small?");
break; break;
} }
}
if (SysProperties.CHECK && check == head) { if (SysProperties.CHECK && check == head) {
Message.throwInternalError("try to remove head"); Message.throwInternalError("try to remove head");
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论