提交 6bdaf52a authored 作者: Thomas Mueller's avatar Thomas Mueller

New experimental page store.

上级 37acb1ff
...@@ -94,9 +94,10 @@ abstract class PageBtree extends Record { ...@@ -94,9 +94,10 @@ abstract class PageBtree extends Record {
* @param compare the row * @param compare the row
* @param bigger if looking for a larger row * @param bigger if looking for a larger row
* @param add if the row should be added (check for duplicate keys) * @param add if the row should be added (check for duplicate keys)
* @param compareKeys compare the row keys as well
* @return the index of the found row * @return the index of the found row
*/ */
int find(SearchRow compare, boolean bigger, boolean add) throws SQLException { int find(SearchRow compare, boolean bigger, boolean add, boolean compareKeys) throws SQLException {
if (compare == null) { if (compare == null) {
return 0; return 0;
} }
...@@ -106,13 +107,18 @@ abstract class PageBtree extends Record { ...@@ -106,13 +107,18 @@ abstract class PageBtree extends Record {
int i = (l + r) >>> 1; int i = (l + r) >>> 1;
SearchRow row = getRow(i); SearchRow row = getRow(i);
comp = index.compareRows(row, compare); comp = index.compareRows(row, compare);
if (comp == 0 && add) { if (comp == 0) {
if (index.indexType.isUnique()) { if (add && index.indexType.isUnique()) {
if (!index.containsNullAndAllowMultipleNull(compare)) { if (!index.containsNullAndAllowMultipleNull(compare)) {
throw index.getDuplicateKeyException(); throw index.getDuplicateKeyException();
} }
} }
comp = index.compareKeys(row, compare); if (compareKeys) {
comp = index.compareKeys(row, compare);
if (comp == 0) {
return i;
}
}
} }
if (comp > 0 || (!bigger && comp == 0)) { if (comp > 0 || (!bigger && comp == 0)) {
r = i; r = i;
...@@ -129,12 +135,13 @@ abstract class PageBtree extends Record { ...@@ -129,12 +135,13 @@ abstract class PageBtree extends Record {
abstract void read() throws SQLException; abstract void read() throws SQLException;
/** /**
* Try to add a row. * Add a row if possible. If it is possible this method returns -1, otherwise
* the split point. It is always possible to add one row.
* *
* @param row the row * @param row the row to add
* @return 0 if successful, or the split position if the page needs to be * @return the split point of this page, or -1 if no split is required
* split
*/ */
abstract int addRowTry(SearchRow row) throws SQLException; abstract int addRowTry(SearchRow row) throws SQLException;
/** /**
...@@ -221,9 +228,11 @@ abstract class PageBtree extends Record { ...@@ -221,9 +228,11 @@ abstract class PageBtree extends Record {
* Remove a row. * Remove a row.
* *
* @param row the row to remove * @param row the row to remove
* @return true if this page is now empty * @return null if the last row didn't change,
* the deleted row if the page is now empty,
* otherwise the new last row of this page
*/ */
abstract boolean remove(SearchRow row) throws SQLException; abstract SearchRow remove(SearchRow row) throws SQLException;
/** /**
* Free up all child pages. * Free up all child pages.
......
...@@ -87,7 +87,7 @@ public class PageBtreeIndex extends BaseIndex { ...@@ -87,7 +87,7 @@ public class PageBtreeIndex extends BaseIndex {
while (true) { while (true) {
PageBtree root = getPage(headPos); PageBtree root = getPage(headPos);
int splitPoint = root.addRowTry(newRow); int splitPoint = root.addRowTry(newRow);
if (splitPoint == 0) { if (splitPoint == -1) {
break; break;
} }
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
......
...@@ -54,20 +54,13 @@ class PageBtreeLeaf extends PageBtree { ...@@ -54,20 +54,13 @@ class PageBtreeLeaf extends PageBtree {
start = data.length(); start = data.length();
} }
/**
* Add a row if possible. If it is possible this method returns 0, otherwise
* the split point. It is always possible to add one row.
*
* @param row the now to add
* @return the split point of this page, or 0 if no split is required
*/
int addRowTry(SearchRow row) throws SQLException { int addRowTry(SearchRow row) throws SQLException {
int rowLength = index.getRowSize(data, row, onlyPosition); int rowLength = index.getRowSize(data, row, onlyPosition);
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];
if (last - rowLength < start + OFFSET_LENGTH) { if (last - rowLength < start + OFFSET_LENGTH) {
if (entryCount > 1) { if (entryCount > 1) {
return (entryCount / 2) + 1; return entryCount / 2;
} }
onlyPosition = true; onlyPosition = true;
// change the offsets (now storing only positions) // change the offsets (now storing only positions)
...@@ -91,7 +84,7 @@ class PageBtreeLeaf extends PageBtree { ...@@ -91,7 +84,7 @@ class PageBtreeLeaf extends PageBtree {
x = 0; x = 0;
} else { } else {
readAllRows(); readAllRows();
x = find(row, false, true); x = find(row, false, true, true);
System.arraycopy(offsets, 0, newOffsets, 0, x); System.arraycopy(offsets, 0, newOffsets, 0, x);
System.arraycopy(rows, 0, newRows, 0, x); System.arraycopy(rows, 0, newRows, 0, x);
if (x < entryCount) { if (x < entryCount) {
...@@ -109,7 +102,7 @@ class PageBtreeLeaf extends PageBtree { ...@@ -109,7 +102,7 @@ class PageBtreeLeaf extends PageBtree {
offsets = newOffsets; offsets = newOffsets;
rows = newRows; rows = newRows;
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this, true, data);
return 0; return -1;
} }
private void removeRow(int i) throws SQLException { private void removeRow(int i) throws SQLException {
...@@ -156,17 +149,24 @@ class PageBtreeLeaf extends PageBtree { ...@@ -156,17 +149,24 @@ class PageBtreeLeaf extends PageBtree {
return this; return this;
} }
boolean remove(SearchRow row) throws SQLException { SearchRow remove(SearchRow row) throws SQLException {
int at = find(row, false, false); int at = find(row, false, false, true);
if (index.compareRows(row, getRow(at)) != 0) { SearchRow delete = getRow(at);
if (index.compareRows(row, delete) != 0 || delete.getPos() != row.getPos()) {
throw Message.getSQLException(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, index.getSQL() + ": " + row); throw Message.getSQLException(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, index.getSQL() + ": " + row);
} }
if (entryCount == 1) { if (entryCount == 1) {
return true; // the page is now empty
return row;
} }
removeRow(at); removeRow(at);
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this, true, data);
return false; if (at == entryCount) {
// the last row changed
return getRow(at - 1);
}
// the last row didn't change
return null;
} }
void freeChildren() { void freeChildren() {
...@@ -210,7 +210,7 @@ class PageBtreeLeaf extends PageBtree { ...@@ -210,7 +210,7 @@ class PageBtreeLeaf extends PageBtree {
} }
void find(PageBtreeCursor cursor, SearchRow first, boolean bigger) throws SQLException { void find(PageBtreeCursor cursor, SearchRow first, boolean bigger) throws SQLException {
int i = find(first, bigger, false); int i = find(first, bigger, false, false);
if (i > entryCount) { if (i > entryCount) {
if (parentPageId == Page.ROOT) { if (parentPageId == Page.ROOT) {
return; return;
......
...@@ -16,16 +16,18 @@ import org.h2.store.PageStore; ...@@ -16,16 +16,18 @@ import org.h2.store.PageStore;
import org.h2.util.MemoryUtils; import org.h2.util.MemoryUtils;
/** /**
* A b-tree node page that contains index data. * A b-tree node page that contains index data. Data is organized as follows:
* Data is organized as follows: [leaf 0] (largest value of leaf 0) [leaf 1] * [leaf 0] (largest value of leaf 0) [leaf 1] Format:
* Format: * <ul>
* <ul><li>0-3: parent page id * <li>0-3: parent page id</li>
* </li><li>4-4: page type * <li>4-4: page type</li>
* </li><li>5-6: entry count * <li>5-6: entry count</li>
* </li><li>7-10: row count of all children (-1 if not known) * <li>7-10: row count of all children (-1 if not known)</li>
* </li><li>11-14: rightmost child page id * <li>11-14: rightmost child page id</li>
* </li><li>15- entries: 4 bytes leaf page id, 4 bytes offset to data * <li>15- entries: 4 bytes leaf page id, 4 bytes offset to data</li>
* </li></ul> * </ul>
* The row is the largest row of the respective child, meaning
* row[0] is the largest row of child[0].
*/ */
class PageBtreeNode extends PageBtree { class PageBtreeNode extends PageBtree {
...@@ -37,7 +39,7 @@ class PageBtreeNode extends PageBtree { ...@@ -37,7 +39,7 @@ class PageBtreeNode extends PageBtree {
*/ */
private int[] childPageIds; private int[] childPageIds;
// private int rowCountStored = UNKNOWN_ROWCOUNT; // private int rowCountStored = UNKNOWN_ROWCOUNT;
private int rowCount = UNKNOWN_ROWCOUNT; private int rowCount = UNKNOWN_ROWCOUNT;
...@@ -67,25 +69,32 @@ class PageBtreeNode extends PageBtree { ...@@ -67,25 +69,32 @@ class PageBtreeNode extends PageBtree {
start = data.length(); start = data.length();
} }
/**
* Add a row. If it is possible this method returns -1, otherwise
* the split point. It is always possible to two rows.
*
* @param row the now to add
* @return the split point of this page, or -1 if no split is required
*/
private int addChildTry(SearchRow row) throws SQLException { private int addChildTry(SearchRow row) throws SQLException {
if (entryCount < 2) { if (entryCount < 2) {
return 0; return -1;
} }
int rowLength = index.getRowSize(data, row, onlyPosition); int rowLength = index.getRowSize(data, row, onlyPosition);
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];
if (last - rowLength < start + CHILD_OFFSET_PAIR_LENGTH) { if (last - rowLength < start + CHILD_OFFSET_PAIR_LENGTH) {
return (entryCount / 2) + 1; return entryCount / 2;
} }
return 0; return -1;
} }
/** /**
* Add a row. If it is possible this method returns 0, otherwise * Add a child at the given position.
* the split point. It is always possible to add one row.
* *
* @param row the now to add * @param x the position
* @return the split point of this page, or 0 if no split is required * @param childPageId the child
* @param row the row smaller than the first row of the child and its children
*/ */
private void addChild(int x, int childPageId, SearchRow row) throws SQLException { private void addChild(int x, int childPageId, SearchRow row) throws SQLException {
int rowLength = index.getRowSize(data, row, onlyPosition); int rowLength = index.getRowSize(data, row, onlyPosition);
...@@ -136,15 +145,15 @@ class PageBtreeNode extends PageBtree { ...@@ -136,15 +145,15 @@ class PageBtreeNode extends PageBtree {
int addRowTry(SearchRow row) throws SQLException { int addRowTry(SearchRow row) throws SQLException {
while (true) { while (true) {
int x = find(row, false, false); int x = find(row, false, true, true);
PageBtree page = index.getPage(childPageIds[x]); PageBtree page = index.getPage(childPageIds[x]);
int splitPoint = page.addRowTry(row); int splitPoint = page.addRowTry(row);
if (splitPoint == 0) { if (splitPoint == -1) {
break; break;
} }
SearchRow pivot = page.getRow(splitPoint - 1); SearchRow pivot = page.getRow(splitPoint - 1);
int splitPoint2 = addChildTry(pivot); int splitPoint2 = addChildTry(pivot);
if (splitPoint2 != 0) { if (splitPoint2 != -1) {
return splitPoint2; return splitPoint2;
} }
PageBtree page2 = page.split(splitPoint); PageBtree page2 = page.split(splitPoint);
...@@ -156,7 +165,7 @@ class PageBtreeNode extends PageBtree { ...@@ -156,7 +165,7 @@ class PageBtreeNode extends PageBtree {
} }
updateRowCount(1); updateRowCount(1);
written = false; written = false;
return 0; return -1;
} }
private void updateRowCount(int offset) { private void updateRowCount(int offset) {
...@@ -215,7 +224,7 @@ class PageBtreeNode extends PageBtree { ...@@ -215,7 +224,7 @@ class PageBtreeNode extends PageBtree {
} }
void find(PageBtreeCursor cursor, SearchRow first, boolean bigger) throws SQLException { void find(PageBtreeCursor cursor, SearchRow first, boolean bigger) throws SQLException {
int i = find(first, bigger, false); int i = find(first, bigger, false, false);
if (i > entryCount) { if (i > entryCount) {
if (parentPageId == Page.ROOT) { if (parentPageId == Page.ROOT) {
return; return;
...@@ -243,26 +252,48 @@ class PageBtreeNode extends PageBtree { ...@@ -243,26 +252,48 @@ class PageBtreeNode extends PageBtree {
return index.getPage(child).getLastLeaf(); return index.getPage(child).getLastLeaf();
} }
boolean remove(SearchRow row) throws SQLException { SearchRow remove(SearchRow row) throws SQLException {
int at = find(row, false, false); int at = find(row, false, false, true);
// merge is not implemented to allow concurrent usage // merge is not implemented to allow concurrent usage
// TODO maybe implement merge // TODO maybe implement merge
PageBtree page = index.getPage(childPageIds[at]); PageBtree page = index.getPage(childPageIds[at]);
boolean empty = page.remove(row); SearchRow last = page.remove(row);
updateRowCount(-1); updateRowCount(-1);
if (!empty) { if (last == null) {
// the first row didn't change - nothing to do // the last row didn't change - nothing to do
return false; return null;
} else if (last == row) {
// this child is now empty
index.getPageStore().freePage(page.getPos(), true, page.data);
if (entryCount < 1) {
// no more children - this page is empty as well
return row;
}
if (at == entryCount) {
// removing the last child
last = getRow(at - 1);
} else {
last = null;
}
removeChild(at);
index.getPageStore().updateRecord(this, true, data);
return last;
} }
// this child is now empty // the last row is in the last child
index.getPageStore().freePage(page.getPos(), true, page.data); if (at == entryCount) {
if (entryCount < 1) { return last;
// no more children - this page is empty as well
return true;
} }
int child = childPageIds[at];
removeChild(at); removeChild(at);
// TODO this can mean only the position is now stored
// should split at the next possible moment
addChild(at, child, last);
// remove and add swapped two children, fix that
int temp = childPageIds[at];
childPageIds[at] = childPageIds[at + 1];
childPageIds[at + 1] = temp;
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this, true, data);
return false; return null;
} }
int getRowCount() throws SQLException { int getRowCount() throws SQLException {
...@@ -420,5 +451,4 @@ class PageBtreeNode extends PageBtree { ...@@ -420,5 +451,4 @@ class PageBtreeNode extends PageBtree {
return "page[" + getPos() + "] b-tree node table:" + index.getId() + " entries:" + entryCount; return "page[" + getPos() + "] b-tree node table:" + index.getId() + " entries:" + entryCount;
} }
} }
\ No newline at end of file
...@@ -84,10 +84,10 @@ abstract class PageData extends Record { ...@@ -84,10 +84,10 @@ abstract class PageData extends Record {
while (l < r) { while (l < r) {
int i = (l + r) >>> 1; int i = (l + r) >>> 1;
int k = keys[i]; int k = keys[i];
if (k > key) { if (k == key) {
r = i;
} else if (k == key) {
return i; return i;
} else if (k > key) {
r = i;
} else { } else {
l = i + 1; l = i + 1;
} }
...@@ -101,11 +101,11 @@ abstract class PageData extends Record { ...@@ -101,11 +101,11 @@ abstract class PageData extends Record {
abstract void read() throws SQLException; abstract void read() throws SQLException;
/** /**
* Try to add a row. * Add a row if possible. If it is possible this method returns -1, otherwise
* the split point. It is always possible to add one row.
* *
* @param row the row * @param row the now to add
* @return 0 if successful, or the split position if the page needs to be * @return the split point of this page, or -1 if no split is required
* split
*/ */
abstract int addRowTry(Row row) throws SQLException; abstract int addRowTry(Row row) throws SQLException;
......
...@@ -92,19 +92,20 @@ class PageDataLeaf extends PageData { ...@@ -92,19 +92,20 @@ class PageDataLeaf extends PageData {
start = data.length(); start = data.length();
} }
/**
* Add a row if possible. If it is possible this method returns 0, otherwise
* the split point. It is always possible to add one row.
*
* @param row the now to add
* @return the split point of this page, or 0 if no split is required
*/
int addRowTry(Row row) throws SQLException { int addRowTry(Row row) throws SQLException {
int rowLength = row.getByteCount(data); int rowLength = row.getByteCount(data);
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];
if (entryCount > 0 && last - rowLength < start + KEY_OFFSET_PAIR_LENGTH) { if (entryCount > 0 && last - rowLength < start + KEY_OFFSET_PAIR_LENGTH) {
return (entryCount / 2) + 1; if (entryCount > 1) {
return entryCount / 2;
}
int todoIncorrect;
if (find(row.getPos()) != 1) {
System.out.println("todo " + find(row.getPos()));
}
return 1; // find(row.getPos()) + 1;
} }
int offset = last - rowLength; int offset = last - rowLength;
int[] newOffsets = new int[entryCount + 1]; int[] newOffsets = new int[entryCount + 1];
...@@ -181,7 +182,7 @@ class PageDataLeaf extends PageData { ...@@ -181,7 +182,7 @@ class PageDataLeaf extends PageData {
} while (remaining > 0); } while (remaining > 0);
data.truncate(index.getPageStore().getPageSize()); data.truncate(index.getPageStore().getPageSize());
} }
return 0; return -1;
} }
private void removeRow(int i) throws SQLException { private void removeRow(int i) throws SQLException {
......
...@@ -25,6 +25,8 @@ import org.h2.util.MemoryUtils; ...@@ -25,6 +25,8 @@ import org.h2.util.MemoryUtils;
* </li><li>11-14: rightmost child page id * </li><li>11-14: rightmost child page id
* </li><li>15- entries: 4 bytes leaf page id, 4 bytes key * </li><li>15- entries: 4 bytes leaf page id, 4 bytes key
* </li></ul> * </li></ul>
* The key is the largest key of the respective child, meaning
* key[0] is the largest key of child[0].
*/ */
class PageDataNode extends PageData { class PageDataNode extends PageData {
...@@ -85,14 +87,14 @@ class PageDataNode extends PageData { ...@@ -85,14 +87,14 @@ class PageDataNode extends PageData {
int x = find(row.getPos()); int x = find(row.getPos());
PageData page = index.getPage(childPageIds[x], getPos()); PageData page = index.getPage(childPageIds[x], getPos());
int splitPoint = page.addRowTry(row); int splitPoint = page.addRowTry(row);
if (splitPoint == 0) { if (splitPoint == -1) {
break; break;
} }
int maxEntries = (index.getPageStore().getPageSize() - ENTRY_START) / ENTRY_LENGTH; int maxEntries = (index.getPageStore().getPageSize() - ENTRY_START) / ENTRY_LENGTH;
if (entryCount >= maxEntries) { if (entryCount >= maxEntries) {
return entryCount / 2; return entryCount / 2;
} }
int pivot = page.getKey(splitPoint - 1); int pivot = splitPoint == 0 ? row.getPos() : 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, true, page.data);
index.getPageStore().updateRecord(page2, true, page2.data); index.getPageStore().updateRecord(page2, true, page2.data);
...@@ -100,7 +102,7 @@ class PageDataNode extends PageData { ...@@ -100,7 +102,7 @@ class PageDataNode extends PageData {
index.getPageStore().updateRecord(this, true, data); index.getPageStore().updateRecord(this, true, data);
} }
updateRowCount(1); updateRowCount(1);
return 0; return -1;
} }
private void updateRowCount(int offset) throws SQLException { private void updateRowCount(int offset) throws SQLException {
......
...@@ -115,13 +115,13 @@ public class PageScanIndex extends BaseIndex implements RowIndex { ...@@ -115,13 +115,13 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
while (true) { while (true) {
PageData root = getPage(headPos, 0); PageData root = getPage(headPos, 0);
int splitPoint = root.addRowTry(row); int splitPoint = root.addRowTry(row);
if (splitPoint == 0) { if (splitPoint == -1) {
break; break;
} }
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("split " + splitPoint); trace.debug("split " + splitPoint);
} }
int pivot = root.getKey(splitPoint - 1); int pivot = splitPoint == 0 ? row.getPos() : root.getKey(splitPoint - 1);
PageData page1 = root; PageData page1 = root;
PageData page2 = root.split(splitPoint); PageData page2 = root.split(splitPoint);
int rootPageId = root.getPos(); int rootPageId = root.getPos();
......
...@@ -216,10 +216,13 @@ public class PageLog { ...@@ -216,10 +216,13 @@ public class PageLog {
int pageId = in.readInt(); int pageId = in.readInt();
in.readFully(data.getBytes(), 0, store.getPageSize()); in.readFully(data.getBytes(), 0, store.getPageSize());
if (stage == RECOVERY_STAGE_UNDO) { if (stage == RECOVERY_STAGE_UNDO) {
if (trace.isDebugEnabled()) { if (!undo.get(pageId)) {
trace.debug("log undo " + pageId); if (trace.isDebugEnabled()) {
trace.debug("log undo " + pageId);
}
store.writePage(pageId, data);
undo.set(pageId);
} }
store.writePage(pageId, data);
} }
} else if (x == ADD || x == REMOVE) { } else if (x == ADD || x == REMOVE) {
int sessionId = in.readInt(); int sessionId = in.readInt();
...@@ -288,6 +291,7 @@ public class PageLog { ...@@ -288,6 +291,7 @@ public class PageLog {
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, "recover"); throw Message.convertIOException(e, "recover");
} }
undo = new BitField();
} }
/** /**
......
...@@ -103,6 +103,7 @@ public class PageStore implements CacheWriter { ...@@ -103,6 +103,7 @@ public class PageStore implements CacheWriter {
// TODO update: only log the key and changed values // TODO update: only log the key and changed values
// TODO store dates differently in Data; test moving db to another timezone // TODO store dates differently in Data; test moving db to another timezone
// TODO online backup using bsdiff // TODO online backup using bsdiff
// TODO trying to insert duplicate key can split a page: not in recovery
// TODO when removing DiskFile: // TODO when removing DiskFile:
// remove CacheObject.blockCount // remove CacheObject.blockCount
......
...@@ -295,8 +295,6 @@ java org.h2.test.TestAll timer ...@@ -295,8 +295,6 @@ java org.h2.test.TestAll timer
/* /*
page store: TestBtreeIndex
------------- -------------
create a short documentation create a short documentation
......
...@@ -41,24 +41,27 @@ public class TestBtreeIndex extends TestBase { ...@@ -41,24 +41,27 @@ public class TestBtreeIndex extends TestBase {
private void testAddDelete() throws SQLException { private void testAddDelete() throws SQLException {
deleteDb("index"); deleteDb("index");
Connection conn = getConnection("index"); Connection conn = getConnection("index");
Statement stat = conn.createStatement(); try {
stat.execute("CREATE TABLE TEST(ID bigint primary key)"); Statement stat = conn.createStatement();
int count = 1000; stat.execute("CREATE TABLE TEST(ID bigint primary key)");
stat.execute("insert into test select x from system_range(1, " + count + ")"); int count = 1000;
if (!config.memory) { stat.execute("insert into test select x from system_range(1, " + count + ")");
conn.close(); if (!config.memory) {
conn = getConnection("index"); conn.close();
stat = conn.createStatement(); conn = getConnection("index");
} stat = conn.createStatement();
for (int i = 1; i < count; i++) {
ResultSet rs = stat.executeQuery("select * from test order by id");
for (int j = i; rs.next(); j++) {
assertEquals(j, rs.getInt(1));
} }
stat.execute("delete from test where id =" + i); for (int i = 1; i < count; i++) {
ResultSet rs = stat.executeQuery("select * from test order by id");
for (int j = i; rs.next(); j++) {
assertEquals(j, rs.getInt(1));
}
stat.execute("delete from test where id =" + i);
}
stat.execute("drop all objects delete files");
} finally {
conn.close();
} }
stat.execute("drop all objects delete files");
conn.close();
} }
public void testCase(int seed) throws SQLException { public void testCase(int seed) throws SQLException {
...@@ -92,75 +95,78 @@ public class TestBtreeIndex extends TestBase { ...@@ -92,75 +95,78 @@ public class TestBtreeIndex extends TestBase {
String prefix = buff.toString(); String prefix = buff.toString();
DeleteDbFiles.execute(baseDir, null, true); DeleteDbFiles.execute(baseDir, null, true);
Connection conn = getConnection("index"); Connection conn = getConnection("index");
Statement stat = conn.createStatement(); try {
stat.execute("CREATE TABLE a(text VARCHAR PRIMARY KEY)"); Statement stat = conn.createStatement();
PreparedStatement prepInsert = conn.prepareStatement("INSERT INTO a VALUES(?)"); stat.execute("CREATE TABLE a(text VARCHAR PRIMARY KEY)");
PreparedStatement prepDelete = conn.prepareStatement("DELETE FROM a WHERE text=?"); PreparedStatement prepInsert = conn.prepareStatement("INSERT INTO a VALUES(?)");
PreparedStatement prepDeleteAllButOne = conn.prepareStatement("DELETE FROM a WHERE text <> ?"); PreparedStatement prepDelete = conn.prepareStatement("DELETE FROM a WHERE text=?");
int count = 0; PreparedStatement prepDeleteAllButOne = conn.prepareStatement("DELETE FROM a WHERE text <> ?");
for (int i = 0; i < 1000; i++) { int count = 0;
int y = random.nextInt(distinct); for (int i = 0; i < 1000; i++) {
try { int y = random.nextInt(distinct);
prepInsert.setString(1, prefix + y); try {
prepInsert.executeUpdate(); prepInsert.setString(1, prefix + y);
count++; prepInsert.executeUpdate();
} catch (SQLException e) { count++;
if (e.getSQLState().equals("23001")) { } catch (SQLException e) {
// ignore if (e.getSQLState().equals("23001")) {
} else { // ignore
TestBase.logError("error", e); } else {
break;
}
}
if (delete && random.nextInt(10) == 1) {
if (random.nextInt(4) == 1) {
try {
prepDeleteAllButOne.setString(1, prefix + y);
int deleted = prepDeleteAllButOne.executeUpdate();
if (deleted < count - 1) {
printError(seed, "deleted:" + deleted);
}
count -= deleted;
} catch (SQLException e) {
TestBase.logError("error", e); TestBase.logError("error", e);
break; break;
} }
} else { }
try { if (delete && random.nextInt(10) == 1) {
prepDelete.setString(1, prefix + y); if (random.nextInt(4) == 1) {
int deleted = prepDelete.executeUpdate(); try {
if (deleted > 1) { prepDeleteAllButOne.setString(1, prefix + y);
printError(seed, "deleted:" + deleted); int deleted = prepDeleteAllButOne.executeUpdate();
if (deleted < count - 1) {
printError(seed, "deleted:" + deleted + " i:" + i);
}
count -= deleted;
} catch (SQLException e) {
TestBase.logError("error", e);
break;
}
} else {
try {
prepDelete.setString(1, prefix + y);
int deleted = prepDelete.executeUpdate();
if (deleted > 1) {
printError(seed, "deleted:" + deleted + " i:" + i);
}
count -= deleted;
} catch (SQLException e) {
TestBase.logError("error", e);
break;
} }
count -= deleted;
} catch (SQLException e) {
TestBase.logError("error", e);
break;
} }
} }
} }
} int testCount;
int testCount; testCount = 0;
testCount = 0; ResultSet rs = stat.executeQuery("SELECT text FROM a ORDER BY text");
ResultSet rs = stat.executeQuery("SELECT text FROM a ORDER BY text"); ResultSet rs2 = conn.createStatement().executeQuery("SELECT text FROM a ORDER BY 'x' || text");
ResultSet rs2 = conn.createStatement().executeQuery("SELECT text FROM a ORDER BY 'x' || text"); testCount = 0;
testCount = 0; while (rs.next() && rs2.next()) {
while (rs.next() && rs2.next()) { if (!rs.getString(1).equals(rs2.getString(1))) {
if (!rs.getString(1).equals(rs2.getString(1))) { fail("" + testCount);
fail("" + testCount); }
testCount++;
} }
testCount++; assertFalse(rs.next());
} assertFalse(rs2.next());
assertFalse(rs.next()); if (testCount != count) {
assertFalse(rs2.next()); printError(seed, "count:" + count + " testCount:" + testCount);
if (testCount != count) { }
printError(seed, "count:" + count + " testCount:" + testCount); rs = stat.executeQuery("SELECT text, count(*) FROM a GROUP BY text HAVING COUNT(*)>1");
} if (rs.next()) {
rs = stat.executeQuery("SELECT text, count(*) FROM a GROUP BY text HAVING COUNT(*)>1"); printError(seed, "testCount:" + testCount + " " + rs.getString(1));
if (rs.next()) { }
printError(seed, "testCount:" + testCount); } finally {
conn.close();
} }
conn.close();
} }
private void printError(int seed, String message) { private void printError(int seed, String message) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论