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

Data modifications (inserts, updates, and deletes) are now up to 5 times faster in some cases.

上级 a1622ab3
......@@ -774,11 +774,11 @@ DROP VIEW TEST_VIEW
"Commands (DDL)","TRUNCATE TABLE","
TRUNCATE TABLE tableName
","
Removes all rows from a table.
Unlike DELETE FROM without where clause, this command can not be rolled back.
This command is faster than DELETE without where clause.
Only regular data tables without foreign key constraints can be truncated
(except if referential integrity is disabled for this database or for this table).
Removes all rows from a table.
Unlike DELETE FROM without where clause, this command can not be rolled back.
This command is faster than DELETE without where clause.
Only regular data tables without foreign key constraints can be truncated
(except if referential integrity is disabled for this database or for this table).
Linked tables can't be truncated.
This command commits an open transaction.
......
......@@ -18,7 +18,7 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>Data modifications (inserts, updates, and deletes) are now faster for existing tables
<ul><li>Data modifications (inserts, updates, and deletes) are now up to 5 times faster
because converting objects to byte arrays is avoided if possible.
</li><li>LOG=0 is now a bit faster (previously undo log entries were still written).
</li><li>The command line tools now say so if the source directory of an option doesn't exist.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -188,7 +188,7 @@ public abstract class Command implements CommandInterface {
Object sync = database.isMultiThreaded() ? (Object) session : (Object) database;
session.waitIfExclusiveModeEnabled();
boolean callStop = true;
session.getDatabase().beforeWriting();
database.beforeWriting();
synchronized (sync) {
int rollback = session.getLogId();
session.setCurrentCommand(this, startTime);
......@@ -232,7 +232,7 @@ public abstract class Command implements CommandInterface {
// in this case we need to panic:
// close the database
callStop = false;
session.getDatabase().shutdownImmediately();
database.shutdownImmediately();
throw e;
} else {
session.rollbackTo(rollback, false);
......@@ -244,7 +244,7 @@ public abstract class Command implements CommandInterface {
stop();
}
} finally {
session.getDatabase().afterWriting();
database.afterWriting();
}
}
}
......
......@@ -471,7 +471,8 @@ public class SysProperties {
/**
* System property <code>h2.optimizeUpdate</code> (default: true).<br />
* Speed up inserts, updates, and deletes by not reading all rows from a page unless necessary.
* Speed up inserts, updates, and deletes by not reading all rows from a
* page unless necessary.
*/
public static final boolean OPTIMIZE_UPDATE = getBooleanSetting("h2.optimizeUpdate", true);
......
......@@ -669,7 +669,9 @@ public class Session extends SessionWithState implements SessionFactory {
}
if (locks.size() > 0) {
synchronized (database) {
for (Table t : locks) {
// don't use the enhance for loop to safe memory
for (int i = 0; i < locks.size(); i++) {
Table t = locks.get(i);
t.unlock(this);
}
locks.clear();
......
......@@ -71,8 +71,10 @@ public class IndexCursor implements Cursor {
inList = null;
inColumn = null;
inResult = null;
inResultTested = new HashSet<Value>();
for (IndexCondition condition : indexConditions) {
inResultTested = null;
// don't use enhanced for loop to avoid creating objects
for (int i = 0; i < indexConditions.size(); i++) {
IndexCondition condition = indexConditions.get(i);
if (condition.isAlwaysFalse()) {
alwaysFalse = true;
break;
......@@ -240,6 +242,9 @@ public class IndexCursor implements Cursor {
Value v = inResult.currentRow()[0];
if (v != ValueNull.INSTANCE) {
v = inColumn.convert(v);
if (inResultTested == null) {
inResultTested = new HashSet<Value>();
}
if (inResultTested.add(v)) {
find(v);
break;
......
......@@ -6,6 +6,7 @@
*/
package org.h2.index;
import java.util.Arrays;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
......@@ -32,6 +33,8 @@ public class PageBtreeLeaf extends PageBtree {
private static final int OFFSET_LENGTH = 2;
private boolean writtenData;
private PageBtreeLeaf(PageBtreeIndex index, int pageId, Data data) {
super(index, pageId, data);
}
......@@ -61,6 +64,7 @@ public class PageBtreeLeaf extends PageBtree {
static PageBtreeLeaf create(PageBtreeIndex index, int pageId, int parentPageId) {
PageBtreeLeaf p = new PageBtreeLeaf(index, pageId, index.getPageStore().createData());
index.getPageStore().logUndo(p, null);
p.rows = SearchRow.EMPTY_ARRAY;
p.parentPageId = parentPageId;
p.writeHead();
p.start = p.data.length();
......@@ -87,6 +91,7 @@ public class PageBtreeLeaf extends PageBtree {
}
start = data.length();
written = true;
writtenData = true;
}
int addRowTry(SearchRow row) {
......@@ -125,40 +130,41 @@ public class PageBtreeLeaf extends PageBtree {
}
}
index.getPageStore().logUndo(this, data);
readAllRows();
if (!SysProperties.OPTIMIZE_UPDATE) {
readAllRows();
}
changeCount = index.getPageStore().getChangeCount();
written = false;
int offset = last - rowLength;
int[] newOffsets = new int[entryCount + 1];
SearchRow[] newRows = new SearchRow[entryCount + 1];
int x;
if (entryCount == 0) {
x = 0;
} else {
x = find(row, false, true, true);
System.arraycopy(offsets, 0, newOffsets, 0, x);
System.arraycopy(rows, 0, newRows, 0, x);
if (x < entryCount) {
for (int j = x; j < entryCount; j++) {
newOffsets[j + 1] = offsets[j] - rowLength;
}
offset = (x == 0 ? pageSize : offsets[x - 1]) - rowLength;
System.arraycopy(rows, x, newRows, x + 1, entryCount - x);
}
start += OFFSET_LENGTH;
int offset = (x == 0 ? pageSize : offsets[x - 1]) - rowLength;
if (SysProperties.OPTIMIZE_UPDATE && writtenData) {
if (entryCount > 0) {
byte[] d = data.getBytes();
int dataStart = offsets[entryCount - 1];
int dataEnd = offset;
System.arraycopy(d, dataStart, d, dataStart - rowLength, dataEnd - dataStart + rowLength);
}
index.writeRow(data, offset, row, onlyPosition);
}
offsets = insert(offsets, entryCount, x, offset);
add(offsets, x + 1, entryCount + 1, -rowLength);
rows = insert(rows, entryCount, x, row);
entryCount++;
start += OFFSET_LENGTH;
newOffsets[x] = offset;
newRows[x] = row;
offsets = newOffsets;
rows = newRows;
index.getPageStore().update(this);
memoryChange();
return -1;
}
private void removeRow(int at) {
readAllRows();
if (!SysProperties.OPTIMIZE_UPDATE) {
readAllRows();
}
index.getPageStore().logUndo(this, data);
entryCount--;
written = false;
......@@ -166,19 +172,22 @@ public class PageBtreeLeaf extends PageBtree {
if (entryCount <= 0) {
DbException.throwInternalError();
}
int[] newOffsets = new int[entryCount];
SearchRow[] newRows = new SearchRow[entryCount];
System.arraycopy(offsets, 0, newOffsets, 0, at);
System.arraycopy(rows, 0, newRows, 0, at);
int startNext = at > 0 ? offsets[at - 1] : index.getPageStore().getPageSize();
int rowLength = startNext - offsets[at];
for (int j = at; j < entryCount; j++) {
newOffsets[j] = offsets[j + 1] + rowLength;
}
System.arraycopy(rows, at + 1, newRows, at, entryCount - at);
start -= OFFSET_LENGTH;
offsets = newOffsets;
rows = newRows;
if (SysProperties.OPTIMIZE_UPDATE) {
if (writtenData) {
byte[] d = data.getBytes();
int dataStart = offsets[entryCount];
System.arraycopy(d, dataStart, d, dataStart + rowLength, offsets[at] - dataStart);
Arrays.fill(d, dataStart, dataStart + rowLength, (byte) 0);
}
}
offsets = remove(offsets, entryCount + 1, at);
add(offsets, at, entryCount, rowLength);
rows = remove(rows, entryCount + 1, at);
memoryChange();
}
......@@ -256,13 +265,18 @@ public class PageBtreeLeaf extends PageBtree {
if (written) {
return;
}
readAllRows();
if (!SysProperties.OPTIMIZE_UPDATE) {
readAllRows();
}
writeHead();
for (int i = 0; i < entryCount; i++) {
data.writeShortInt(offsets[i]);
}
for (int i = 0; i < entryCount; i++) {
index.writeRow(data, offsets[i], rows[i], onlyPosition);
if (!writtenData || !SysProperties.OPTIMIZE_UPDATE) {
for (int i = 0; i < entryCount; i++) {
index.writeRow(data, offsets[i], rows[i], onlyPosition);
}
writtenData = true;
}
written = true;
memoryChange();
......@@ -347,7 +361,8 @@ public class PageBtreeLeaf extends PageBtree {
int memory = Constants.MEMORY_PAGE_BTREE + index.getPageStore().getPageSize();
if (rows != null) {
memory += getEntryCount() * (4 + Constants.MEMORY_POINTER);
for (SearchRow r : rows) {
for (int i = 0; i < entryCount; i++) {
SearchRow r = rows[i];
if (r != null) {
memory += r.getMemory();
}
......
......@@ -78,6 +78,7 @@ public class PageBtreeNode extends PageBtree {
p.writeHead();
// 4 bytes for the rightmost child page id
p.start = p.data.length() + 4;
p.rows = SearchRow.EMPTY_ARRAY;
if (SysProperties.PAGE_STORE_INTERNAL_COUNT) {
p.rowCount = 0;
}
......@@ -100,7 +101,7 @@ public class PageBtreeNode extends PageBtree {
entryCount = data.readShortInt();
childPageIds = new int[entryCount + 1];
childPageIds[entryCount] = data.readInt();
rows = PageStore.newSearchRows(entryCount);
rows = entryCount == 0 ? SearchRow.EMPTY_ARRAY : new SearchRow[entryCount];
offsets = Utils.newIntArray(entryCount);
for (int i = 0; i < entryCount; i++) {
childPageIds[i] = data.readInt();
......@@ -158,31 +159,16 @@ public class PageBtreeNode extends PageBtree {
}
}
int offset = last - rowLength;
int[] newOffsets = new int[entryCount + 1];
SearchRow[] newRows = new SearchRow[entryCount + 1];
int[] newChildPageIds = new int[entryCount + 2];
if (childPageIds != null) {
System.arraycopy(childPageIds, 0, newChildPageIds, 0, x + 1);
}
if (entryCount > 0) {
System.arraycopy(offsets, 0, newOffsets, 0, x);
System.arraycopy(rows, 0, newRows, 0, x);
if (x < entryCount) {
for (int j = x; j < entryCount; j++) {
newOffsets[j + 1] = offsets[j] - rowLength;
}
offset = (x == 0 ? pageSize : offsets[x - 1]) - rowLength;
System.arraycopy(rows, x, newRows, x + 1, entryCount - x);
System.arraycopy(childPageIds, x + 1, newChildPageIds, x + 2, entryCount - x);
}
}
newOffsets[x] = offset;
newRows[x] = row;
newChildPageIds[x + 1] = childPageId;
rows = insert(rows, entryCount, x, row);
offsets = insert(offsets, entryCount, x, offset);
add(offsets, x + 1, entryCount + 1, -rowLength);
childPageIds = insert(childPageIds, entryCount + 1, x + 1, childPageId);
start += CHILD_OFFSET_PAIR_LENGTH;
offsets = newOffsets;
rows = newRows;
childPageIds = newChildPageIds;
if (SysProperties.PAGE_STORE_INTERNAL_COUNT) {
if (rowCount != UNKNOWN_ROWCOUNT) {
rowCount += offset;
......@@ -260,7 +246,8 @@ public class PageBtreeNode extends PageBtree {
}
protected void remapChildren() {
for (int child : childPageIds) {
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
PageBtree p = index.getPage(child);
p.setParentPageId(getPos());
index.getPageStore().update(p);
......@@ -277,7 +264,7 @@ public class PageBtreeNode extends PageBtree {
void init(PageBtree page1, SearchRow pivot, PageBtree page2) {
entryCount = 0;
childPageIds = new int[] { page1.getPos() };
rows = new SearchRow[0];
rows = SearchRow.EMPTY_ARRAY;
offsets = Utils.EMPTY_INT_ARRAY;
addChild(0, page2.getPos(), pivot);
if (SysProperties.PAGE_STORE_INTERNAL_COUNT) {
......@@ -365,7 +352,8 @@ public class PageBtreeNode extends PageBtree {
int getRowCount() {
if (rowCount == UNKNOWN_ROWCOUNT) {
int count = 0;
for (int child : childPageIds) {
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
PageBtree page = index.getPage(child);
count += page.getRowCount();
index.getDatabase().setProgress(DatabaseEventListener.STATE_SCAN_FILE, index.getName(), count, Integer.MAX_VALUE);
......@@ -392,9 +380,12 @@ public class PageBtreeNode extends PageBtree {
}
private void check() {
for (int child : childPageIds) {
if (child == 0) {
DbException.throwInternalError();
if (SysProperties.CHECK) {
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
if (child == 0) {
DbException.throwInternalError();
}
}
}
}
......@@ -435,8 +426,9 @@ public class PageBtreeNode extends PageBtree {
void freeRecursive() {
index.getPageStore().logUndo(this, data);
index.getPageStore().free(getPos());
for (int childPageId : childPageIds) {
index.getPage(childPageId).freeRecursive();
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
index.getPage(child).freeRecursive();
}
}
......@@ -451,24 +443,14 @@ public class PageBtreeNode extends PageBtree {
if (entryCount < 0) {
DbException.throwInternalError();
}
SearchRow[] newRows = PageStore.newSearchRows(entryCount);
int[] newOffsets = Utils.newIntArray(entryCount);
int[] newChildPageIds = new int[entryCount + 1];
System.arraycopy(offsets, 0, newOffsets, 0, Math.min(entryCount, i));
System.arraycopy(rows, 0, newRows, 0, Math.min(entryCount, i));
System.arraycopy(childPageIds, 0, newChildPageIds, 0, i);
if (entryCount > i) {
System.arraycopy(rows, i + 1, newRows, i, entryCount - i);
int startNext = i > 0 ? offsets[i - 1] : index.getPageStore().getPageSize();
int rowLength = startNext - offsets[i];
for (int j = i; j < entryCount; j++) {
newOffsets[j] = offsets[j + 1] + rowLength;
}
add(offsets, i, entryCount + 1, rowLength);
}
System.arraycopy(childPageIds, i + 1, newChildPageIds, i, entryCount - i + 1);
offsets = newOffsets;
rows = newRows;
childPageIds = newChildPageIds;
rows = remove(rows, entryCount + 1, i);
offsets = remove(offsets, entryCount + 1, i);
childPageIds = remove(childPageIds, entryCount + 2, i);
start -= CHILD_OFFSET_PAIR_LENGTH;
}
......@@ -481,7 +463,7 @@ public class PageBtreeNode extends PageBtree {
void nextPage(PageBtreeCursor cursor, int pageId) {
int i;
// TODO maybe keep the index in the child page (transiently)
for (i = 0; i < childPageIds.length; i++) {
for (i = 0; i < entryCount + 1; i++) {
if (childPageIds[i] == pageId) {
i++;
break;
......@@ -510,7 +492,7 @@ public class PageBtreeNode extends PageBtree {
void previousPage(PageBtreeCursor cursor, int pageId) {
int i;
// TODO maybe keep the index in the child page (transiently)
for (i = childPageIds.length - 1; i >= 0; i--) {
for (i = entryCount; i >= 0; i--) {
if (childPageIds[i] == pageId) {
i--;
break;
......@@ -560,8 +542,9 @@ public class PageBtreeNode extends PageBtree {
PageBtreeNode n = (PageBtreeNode) p;
n.moveChild(getPos(), newPos);
}
for (int childPageId : childPageIds) {
PageBtree p = index.getPage(childPageId);
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
PageBtree p = index.getPage(child);
p.setParentPageId(newPos);
store.update(p);
}
......@@ -575,7 +558,7 @@ public class PageBtreeNode extends PageBtree {
* @param newPos the new position
*/
void moveChild(int oldPos, int newPos) {
for (int i = 0; i < childPageIds.length; i++) {
for (int i = 0; i < entryCount + 1; i++) {
if (childPageIds[i] == oldPos) {
index.getPageStore().logUndo(this, data);
written = false;
......
......@@ -240,6 +240,4 @@ abstract class PageData extends Page {
return true;
}
}
......@@ -85,6 +85,7 @@ public class PageDataLeaf extends PageData {
static PageDataLeaf create(PageDataIndex index, int pageId, int parentPageId) {
PageDataLeaf p = new PageDataLeaf(index, pageId, index.getPageStore().createData());
index.getPageStore().logUndo(p, null);
p.rows = Row.EMPTY_ARRAY;
p.parentPageId = parentPageId;
p.columnCount = index.getTable().getColumns().length;
p.writeHead();
......@@ -147,7 +148,7 @@ public class PageDataLeaf extends PageData {
private int findInsertionPoint(long key) {
int x = find(key);
if (x < keys.length && keys[x] == key) {
if (x < entryCount && keys[x] == key) {
throw index.getDuplicateKeyException();
}
return x;
......@@ -178,10 +179,6 @@ 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];
Row[] newRows = new Row[entryCount + 1];
int x;
if (entryCount == 0) {
x = 0;
......@@ -190,29 +187,17 @@ public class PageDataLeaf extends PageData {
readAllRows();
}
x = findInsertionPoint(row.getKey());
System.arraycopy(offsets, 0, newOffsets, 0, x);
System.arraycopy(keys, 0, newKeys, 0, x);
System.arraycopy(rows, 0, newRows, 0, x);
if (x < entryCount) {
for (int j = x; j < entryCount; j++) {
newOffsets[j + 1] = offsets[j] - rowLength;
}
System.arraycopy(keys, x, newKeys, x + 1, entryCount - x);
System.arraycopy(rows, x, newRows, x + 1, entryCount - x);
}
}
written = false;
changeCount = index.getPageStore().getChangeCount();
last = x == 0 ? pageSize : offsets[x - 1];
offset = last - rowLength;
entryCount++;
int offset = last - rowLength;
start += keyOffsetPairLen;
newOffsets[x] = offset;
newKeys[x] = row.getKey();
newRows[x] = row;
offsets = newOffsets;
keys = newKeys;
rows = newRows;
offsets = insert(offsets, entryCount, x, offset);
add(offsets, x + 1, entryCount + 1, -rowLength);
keys = insert(keys, entryCount, x, row.getKey());
rows = insert(rows, entryCount, x, row);
entryCount++;
index.getPageStore().update(this);
if (SysProperties.OPTIMIZE_UPDATE) {
if (writtenData && offset >= start) {
......@@ -298,12 +283,6 @@ public class PageDataLeaf extends PageData {
overflowRowSize = 0;
rowRef = null;
int keyOffsetPairLen = 2 + Data.getVarLongLen(keys[i]);
int[] newOffsets = new int[entryCount];
long[] newKeys = new long[entryCount];
Row[] newRows = new Row[entryCount];
System.arraycopy(offsets, 0, newOffsets, 0, i);
System.arraycopy(keys, 0, newKeys, 0, i);
System.arraycopy(rows, 0, newRows, 0, i);
int startNext = i > 0 ? offsets[i - 1] : index.getPageStore().getPageSize();
int rowLength = startNext - offsets[i];
if (SysProperties.OPTIMIZE_UPDATE) {
......@@ -317,15 +296,11 @@ public class PageDataLeaf extends PageData {
int clearStart = offsets[entryCount];
Arrays.fill(data.getBytes(), clearStart, clearStart + rowLength, (byte) 0);
}
for (int j = i; j < entryCount; j++) {
newOffsets[j] = offsets[j + 1] + rowLength;
}
System.arraycopy(keys, i + 1, newKeys, i, entryCount - i);
System.arraycopy(rows, i + 1, newRows, i, entryCount - i);
start -= keyOffsetPairLen;
offsets = newOffsets;
keys = newKeys;
rows = newRows;
offsets = remove(offsets, entryCount + 1, i);
add(offsets, i, entryCount, rowLength);
keys = remove(keys, entryCount + 1, i);
rows = remove(rows, entryCount + 1, i);
}
Cursor find(Session session, long min, long max, boolean multiVersion) {
......
......@@ -114,22 +114,8 @@ public class PageDataNode extends PageData {
index.getPageStore().logUndo(this, data);
written = false;
changeCount = index.getPageStore().getChangeCount();
long[] newKeys = new long[entryCount + 1];
int[] newChildPageIds = new int[entryCount + 2];
if (childPageIds != null) {
System.arraycopy(childPageIds, 0, newChildPageIds, 0, x + 1);
}
if (entryCount > 0) {
System.arraycopy(keys, 0, newKeys, 0, x);
if (x < entryCount) {
System.arraycopy(keys, x, newKeys, x + 1, entryCount - x);
System.arraycopy(childPageIds, x, newChildPageIds, x + 1, entryCount - x + 1);
}
}
newKeys[x] = key;
newChildPageIds[x + 1] = childPageId;
keys = newKeys;
childPageIds = newChildPageIds;
childPageIds = insert(childPageIds, entryCount + 1, x + 1, childPageId);
keys = insert(keys, entryCount, x, key);
entryCount++;
length += 4 + Data.getVarLongLen(key);
}
......@@ -195,7 +181,8 @@ public class PageDataNode extends PageData {
}
protected void remapChildren(int old) {
for (int child : childPageIds) {
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
PageData p = index.getPage(child, old);
p.setParentPageId(getPos());
index.getPageStore().update(p);
......@@ -271,8 +258,9 @@ public class PageDataNode extends PageData {
void freeRecursive() {
index.getPageStore().logUndo(this, data);
index.getPageStore().free(getPos());
for (int childPageId : childPageIds) {
index.getPage(childPageId, getPos()).freeRecursive();
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
index.getPage(child, getPos()).freeRecursive();
}
}
......@@ -285,7 +273,8 @@ public class PageDataNode extends PageData {
int getRowCount() {
if (rowCount == UNKNOWN_ROWCOUNT) {
int count = 0;
for (int child : childPageIds) {
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
PageData page = index.getPage(child, getPos());
if (getPos() == page.getPos()) {
throw DbException.throwInternalError("Page it its own child: " + getPos());
......@@ -312,9 +301,12 @@ public class PageDataNode extends PageData {
}
private void check() {
for (int child : childPageIds) {
if (child == 0) {
DbException.throwInternalError();
if (SysProperties.CHECK) {
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
if (child == 0) {
DbException.throwInternalError();
}
}
}
}
......@@ -360,22 +352,14 @@ public class PageDataNode extends PageData {
index.getPageStore().logUndo(this, data);
written = false;
changeCount = index.getPageStore().getChangeCount();
int removedKeyIndex = i < entryCount ? i : i - 1;
entryCount--;
int removedKeyIndex = i < keys.length ? i : i - 1;
length -= 4 + Data.getVarLongLen(keys[removedKeyIndex]);
if (entryCount < 0) {
DbException.throwInternalError();
}
long[] newKeys = Utils.newLongArray(entryCount);
int[] newChildPageIds = new int[entryCount + 1];
System.arraycopy(keys, 0, newKeys, 0, Math.min(entryCount, i));
System.arraycopy(childPageIds, 0, newChildPageIds, 0, i);
if (entryCount > i) {
System.arraycopy(keys, i + 1, newKeys, i, entryCount - i);
}
System.arraycopy(childPageIds, i + 1, newChildPageIds, i, entryCount - i + 1);
keys = newKeys;
childPageIds = newChildPageIds;
keys = remove(keys, entryCount + 1, removedKeyIndex);
childPageIds = remove(childPageIds, entryCount + 2, i);
}
public String toString() {
......@@ -386,7 +370,8 @@ public class PageDataNode extends PageData {
PageStore store = index.getPageStore();
// load the pages into the cache, to ensure old pages
// are written
for (int child : childPageIds) {
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
store.getPage(child);
}
if (parentPageId != ROOT) {
......@@ -407,7 +392,8 @@ public class PageDataNode extends PageData {
PageDataNode p = (PageDataNode) store.getPage(parentPageId);
p.moveChild(getPos(), newPos);
}
for (int child : childPageIds) {
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
PageData p = (PageData) store.getPage(child);
p.setParentPageId(newPos);
store.update(p);
......@@ -422,7 +408,7 @@ public class PageDataNode extends PageData {
* @param newPos the new position
*/
void moveChild(int oldPos, int newPos) {
for (int i = 0; i < childPageIds.length; i++) {
for (int i = 0; i < entryCount + 1; i++) {
if (childPageIds[i] == oldPos) {
index.getPageStore().logUndo(this, data);
written = false;
......
......@@ -17,6 +17,7 @@ import org.h2.value.Value;
public class Row implements SearchRow {
public static final int MEMORY_CALCULATE = -1;
public static final Row[] EMPTY_ARRAY = {};
private long key;
private final Value[] data;
private final int memory;
......
......@@ -14,6 +14,11 @@ import org.h2.value.Value;
*/
public interface SearchRow {
/**
* An empty array of SearchRow objects.
*/
SearchRow[] EMPTY_ARRAY = {};
/**
* Get the column count.
*
......
......@@ -6,6 +6,7 @@
*/
package org.h2.store;
import java.lang.reflect.Array;
import org.h2.engine.Session;
import org.h2.util.CacheObject;
......@@ -69,6 +70,8 @@ public abstract class Page extends CacheObject {
*/
public static final int TYPE_STREAM_DATA = 8;
private static final int COPY_THRESHOLD = 3;
/**
* When this page was changed the last time.
*/
......@@ -88,4 +91,166 @@ public abstract class Page extends CacheObject {
*/
public abstract void write();
/**
* Insert a value in an array. A new array is created if required.
*
* @param old the old array
* @param oldSize the old size
* @param pos the position
* @param x the value to insert
* @return the (new) array
*/
@SuppressWarnings("unchecked")
public
static <T> T[] insert(T[] old, int oldSize, int pos, T x) {
T[] result;
if (old != null && old.length > oldSize) {
result = old;
} else {
// according to a test, this is as fast as "new Row[..]"
result = (T[]) Array.newInstance(old.getClass().getComponentType(), oldSize + 1 + COPY_THRESHOLD);
if (pos > 0) {
System.arraycopy(old, 0, result, 0, pos);
}
}
if (old != null && oldSize - pos > 0) {
System.arraycopy(old, pos, result, pos + 1, oldSize - pos);
}
result[pos] = x;
return result;
}
/**
* Delete a value in an array. A new array is created if required.
*
* @param old the old array
* @param oldSize the old size
* @param pos the position
* @return the (new) array
*/
@SuppressWarnings("unchecked")
public
static <T> T[] remove(T[] old, int oldSize, int pos) {
T[] result;
if (old.length - oldSize < COPY_THRESHOLD) {
result = old;
} else {
// according to a test, this is as fast as "new Row[..]"
result = (T[]) Array.newInstance(old.getClass().getComponentType(), oldSize - 1);
System.arraycopy(old, 0, result, 0, Math.min(oldSize - 1, pos));
}
if (pos < oldSize) {
System.arraycopy(old, pos + 1, result, pos, oldSize - pos - 1);
}
return result;
}
/**
* Insert a value in an array. A new array is created if required.
*
* @param old the old array
* @param oldSize the old size
* @param pos the position
* @param x the value to insert
* @return the (new) array
*/
protected static long[] insert(long[] old, int oldSize, int pos, long x) {
long[] result;
if (old != null && old.length > oldSize) {
result = old;
} else {
result = new long[oldSize + 1 + COPY_THRESHOLD];
if (pos > 0) {
System.arraycopy(old, 0, result, 0, pos);
}
}
if (old != null && oldSize - pos > 0) {
System.arraycopy(old, pos, result, pos + 1, oldSize - pos);
}
result[pos] = x;
return result;
}
/**
* Delete a value in an array. A new array is created if required.
*
* @param old the old array
* @param oldSize the old size
* @param pos the position
* @return the (new) array
*/
protected static long[] remove(long[] old, int oldSize, int pos) {
long[] result;
if (old.length - oldSize < COPY_THRESHOLD) {
result = old;
} else {
result = new long[oldSize - 1];
System.arraycopy(old, 0, result, 0, pos);
}
System.arraycopy(old, pos + 1, result, pos, oldSize - pos - 1);
return result;
}
/**
* Insert a value in an array. A new array is created if required.
*
* @param old the old array
* @param oldSize the old size
* @param pos the position
* @param x the value to insert
* @return the (new) array
*/
protected static int[] insert(int[] old, int oldSize, int pos, int x) {
int[] result;
if (old != null && old.length > oldSize) {
result = old;
} else {
result = new int[oldSize + 1 + COPY_THRESHOLD];
if (pos > 0 && old != null) {
System.arraycopy(old, 0, result, 0, pos);
}
}
if (old != null && oldSize - pos > 0) {
System.arraycopy(old, pos, result, pos + 1, oldSize - pos);
}
result[pos] = x;
return result;
}
/**
* Delete a value in an array. A new array is created if required.
*
* @param old the old array
* @param oldSize the old size
* @param pos the position
* @return the (new) array
*/
protected static int[] remove(int[] old, int oldSize, int pos) {
int[] result;
if (old.length - oldSize < COPY_THRESHOLD) {
result = old;
} else {
result = new int[oldSize - 1];
System.arraycopy(old, 0, result, 0, Math.min(oldSize - 1, pos));
}
if (pos < oldSize) {
System.arraycopy(old, pos + 1, result, pos, oldSize - pos - 1);
}
return result;
}
/**
* Add a value to a subset of the array.
*
* @param array the array
* @param from the index of the first element (including)
* @param to the index of the last element (excluding)
* @param x the value to add
*/
protected static void add(int[] array, int from, int to, int x) {
for (int i = from; i < to; i++) {
array[i] += x;
}
}
}
......@@ -35,7 +35,6 @@ import org.h2.index.PageIndex;
import org.h2.message.DbException;
import org.h2.message.Trace;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.schema.Schema;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
......@@ -128,7 +127,6 @@ public class PageStore implements CacheWriter {
private static final int META_TYPE_DATA_INDEX = 0;
private static final int META_TYPE_BTREE_INDEX = 1;
private static final int META_TABLE_ID = -1;
private static final SearchRow[] EMPTY_SEARCH_ROW = { };
private static final int COMPACT_BLOCK_SIZE = 1536;
private Database database;
private final Trace trace;
......@@ -1614,19 +1612,6 @@ public class PageStore implements CacheWriter {
}
}
/**
* Create an array of SearchRow with the given size.
*
* @param entryCount the number of elements
* @return the array
*/
public static SearchRow[] newSearchRows(int entryCount) {
if (entryCount == 0) {
return EMPTY_SEARCH_ROW;
}
return new SearchRow[entryCount];
}
/**
* Get the file write count since the database was created.
*
......
......@@ -796,7 +796,9 @@ public abstract class Table extends SchemaObjectBase {
private void fireConstraints(Session session, Row oldRow, Row newRow, boolean before) {
if (constraints != null) {
for (Constraint constraint : constraints) {
// don't use enhanced for loop to avoid creating objects
for (int i = 0; i < constraints.size(); i++) {
Constraint constraint = constraints.get(i);
if (constraint.isBefore() == before) {
constraint.checkRow(session, this, oldRow, newRow);
}
......
......@@ -24,7 +24,7 @@ public class New {
* @return the object
*/
public static <T> ArrayList<T> arrayList() {
return new ArrayList<T>();
return new ArrayList<T>(4);
}
/**
......
......@@ -26,7 +26,11 @@ public class TestBtreeIndex extends TestBase {
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
TestBase test = TestBase.createCaller().init();
test.config.big = true;
test.test();
test.test();
test.test();
}
public void test() throws SQLException {
......@@ -163,7 +167,7 @@ public class TestBtreeIndex extends TestBase {
testCount = 0;
while (rs.next() && rs2.next()) {
if (!rs.getString(1).equals(rs2.getString(1))) {
fail("" + testCount);
assertEquals("" + testCount, rs.getString(1), rs.getString(2));
}
testCount++;
}
......
......@@ -16,6 +16,8 @@ import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import org.h2.api.DatabaseEventListener;
import org.h2.result.Row;
import org.h2.store.Page;
import org.h2.test.TestBase;
import org.h2.util.IOUtils;
......@@ -36,6 +38,7 @@ public class TestPageStore extends TestBase implements DatabaseEventListener {
}
public void test() throws Exception {
testInsertDelete();
testCheckpoint();
testDropRecreate();
testDropAll();
......@@ -61,6 +64,29 @@ public class TestPageStore extends TestBase implements DatabaseEventListener {
deleteDb("pageStore");
}
private void testInsertDelete() {
Row[] x = new Row[0];
Row r = new Row(null, 0);
x = Page.insert(x, 0, 0, r);
assertTrue(x[0] == r);
Row r2 = new Row(null, 0);
x = Page.insert(x, 1, 0, r2);
assertTrue(x[0] == r2);
assertTrue(x[1] == r);
Row r3 = new Row(null, 0);
x = Page.insert(x, 2, 1, r3);
assertTrue(x[0] == r2);
assertTrue(x[1] == r3);
assertTrue(x[2] == r);
x = Page.remove(x, 3, 1);
assertTrue(x[0] == r2);
assertTrue(x[1] == r);
x = Page.remove(x, 2, 0);
assertTrue(x[0] == r);
x = Page.remove(x, 1, 0);
}
private void testCheckpoint() throws SQLException {
deleteDb("pageStore");
Connection conn;
......
......@@ -51,8 +51,8 @@ public class TestUtils extends TestBase {
testGetNonPrimitiveClass(Void.class, void.class);
}
private void testGetNonPrimitiveClass(Class<?> expected, Class<?> prim) {
assertEquals(expected.getName(), Utils.getNonPrimitiveClass(prim).getName());
private void testGetNonPrimitiveClass(Class<?> expected, Class<?> p) {
assertEquals(expected.getName(), Utils.getNonPrimitiveClass(p).getName());
}
private void testReflectionUtils() throws Exception {
......
......@@ -653,4 +653,4 @@ iml unified regclass netbeans geqo servername creator eclipsecs cacheable
stacked unable seeking underflow violations evaluates repeats minimalistic
licensing appreciate textbook diligence undergraduate afaik mathematics chris
arrangements bugfix premain longs majority crashing behaving inst inventor
javaagent park accurately adopt consists night equally
javaagent park accurately adopt consists night equally enhance enhanced
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论