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

Page store: opening a large database was slow if it was not closed before.

上级 2460e391
...@@ -18,7 +18,8 @@ Change Log ...@@ -18,7 +18,8 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>Page store: new write and read counters in the meta data table. Use <ul><li>Page store: opening a large database was slow if it was not closed before.
</li><li>Page store: new write and read counters in the meta data table. Use
SELECT * FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME IN( SELECT * FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME IN(
'info.FILE_WRITE_TOTAL', 'info.FILE_WRITE', 'info.FILE_READ', 'info.FILE_WRITE_TOTAL', 'info.FILE_WRITE', 'info.FILE_READ',
'info.CACHE_MAX_SIZE', 'info.CACHE_SIZE') 'info.CACHE_MAX_SIZE', 'info.CACHE_SIZE')
......
...@@ -18,7 +18,7 @@ import java.util.EventListener; ...@@ -18,7 +18,7 @@ import java.util.EventListener;
public interface DatabaseEventListener extends EventListener { public interface DatabaseEventListener extends EventListener {
/** /**
* This state is used when scanning the data or index file. * This state is used when scanning the database file.
*/ */
int STATE_SCAN_FILE = 0; int STATE_SCAN_FILE = 0;
......
...@@ -89,7 +89,6 @@ public abstract class PageBtree extends Page { ...@@ -89,7 +89,6 @@ public abstract class PageBtree extends Page {
* *
* @param rowCount the stored row count * @param rowCount the stored row count
*/ */
// TODO remove
abstract void setRowCountStored(int rowCount) throws SQLException; abstract void setRowCountStored(int rowCount) throws SQLException;
/** /**
......
...@@ -18,6 +18,7 @@ import org.h2.store.PageStore; ...@@ -18,6 +18,7 @@ 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;
import org.h2.table.TableData; import org.h2.table.TableData;
import org.h2.util.MathUtils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueLob; import org.h2.value.ValueLob;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -100,6 +101,7 @@ public class PageBtreeIndex extends PageIndex { ...@@ -100,6 +101,7 @@ public class PageBtreeIndex extends PageIndex {
store.update(newRoot); store.update(newRoot);
root = newRoot; root = newRoot;
} }
invalidateRowCount();
rowCount++; rowCount++;
} }
...@@ -217,6 +219,7 @@ public class PageBtreeIndex extends PageIndex { ...@@ -217,6 +219,7 @@ public class PageBtreeIndex extends PageIndex {
} else { } else {
PageBtree root = getPage(rootPageId); PageBtree root = getPage(rootPageId);
root.remove(row); root.remove(row);
invalidateRowCount();
rowCount--; rowCount--;
} }
} }
...@@ -275,14 +278,16 @@ public class PageBtreeIndex extends PageIndex { ...@@ -275,14 +278,16 @@ public class PageBtreeIndex extends PageIndex {
} }
public long getRowCount(Session session) { public long getRowCount(Session session) {
return tableData.getRowCount(session); return rowCount;
} }
public void close(Session session) { public void close(Session session) throws SQLException {
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("close"); trace.debug("close");
} }
// TODO write the row count // can not close the index because it might get used afterwards,
// for example after running recovery
writeRowCount();
} }
/** /**
...@@ -363,4 +368,14 @@ public class PageBtreeIndex extends PageIndex { ...@@ -363,4 +368,14 @@ public class PageBtreeIndex extends PageIndex {
store.addIndex(this); store.addIndex(this);
} }
private void invalidateRowCount() throws SQLException {
PageBtree root = getPage(rootPageId);
root.setRowCountStored(PageData.UNKNOWN_ROWCOUNT);
}
public void writeRowCount() throws SQLException {
PageBtree root = getPage(rootPageId);
root.setRowCountStored(MathUtils.convertLongToInt(rowCount));
}
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
package org.h2.index; package org.h2.index;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.api.DatabaseEventListener;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -41,7 +42,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -41,7 +42,7 @@ public 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;
...@@ -93,11 +94,8 @@ public class PageBtreeNode extends PageBtree { ...@@ -93,11 +94,8 @@ public class PageBtreeNode extends PageBtree {
"page:" + getPos() + " expected index:" + index.getId() + "page:" + getPos() + " expected index:" + index.getId() +
"got:" + indexId); "got:" + indexId);
} }
rowCount = data.readInt(); rowCount = rowCountStored = data.readInt();
entryCount = data.readShortInt(); entryCount = data.readShortInt();
if (!PageStore.STORE_BTREE_ROWCOUNT) {
rowCount = UNKNOWN_ROWCOUNT;
}
childPageIds = new int[entryCount + 1]; childPageIds = new int[entryCount + 1];
childPageIds[entryCount] = data.readInt(); childPageIds[entryCount] = data.readInt();
rows = PageStore.newSearchRows(entryCount); rows = PageStore.newSearchRows(entryCount);
...@@ -213,10 +211,18 @@ public class PageBtreeNode extends PageBtree { ...@@ -213,10 +211,18 @@ public class PageBtreeNode extends PageBtree {
return -1; return -1;
} }
private void updateRowCount(int offset) { private void updateRowCount(int offset) throws SQLException {
if (PageStore.STORE_BTREE_ROWCOUNT) { if (rowCount != UNKNOWN_ROWCOUNT) {
rowCount += offset; rowCount += offset;
} }
if (rowCountStored != UNKNOWN_ROWCOUNT) {
rowCountStored = UNKNOWN_ROWCOUNT;
index.getPageStore().logUndo(this, data);
if (written) {
writeHead();
}
index.getPageStore().update(this);
}
} }
PageBtree split(int splitPoint) throws SQLException { PageBtree split(int splitPoint) throws SQLException {
...@@ -350,14 +356,23 @@ public class PageBtreeNode extends PageBtree { ...@@ -350,14 +356,23 @@ public class PageBtreeNode extends PageBtree {
for (int child : childPageIds) { for (int child : childPageIds) {
PageBtree page = index.getPage(child); PageBtree page = index.getPage(child);
count += page.getRowCount(); count += page.getRowCount();
index.getDatabase().setProgress(DatabaseEventListener.STATE_SCAN_FILE, index.getName(), count, Integer.MAX_VALUE);
} }
rowCount = count; rowCount = count;
} }
return rowCount; return rowCount;
} }
void setRowCountStored(int rowCount) { void setRowCountStored(int rowCount) throws SQLException {
this.rowCount = rowCount; this.rowCount = rowCount;
if (rowCountStored != rowCount) {
rowCountStored = rowCount;
index.getPageStore().logUndo(this, data);
if (written) {
writeHead();
}
index.getPageStore().update(this);
}
} }
private void check() { private void check() {
...@@ -384,7 +399,7 @@ public class PageBtreeNode extends PageBtree { ...@@ -384,7 +399,7 @@ public class PageBtreeNode extends PageBtree {
data.writeShortInt(0); data.writeShortInt(0);
data.writeInt(parentPageId); data.writeInt(parentPageId);
data.writeVarInt(index.getId()); data.writeVarInt(index.getId());
data.writeInt(rowCount); data.writeInt(rowCountStored);
data.writeShortInt(entryCount); data.writeShortInt(entryCount);
} }
...@@ -510,6 +525,8 @@ public class PageBtreeNode extends PageBtree { ...@@ -510,6 +525,8 @@ public class PageBtreeNode extends PageBtree {
store.logUndo(this, data); store.logUndo(this, data);
PageBtreeNode p2 = PageBtreeNode.create(index, newPos, parentPageId); PageBtreeNode p2 = PageBtreeNode.create(index, newPos, parentPageId);
readAllRows(); readAllRows();
p2.rowCountStored = rowCountStored;
p2.rowCount = rowCount;
p2.childPageIds = childPageIds; p2.childPageIds = childPageIds;
p2.rows = rows; p2.rows = rows;
p2.entryCount = entryCount; p2.entryCount = entryCount;
......
...@@ -307,11 +307,6 @@ public class PageDataIndex extends PageIndex implements RowIndex { ...@@ -307,11 +307,6 @@ public class PageDataIndex extends PageIndex implements RowIndex {
store.logAddOrRemoveRow(session, tableData.getId(), row, false); store.logAddOrRemoveRow(session, tableData.getId(), row, false);
} }
private void invalidateRowCount() throws SQLException {
PageData root = getPage(rootPageId, 0);
root.setRowCountStored(PageData.UNKNOWN_ROWCOUNT);
}
public void remove(Session session) throws SQLException { public void remove(Session session) throws SQLException {
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug(this + " remove"); trace.debug(this + " remove");
...@@ -424,8 +419,7 @@ public class PageDataIndex extends PageIndex implements RowIndex { ...@@ -424,8 +419,7 @@ public class PageDataIndex extends PageIndex implements RowIndex {
} }
// can not close the index because it might get used afterwards, // can not close the index because it might get used afterwards,
// for example after running recovery // for example after running recovery
PageData root = getPage(rootPageId, 0); writeRowCount();
root.setRowCountStored(MathUtils.convertLongToInt(rowCount));
} }
Iterator<Row> getDelta() { Iterator<Row> getDelta() {
...@@ -484,4 +478,14 @@ public class PageDataIndex extends PageIndex implements RowIndex { ...@@ -484,4 +478,14 @@ public class PageDataIndex extends PageIndex implements RowIndex {
return getName(); return getName();
} }
private void invalidateRowCount() throws SQLException {
PageData root = getPage(rootPageId, 0);
root.setRowCountStored(PageData.UNKNOWN_ROWCOUNT);
}
public void writeRowCount() throws SQLException {
PageData root = getPage(rootPageId, 0);
root.setRowCountStored(MathUtils.convertLongToInt(rowCount));
}
} }
...@@ -8,6 +8,7 @@ package org.h2.index; ...@@ -8,6 +8,7 @@ package org.h2.index;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import org.h2.api.DatabaseEventListener;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -292,6 +293,7 @@ public class PageDataNode extends PageData { ...@@ -292,6 +293,7 @@ public class PageDataNode extends PageData {
throw Message.throwInternalError("Page it its own child: " + getPos()); throw Message.throwInternalError("Page it its own child: " + getPos());
} }
count += page.getRowCount(); count += page.getRowCount();
index.getDatabase().setProgress(DatabaseEventListener.STATE_SCAN_FILE, index.getTable() + "." + index.getName(), count, Integer.MAX_VALUE);
} }
rowCount = count; rowCount = count;
} }
......
...@@ -112,4 +112,8 @@ public class PageDelegateIndex extends PageIndex { ...@@ -112,4 +112,8 @@ public class PageDelegateIndex extends PageIndex {
return mainIndex.getRowCountApproximation(); return mainIndex.getRowCountApproximation();
} }
public void writeRowCount() {
// ignore
}
} }
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
*/ */
package org.h2.index; package org.h2.index;
import java.sql.SQLException;
/** /**
* A page store index. * A page store index.
*/ */
...@@ -24,4 +26,9 @@ public abstract class PageIndex extends BaseIndex { ...@@ -24,4 +26,9 @@ public abstract class PageIndex extends BaseIndex {
return 0; return 0;
} }
/**
* Write back the row count if it has changed.
*/
public abstract void writeRowCount() throws SQLException;
} }
...@@ -90,21 +90,18 @@ public class PageStore implements CacheWriter { ...@@ -90,21 +90,18 @@ public class PageStore implements CacheWriter {
// TODO optimization: check if calling Data.getValueLen slows things down // TODO optimization: check if calling Data.getValueLen slows things down
// TODO order pages so that searching for a key only seeks forward // TODO order pages so that searching for a key only seeks forward
// TODO optimization: update: only log the key and changed values // TODO optimization: update: only log the key and changed values
// TODO maybe remove some parent pointers
// TODO index creation: use less space (ordered, split at insertion point) // TODO index creation: use less space (ordered, split at insertion point)
// TODO detect circles in linked lists // TODO detect circles in linked lists
// (input stream, free list, extend pages...) // (input stream, free list, extend pages...)
// at runtime and recovery // at runtime and recovery
// synchronized correctly (on the index?) // synchronized correctly (on the index?)
// TODO remove trace or use isDebugEnabled // TODO remove trace or use isDebugEnabled
// TODO recover tool: don't re-do uncommitted operations
// TODO recover tool: support syntax to delete a row with a key // TODO recover tool: support syntax to delete a row with a key
// TODO don't store default values (store a special value) // TODO don't store default values (store a special value)
// TODO split files (1 GB max size) // TODO split files (1 GB max size)
// TODO add a setting (that can be changed at runtime) to call fsync // TODO add a setting (that can be changed at runtime) to call fsync
// and delay on each commit // and delay on each commit
// TODO check for file size (exception if not exact size expected) // TODO check for file size (exception if not exact size expected)
// TODO implement missing code for STORE_BTREE_ROWCOUNT (maybe enable)
// TODO online backup using bsdiff // TODO online backup using bsdiff
// TODO when removing DiskFile: // TODO when removing DiskFile:
...@@ -132,11 +129,6 @@ public class PageStore implements CacheWriter { ...@@ -132,11 +129,6 @@ public class PageStore implements CacheWriter {
*/ */
public static final int PAGE_SIZE_DEFAULT = 2 * 1024; public static final int PAGE_SIZE_DEFAULT = 2 * 1024;
/**
* Store the rowcount in b-tree indexes.
*/
public static final boolean STORE_BTREE_ROWCOUNT = false;
private static final int PAGE_ID_FREE_LIST_ROOT = 3; private static final int PAGE_ID_FREE_LIST_ROOT = 3;
private static final int PAGE_ID_META_ROOT = 4; private static final int PAGE_ID_META_ROOT = 4;
...@@ -188,7 +180,7 @@ public class PageStore implements CacheWriter { ...@@ -188,7 +180,7 @@ public class PageStore implements CacheWriter {
private TableData metaTable; private TableData metaTable;
private PageDataIndex metaIndex; private PageDataIndex metaIndex;
private IntIntHashMap metaRootPageId = new IntIntHashMap(); private IntIntHashMap metaRootPageId = new IntIntHashMap();
private HashMap<Integer, Index> metaObjects = New.hashMap(); private HashMap<Integer, PageIndex> metaObjects = New.hashMap();
/** /**
* The map of reserved pages, to ensure index head pages * The map of reserved pages, to ensure index head pages
...@@ -313,6 +305,12 @@ public class PageStore implements CacheWriter { ...@@ -313,6 +305,12 @@ public class PageStore implements CacheWriter {
} }
} }
private void writeIndexRowCounts() throws SQLException {
for (PageIndex index: metaObjects.values()) {
index.writeRowCount();
}
}
private void writeBack() throws SQLException { private void writeBack() throws SQLException {
ObjectArray<CacheObject> list = cache.getAllChanged(); ObjectArray<CacheObject> list = cache.getAllChanged();
CacheObject.sort(list); CacheObject.sort(list);
...@@ -332,6 +330,7 @@ public class PageStore implements CacheWriter { ...@@ -332,6 +330,7 @@ public class PageStore implements CacheWriter {
} }
synchronized (database) { synchronized (database) {
database.checkPowerOff(); database.checkPowerOff();
writeIndexRowCounts();
writeBack(); writeBack();
log.checkpoint(); log.checkpoint();
switchLog(); switchLog();
...@@ -1034,10 +1033,13 @@ public class PageStore implements CacheWriter { ...@@ -1034,10 +1033,13 @@ public class PageStore implements CacheWriter {
} }
recoveryRunning = false; recoveryRunning = false;
reservedPages = null; reservedPages = null;
writeIndexRowCounts();
writeBack(); writeBack();
// clear the cache because it contains pages with closed indexes // clear the cache because it contains pages with closed indexes
cache.clear(); cache.clear();
freeLists.clear(); freeLists.clear();
metaObjects.clear();
metaObjects.put(-1, metaIndex);
if (setReadOnly) { if (setReadOnly) {
database.setReadOnly(true); database.setReadOnly(true);
} }
...@@ -1201,12 +1203,9 @@ public class PageStore implements CacheWriter { ...@@ -1201,12 +1203,9 @@ public class PageStore implements CacheWriter {
private void removeMeta(int logPos, Row row) throws SQLException { private void removeMeta(int logPos, Row row) throws SQLException {
int id = row.getValue(0).getInt(); int id = row.getValue(0).getInt();
Index index = metaObjects.get(id); PageIndex index = metaObjects.get(id);
int rootPageId = index.getRootPageId(); int rootPageId = index.getRootPageId();
index.getTable().removeIndex(index); index.getTable().removeIndex(index);
if (index instanceof MultiVersionIndex) {
index = ((MultiVersionIndex) index).getBaseIndex();
}
if (index instanceof PageBtreeIndex) { if (index instanceof PageBtreeIndex) {
if (index.isTemporary()) { if (index.isTemporary()) {
systemSession.removeLocalTempTableIndex(index); systemSession.removeLocalTempTableIndex(index);
...@@ -1297,7 +1296,13 @@ public class PageStore implements CacheWriter { ...@@ -1297,7 +1296,13 @@ public class PageStore implements CacheWriter {
} }
meta = table.addIndex(session, "I" + id, id, cols, indexType, id, null); meta = table.addIndex(session, "I" + id, id, cols, indexType, id, null);
} }
metaObjects.put(id, meta); PageIndex index;
if (meta instanceof MultiVersionIndex) {
index = (PageIndex) ((MultiVersionIndex) meta).getBaseIndex();
} else {
index = (PageIndex) meta;
}
metaObjects.put(id, index);
} }
/** /**
......
...@@ -10,7 +10,6 @@ import java.sql.SQLException; ...@@ -10,7 +10,6 @@ import java.sql.SQLException;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.CreateTableData;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
...@@ -28,8 +27,8 @@ import org.h2.index.IndexType; ...@@ -28,8 +27,8 @@ import org.h2.index.IndexType;
import org.h2.index.MultiVersionIndex; import org.h2.index.MultiVersionIndex;
import org.h2.index.NonUniqueHashIndex; import org.h2.index.NonUniqueHashIndex;
import org.h2.index.PageBtreeIndex; import org.h2.index.PageBtreeIndex;
import org.h2.index.PageDelegateIndex;
import org.h2.index.PageDataIndex; import org.h2.index.PageDataIndex;
import org.h2.index.PageDelegateIndex;
import org.h2.index.RowIndex; import org.h2.index.RowIndex;
import org.h2.index.ScanIndex; import org.h2.index.ScanIndex;
import org.h2.index.TreeIndex; import org.h2.index.TreeIndex;
...@@ -39,7 +38,6 @@ import org.h2.result.Row; ...@@ -39,7 +38,6 @@ import org.h2.result.Row;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.schema.SchemaObject; import org.h2.schema.SchemaObject;
import org.h2.store.DataPage; import org.h2.store.DataPage;
import org.h2.store.PageStore;
import org.h2.store.Record; import org.h2.store.Record;
import org.h2.store.RecordReader; import org.h2.store.RecordReader;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
...@@ -156,12 +154,11 @@ public class TableData extends Table implements RecordReader { ...@@ -156,12 +154,11 @@ public class TableData extends Table implements RecordReader {
private void checkRowCount(Session session, Index index, int offset) { private void checkRowCount(Session session, Index index, int offset) {
if (SysProperties.CHECK && !database.isMultiVersion()) { if (SysProperties.CHECK && !database.isMultiVersion()) {
if (database.isPageStoreEnabled() && !PageStore.STORE_BTREE_ROWCOUNT) { if (!(index instanceof PageDelegateIndex)) {
return; long rc = index.getRowCount(session);
} if (rc != rowCount + offset) {
long rc = index.getRowCount(session); Message.throwInternalError("rowCount expected " + (rowCount + offset) + " got " + rc + " " + getName() + "." + index.getName());
if (rc != rowCount + offset) { }
Message.throwInternalError("rowCount expected " + (rowCount + offset) + " got " + rc + " " + getName() + "." + index.getName());
} }
} }
} }
......
...@@ -15,12 +15,15 @@ import java.sql.Statement; ...@@ -15,12 +15,15 @@ import java.sql.Statement;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import org.h2.api.DatabaseEventListener;
import org.h2.test.TestBase; import org.h2.test.TestBase;
/** /**
* Test the page store. * Test the page store.
*/ */
public class TestPageStore extends TestBase { public class TestPageStore extends TestBase implements DatabaseEventListener {
static StringBuilder eventBuffer = new StringBuilder();
/** /**
* Run just this test. * Run just this test.
...@@ -33,6 +36,8 @@ public class TestPageStore extends TestBase { ...@@ -33,6 +36,8 @@ public class TestPageStore extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
testLargeDatabaseFastOpen();
testUniqueIndexReopen();
testExistingOld(); testExistingOld();
testLargeRows(); testLargeRows();
testRecoverDropIndex(); testRecoverDropIndex();
...@@ -45,6 +50,56 @@ public class TestPageStore extends TestBase { ...@@ -45,6 +50,56 @@ public class TestPageStore extends TestBase {
testFuzzOperations(); testFuzzOperations();
} }
private void testLargeDatabaseFastOpen() throws SQLException {
if (config.memory) {
return;
}
deleteDb("pageStore");
Connection conn;
String url = "pageStore";
conn = getConnection(url);
conn.createStatement().execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
conn.createStatement().execute("create unique index idx_test_name on test(name)");
conn.createStatement().execute("INSERT INTO TEST SELECT X, X || space(10) FROM SYSTEM_RANGE(1, 1000)");
conn.close();
conn = getConnection(url);
conn.createStatement().execute("DELETE FROM TEST WHERE ID=1");
conn.createStatement().execute("CHECKPOINT");
conn.createStatement().execute("SHUTDOWN IMMEDIATELY");
try {
conn.close();
} catch (SQLException e) {
// ignore
}
eventBuffer.setLength(0);
conn = getConnection(url + ";DATABASE_EVENT_LISTENER='" + getClass().getName() + "'");
assertEquals("init;opened;", eventBuffer.toString());
conn.close();
}
private void testUniqueIndexReopen() throws SQLException {
if (config.memory) {
return;
}
deleteDb("pageStore");
Connection conn;
String url = "pageStore";
conn = getConnection(url);
conn.createStatement().execute("CREATE TABLE test(ID INT PRIMARY KEY, NAME VARCHAR(255))");
conn.createStatement().execute("create unique index idx_test_name on test(name)");
conn.createStatement().execute("INSERT INTO TEST VALUES(1, 'Hello')");
conn.close();
conn = getConnection(url);
try {
conn.createStatement().execute("INSERT INTO TEST VALUES(2, 'Hello')");
fail();
} catch (SQLException e) {
assertKnownException(e);
}
conn.close();
}
private void testExistingOld() throws SQLException { private void testExistingOld() throws SQLException {
if (config.memory) { if (config.memory) {
return; return;
...@@ -359,4 +414,36 @@ public class TestPageStore extends TestBase { ...@@ -359,4 +414,36 @@ public class TestPageStore extends TestBase {
trace(" " + m); trace(" " + m);
} }
public void closingDatabase() {
event("closing");
}
public void diskSpaceIsLow(long stillAvailable) {
event("diskSpaceIsLow " + stillAvailable);
}
public void exceptionThrown(SQLException e, String sql) {
event("exceptionThrown " + e + " " + sql);
}
public void init(String url) {
event("init");
}
public void opened() {
event("opened");
}
public void setProgress(int state, String name, int x, int max) {
if (name.startsWith("SYS:SYS_ID")) {
// ignore
return;
}
event("setProgress " + state + " " + name + " " + x + " " + max);
}
private void event(String s) {
eventBuffer.append(s).append(';');
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论