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

Page store bugfixes.

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