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

MVStore: temporary tables from result sets could survive re-opening a database,…

MVStore: temporary tables from result sets could survive re-opening a database, which could result in a ClassCastException.
上级 d0d72f03
...@@ -27,10 +27,12 @@ import org.h2.mvstore.FileStore; ...@@ -27,10 +27,12 @@ import org.h2.mvstore.FileStore;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore; import org.h2.mvstore.MVStore;
import org.h2.mvstore.db.TransactionStore.Transaction; import org.h2.mvstore.db.TransactionStore.Transaction;
import org.h2.mvstore.db.TransactionStore.TransactionMap;
import org.h2.store.InDoubtTransaction; import org.h2.store.InDoubtTransaction;
import org.h2.store.fs.FileChannelInputStream; import org.h2.store.fs.FileChannelInputStream;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
import org.h2.table.TableBase; import org.h2.table.TableBase;
import org.h2.util.BitField;
import org.h2.util.New; import org.h2.util.New;
/** /**
...@@ -230,12 +232,23 @@ public class MVTableEngine implements TableEngine { ...@@ -230,12 +232,23 @@ public class MVTableEngine implements TableEngine {
/** /**
* Remove all temporary maps. * Remove all temporary maps.
* @param objectIds
*/ */
public void removeTemporaryMaps() { public void removeTemporaryMaps(BitField objectIds) {
for (String mapName : store.getMapNames()) { for (String mapName : store.getMapNames()) {
if (mapName.startsWith("temp.")) { if (mapName.startsWith("temp.")) {
MVMap<?, ?> map = store.openMap(mapName); MVMap<?, ?> map = store.openMap(mapName);
store.removeMap(map); store.removeMap(map);
} else if (mapName.startsWith("table.") || mapName.startsWith("index.")) {
int id = Integer.parseInt(mapName.substring(1 + mapName.indexOf(".")));
if (!objectIds.get(id)) {
ValueDataType keyType = new ValueDataType(null, null, null);
ValueDataType valueType = new ValueDataType(null, null, null);
Transaction t = transactionStore.begin();
TransactionMap<?, ?> m = t.openMap(mapName, keyType, valueType);
transactionStore.removeMap(m);
t.commit();
}
} }
} }
} }
...@@ -303,12 +316,16 @@ public class MVTableEngine implements TableEngine { ...@@ -303,12 +316,16 @@ public class MVTableEngine implements TableEngine {
*/ */
public void compactFile(long maxCompactTime) { public void compactFile(long maxCompactTime) {
store.setRetentionTime(0); store.setRetentionTime(0);
long start = System.currentTimeMillis(); if (maxCompactTime == Long.MAX_VALUE) {
while (store.compact(99, 4 * 1024 * 1024)) { store.compactRewriteFully();
store.sync(); } else {
long time = System.currentTimeMillis() - start; long start = System.currentTimeMillis();
if (time > maxCompactTime) { while (store.compact(99, 4 * 1024 * 1024)) {
break; store.sync();
long time = System.currentTimeMillis() - start;
if (time > maxCompactTime) {
break;
}
} }
} }
store.compactMoveChunks(); store.compactMoveChunks();
......
...@@ -447,8 +447,8 @@ public class TransactionStore { ...@@ -447,8 +447,8 @@ public class TransactionStore {
// if there is no open transaction, // if there is no open transaction,
// and if there have been many changes, store them now // and if there have been many changes, store them now
if (undoLog.isEmpty()) { if (undoLog.isEmpty()) {
int unsaved = store.getUnsavedPageCount(); int unsaved = store.getUnsavedMemory();
int max = store.getAutoCommitPageCount(); int max = store.getAutoCommitMemory();
// save at 3/4 capacity // save at 3/4 capacity
if (unsaved * 4 > max * 3) { if (unsaved * 4 > max * 3) {
store.commit(); store.commit();
...@@ -1162,7 +1162,6 @@ public class TransactionStore { ...@@ -1162,7 +1162,6 @@ public class TransactionStore {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public V get(K key, long maxLogId) { public V get(K key, long maxLogId) {
transaction.checkNotClosed();
VersionedValue data = getValue(key, maxLogId); VersionedValue data = getValue(key, maxLogId);
return data == null ? null : (V) data.value; return data == null ? null : (V) data.value;
} }
......
...@@ -64,13 +64,22 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -64,13 +64,22 @@ public class LocalResult implements ResultInterface, ResultTarget {
if (session == null) { if (session == null) {
this.maxMemoryRows = Integer.MAX_VALUE; this.maxMemoryRows = Integer.MAX_VALUE;
} else { } else {
this.maxMemoryRows = session.getDatabase().getMaxMemoryRows(); Database db = session.getDatabase();
if (db.isPersistent() && !db.isReadOnly()) {
this.maxMemoryRows = session.getDatabase().getMaxMemoryRows();
} else {
this.maxMemoryRows = Integer.MAX_VALUE;
}
} }
rows = New.arrayList(); rows = New.arrayList();
this.visibleColumnCount = visibleColumnCount; this.visibleColumnCount = visibleColumnCount;
rowId = -1; rowId = -1;
this.expressions = expressions; this.expressions = expressions;
} }
public void setMaxMemoryRows(int maxValue) {
this.maxMemoryRows = maxValue;
}
/** /**
* Construct a local result set by reading all data from a regular result * Construct a local result set by reading all data from a regular result
...@@ -227,7 +236,7 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -227,7 +236,7 @@ public class LocalResult implements ResultInterface, ResultTarget {
@Override @Override
public boolean next() { public boolean next() {
if (rowId < rowCount) { if (!closed && rowId < rowCount) {
rowId++; rowId++;
if (rowId < rowCount) { if (rowId < rowCount) {
if (external != null) { if (external != null) {
...@@ -259,10 +268,8 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -259,10 +268,8 @@ public class LocalResult implements ResultInterface, ResultTarget {
ValueArray array = ValueArray.get(values); ValueArray array = ValueArray.get(values);
distinctRows.put(array, values); distinctRows.put(array, values);
rowCount = distinctRows.size(); rowCount = distinctRows.size();
Database db = session.getDatabase(); if (rowCount > maxMemoryRows) {
if (rowCount > db.getMaxMemoryRows() && external = new ResultTempTable(session, true, sort);
db.isPersistent() && !db.isReadOnly()) {
external = new ResultTempTable(session, sort);
rowCount = external.addRows(distinctRows.values()); rowCount = external.addRows(distinctRows.values());
distinctRows = null; distinctRows = null;
} }
...@@ -273,16 +280,9 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -273,16 +280,9 @@ public class LocalResult implements ResultInterface, ResultTarget {
} }
rows.add(values); rows.add(values);
rowCount++; rowCount++;
if (rows.size() > maxMemoryRows && session.getDatabase().isPersistent()) { if (rows.size() > maxMemoryRows) {
if (external == null) { if (external == null) {
if (randomAccess) { external = new ResultTempTable(session, false, sort);
Database db = session.getDatabase();
if (!db.isReadOnly()) {
external = new ResultTempTable(session, sort);
}
} else {
external = new ResultDiskBuffer(session, sort, values.length);
}
} }
addRowsToDisk(); addRowsToDisk();
} }
...@@ -319,14 +319,7 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -319,14 +319,7 @@ public class LocalResult implements ResultInterface, ResultTarget {
break; break;
} }
if (external == null) { if (external == null) {
if (randomAccess) { external = new ResultTempTable(session, true, sort);
Database db = session.getDatabase();
if (!db.isReadOnly()) {
external = new ResultTempTable(session, sort);
}
} else {
external = new ResultDiskBuffer(session, sort, list.length);
}
} }
rows.add(list); rows.add(list);
if (rows.size() > maxMemoryRows) { if (rows.size() > maxMemoryRows) {
......
...@@ -29,6 +29,7 @@ import org.h2.value.ValueArray; ...@@ -29,6 +29,7 @@ import org.h2.value.ValueArray;
public class ResultTempTable implements ResultExternal { public class ResultTempTable implements ResultExternal {
private static final String COLUMN_NAME = "DATA"; private static final String COLUMN_NAME = "DATA";
private final boolean distinct;
private final SortOrder sort; private final SortOrder sort;
private final Index index; private final Index index;
private Session session; private Session session;
...@@ -40,8 +41,9 @@ public class ResultTempTable implements ResultExternal { ...@@ -40,8 +41,9 @@ public class ResultTempTable implements ResultExternal {
private boolean closed; private boolean closed;
private int childCount; private int childCount;
ResultTempTable(Session session, SortOrder sort) { ResultTempTable(Session session, boolean distinct, SortOrder sort) {
this.session = session; this.session = session;
this.distinct = distinct;
this.sort = sort; this.sort = sort;
Schema schema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN); Schema schema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN);
Column column = new Column(COLUMN_NAME, Value.ARRAY); Column column = new Column(COLUMN_NAME, Value.ARRAY);
...@@ -61,13 +63,14 @@ public class ResultTempTable implements ResultExternal { ...@@ -61,13 +63,14 @@ public class ResultTempTable implements ResultExternal {
indexColumn.column = column; indexColumn.column = column;
indexColumn.columnName = COLUMN_NAME; indexColumn.columnName = COLUMN_NAME;
IndexType indexType; IndexType indexType;
indexType = IndexType.createPrimaryKey(true, false);
IndexColumn[] indexCols = { indexColumn }; IndexColumn[] indexCols = { indexColumn };
if (session.getDatabase().getMvStore() != null) { if (session.getDatabase().getMvStore() != null) {
indexType = IndexType.createNonUnique(true);
index = table.addIndex(session, data.tableName, indexId, indexCols, index = table.addIndex(session, data.tableName, indexId, indexCols,
indexType, true, null); indexType, true, null);
index.setTemporary(true); index.setTemporary(true);
} else { } else {
indexType = IndexType.createPrimaryKey(true, false);
index = new PageBtreeIndex((RegularTable) table, indexId, index = new PageBtreeIndex((RegularTable) table, indexId,
data.tableName, indexCols, indexType, true, session); data.tableName, indexCols, indexType, true, session);
index.setTemporary(true); index.setTemporary(true);
...@@ -78,6 +81,7 @@ public class ResultTempTable implements ResultExternal { ...@@ -78,6 +81,7 @@ public class ResultTempTable implements ResultExternal {
private ResultTempTable(ResultTempTable parent) { private ResultTempTable(ResultTempTable parent) {
this.parent = parent; this.parent = parent;
this.distinct = parent.distinct;
this.session = parent.session; this.session = parent.session;
this.table = parent.table; this.table = parent.table;
this.index = parent.index; this.index = parent.index;
...@@ -119,8 +123,13 @@ public class ResultTempTable implements ResultExternal { ...@@ -119,8 +123,13 @@ public class ResultTempTable implements ResultExternal {
@Override @Override
public int addRow(Value[] values) { public int addRow(Value[] values) {
Row row = convertToRow(values); Row row = convertToRow(values);
Cursor cursor = find(row); if (distinct) {
if (cursor == null) { Cursor cursor = find(row);
if (cursor == null) {
table.addRow(session, row);
rowCount++;
}
} else {
table.addRow(session, row); table.addRow(session, row);
rowCount++; rowCount++;
} }
...@@ -199,14 +208,20 @@ public class ResultTempTable implements ResultExternal { ...@@ -199,14 +208,20 @@ public class ResultTempTable implements ResultExternal {
public Value[] next() { public Value[] next() {
if (resultCursor == null) { if (resultCursor == null) {
if (session.getDatabase().getMvStore() != null) { if (session.getDatabase().getMvStore() != null) {
Index idx;
if (distinct || sort != null) {
idx = index;
} else {
idx = table.getScanIndex(session);
}
// sometimes the transaction is already committed, // sometimes the transaction is already committed,
// in which case we can't use the session // in which case we can't use the session
if (index.getRowCount(session) == 0 && rowCount > 0) { if (idx.getRowCount(session) == 0 && rowCount > 0) {
// this means querying is not transactional // this means querying is not transactional
resultCursor = index.find((Session) null, null, null); resultCursor = idx.find((Session) null, null, null);
} else { } else {
// the transaction is still open // the transaction is still open
resultCursor = index.find(session, null, null); resultCursor = idx.find(session, null, null);
} }
} else { } else {
resultCursor = index.find(session, null, null); resultCursor = index.find(session, null, null);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论