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

Mainly MVStore improvements

上级 464c791c
......@@ -18,7 +18,11 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>The license has changed to MPL 2.0 + EPL 1.0.
<ul><li>Recursive queries with many result rows (more than the setting "max_memory_rows")
did not work correctly.
</li><li>The license has changed to MPL 2.0 + EPL 1.0.
</li><li>MVStore: temporary tables from result sets could survive re-opening a database,
which could result in a ClassCastException.
</li><li>MVStore: unique indexes that were created later on did not work correctly
if there were over 5000 rows in the table.
</li><li>MVStore: creating secondary indexes on large tables
......
......@@ -603,7 +603,6 @@ public class Select extends Query {
}
if (randomAccessResult) {
result = createLocalResult(result);
result.setRandomAccess();
}
if (isGroupQuery && !isGroupSortedQuery) {
result = createLocalResult(result);
......
......@@ -18,6 +18,7 @@ import java.util.StringTokenizer;
import org.h2.api.DatabaseEventListener;
import org.h2.api.ErrorCode;
import org.h2.api.JavaObjectSerializer;
import org.h2.command.CommandInterface;
import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.SetTypes;
import org.h2.constraint.Constraint;
......@@ -725,7 +726,7 @@ public class Database implements DataHandler {
}
if (mvStore != null) {
mvStore.initTransactions();
mvStore.removeTemporaryMaps();
mvStore.removeTemporaryMaps(objectIds);
}
recompileInvalidViews(systemSession);
starting = false;
......@@ -1325,8 +1326,12 @@ public class Database implements DataHandler {
}
reconnectModified(false);
if (mvStore != null) {
if (!readOnly && compactMode != 0) {
mvStore.compactFile(dbSettings.maxCompactTime);
if (!readOnly) {
if (compactMode == CommandInterface.SHUTDOWN_COMPACT) {
mvStore.compactFile(dbSettings.maxCompactTime);
} else if (compactMode == CommandInterface.SHUTDOWN_DEFRAG) {
mvStore.compactFile(Long.MAX_VALUE);
}
}
mvStore.close(dbSettings.maxCompactTime);
}
......
......@@ -27,7 +27,7 @@ import org.h2.message.TraceSystem;
import org.h2.mvstore.db.MVTable;
import org.h2.mvstore.db.TransactionStore.Change;
import org.h2.mvstore.db.TransactionStore.Transaction;
import org.h2.result.ResultInterface;
import org.h2.result.LocalResult;
import org.h2.result.Row;
import org.h2.schema.Schema;
import org.h2.store.DataHandler;
......@@ -99,7 +99,7 @@ public class Session extends SessionWithState {
private long transactionStart;
private long currentCommandStart;
private HashMap<String, Value> variables;
private HashSet<ResultInterface> temporaryResults;
private HashSet<LocalResult> temporaryResults;
private int queryTimeout;
private boolean commitOrRollbackDisabled;
private Table waitForLock;
......@@ -1268,7 +1268,7 @@ public class Session extends SessionWithState {
*
* @param result the temporary result set
*/
public void addTemporaryResult(ResultInterface result) {
public void addTemporaryResult(LocalResult result) {
if (!result.needToClose()) {
return;
}
......@@ -1283,7 +1283,7 @@ public class Session extends SessionWithState {
private void closeTemporaryResults() {
if (temporaryResults != null) {
for (ResultInterface result : temporaryResults) {
for (LocalResult result : temporaryResults) {
result.close();
}
temporaryResults = null;
......
......@@ -21,6 +21,7 @@ public class Cursor<K, V> implements Iterator<K> {
private CursorPos pos;
private K current, last;
private V currentValue, lastValue;
private Page lastPage;
private final Page root;
private boolean initialized;
......@@ -46,6 +47,7 @@ public class Cursor<K, V> implements Iterator<K> {
K c = current;
last = current;
lastValue = currentValue;
lastPage = pos == null ? null : pos.page;
fetchNext();
return c;
}
......@@ -67,6 +69,10 @@ public class Cursor<K, V> implements Iterator<K> {
public V getValue() {
return lastValue;
}
Page getPage() {
return lastPage;
}
/**
* Skip over that many entries. This method is relatively fast (for this map
......@@ -147,5 +153,5 @@ public class Cursor<K, V> implements Iterator<K> {
}
current = null;
}
}
......@@ -772,6 +772,72 @@ public class MVMap<K, V> extends AbstractMap<K, V>
public Iterator<K> keyIterator(K from) {
return new Cursor<K, V>(this, root, from);
}
/**
* Re-write any pages that belong to one of the chunks in the given set.
*
* @param set the set of chunk ids
*/
public void rewrite(Set<Integer> set) {
rewrite(root, set);
}
public int rewrite(Page p, Set<Integer> set) {
; // TODO write more tests
if (p.isLeaf()) {
long pos = p.getPos();
if (pos == 0) {
return 0;
}
int chunkId = DataUtils.getPageChunkId(pos);
if (!set.contains(chunkId)) {
return 0;
}
@SuppressWarnings("unchecked")
K key = (K) p.getKey(0);
@SuppressWarnings("unchecked")
V value = (V) p.getValue(0);
put(key, value);
return 1;
}
int writtenPageCount = 0;
for (int i = 0; i < p.getChildPageCount(); i++) {
long pos = p.getChildPagePos(i);
if (pos == 0) {
continue;
}
if (DataUtils.getPageType(pos) == DataUtils.PAGE_TYPE_LEAF) {
int chunkId = DataUtils.getPageChunkId(pos);
if (!set.contains(chunkId)) {
continue;
}
}
writtenPageCount += rewrite(p.getChildPage(i), set);
}
if (writtenPageCount == 0) {
long pos = p.getPos();
if (pos != 0) {
int chunkId = DataUtils.getPageChunkId(pos);
if (set.contains(chunkId)) {
// an inner node page that is in one of the chunks,
// but only points to chunks that are not in the set:
// if no child was changed, we need to do that now
Page p2 = p;
while (!p2.isLeaf()) {
p2 = p2.getChildPage(0);
}
@SuppressWarnings("unchecked")
K key = (K) p2.getKey(0);
@SuppressWarnings("unchecked")
V value = (V) p2.getValue(0);
put(key, value);
writtenPageCount++;
}
}
}
return writtenPageCount;
}
/**
* Get a cursor to iterate over a number of keys and values.
......
......@@ -221,6 +221,10 @@ public class Page {
Page p = childrenPages[index];
return p != null ? p : map.readPage(children[index]);
}
public long getChildPagePos(int index) {
return children[index];
}
/**
* Get the child page at the given index, if it is live.
......
......@@ -14,11 +14,9 @@ import java.io.OutputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import org.h2.api.ErrorCode;
......
......@@ -320,5 +320,36 @@ public abstract class FilePath {
public FilePath unwrap() {
return this;
}
/**
* The options to open a file.
*/
public enum FileOpenOption {
/**
* Append at the end of the file.
*/
APPEND,
/**
* Written data is not buffered.
*/
DSYNC,
/**
* Open the file for read access.
*/
READ,
/**
* Written data and metadata is not buffered.
*/
SYNC,
/**
* Open the file for write access.
*/
WRITE,
}
}
......@@ -6,9 +6,7 @@
*/
package org.h2.table;
import java.sql.Date;
import java.sql.ResultSetMetaData;
import java.sql.Timestamp;
import org.h2.api.ErrorCode;
import org.h2.command.Parser;
......
......@@ -26,7 +26,6 @@ import org.h2.index.IndexType;
import org.h2.index.ViewIndex;
import org.h2.message.DbException;
import org.h2.result.LocalResult;
import org.h2.result.ResultInterface;
import org.h2.result.Row;
import org.h2.result.SortOrder;
import org.h2.schema.Schema;
......@@ -46,41 +45,6 @@ public class TableView extends Table {
private static final long ROW_COUNT_APPROXIMATION = 100;
private static final class CacheKey {
private final int[] masks;
private final Session session;
public CacheKey(int[] masks, Session session) {
this.masks = masks;
this.session = session;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(masks);
result = prime * result + session.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CacheKey other = (CacheKey) obj;
if (!Arrays.equals(masks, other.masks))
return false;
if (session != other.session)
return false;
return true;
}
}
private String querySQL;
private ArrayList<Table> tables;
private String[] columnNames;
......@@ -572,7 +536,7 @@ public class TableView extends Table {
this.recursiveResult = value;
}
public ResultInterface getRecursiveResult() {
public LocalResult getRecursiveResult() {
return recursiveResult;
}
......@@ -595,5 +559,49 @@ public class TableView extends Table {
}
}
}
/**
* The key of the index cache for views.
*/
private static final class CacheKey {
private final int[] masks;
private final Session session;
public CacheKey(int[] masks, Session session) {
this.masks = masks;
this.session = session;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(masks);
result = prime * result + session.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
CacheKey other = (CacheKey) obj;
if (session != other.session) {
return false;
}
if (!Arrays.equals(masks, other.masks)) {
return false;
}
return true;
}
}
}
......@@ -4,6 +4,11 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.tools;
//## AWT ##
......
......@@ -362,10 +362,10 @@ java org.h2.test.TestAll timer
*/
String cacheType;
private Server server;
AbbaLockingDetector abbaLockingDetector;
private Server server;
/**
* Run all tests.
*
......@@ -385,7 +385,15 @@ java org.h2.test.TestAll timer
// use lower values, to better test those cases,
// and to speed up the tests (for delays)
System.setProperty("h2.maxMemoryRows", "128");
; // TEST
// System.setProperty("h2.maxMemoryRows", "2");
System.setProperty("h2.maxMemoryRows", "100");
// System.setProperty("h2.maxMemoryRows", "1000");
// System.setProperty("h2.maxMemoryRows", "2");
System.setProperty("h2.check2", "true");
System.setProperty("h2.delayWrongPasswordMin", "0");
System.setProperty("h2.delayWrongPasswordMax", "0");
......@@ -610,7 +618,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new TestAlterSchemaRename().runTest(this);
new TestAutoRecompile().runTest(this);
new TestBitField().runTest(this);
new TestBnf().runTest(this);
new TestBackup().runTest(this);
new TestBigDb().runTest(this);
new TestBigResult().runTest(this);
......@@ -752,6 +759,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
// unit
new TestAutoReconnect().runTest(this);
new TestBnf().runTest(this);
new TestCache().runTest(this);
new TestClearReferences().runTest(this);
new TestCollation().runTest(this);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论