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

Mainly MVStore improvements

上级 464c791c
...@@ -18,7 +18,11 @@ Change Log ...@@ -18,7 +18,11 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <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 </li><li>MVStore: unique indexes that were created later on did not work correctly
if there were over 5000 rows in the table. if there were over 5000 rows in the table.
</li><li>MVStore: creating secondary indexes on large tables </li><li>MVStore: creating secondary indexes on large tables
......
...@@ -603,7 +603,6 @@ public class Select extends Query { ...@@ -603,7 +603,6 @@ public class Select extends Query {
} }
if (randomAccessResult) { if (randomAccessResult) {
result = createLocalResult(result); result = createLocalResult(result);
result.setRandomAccess();
} }
if (isGroupQuery && !isGroupSortedQuery) { if (isGroupQuery && !isGroupSortedQuery) {
result = createLocalResult(result); result = createLocalResult(result);
......
...@@ -18,6 +18,7 @@ import java.util.StringTokenizer; ...@@ -18,6 +18,7 @@ import java.util.StringTokenizer;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.JavaObjectSerializer; import org.h2.api.JavaObjectSerializer;
import org.h2.command.CommandInterface;
import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.SetTypes; import org.h2.command.dml.SetTypes;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
...@@ -725,7 +726,7 @@ public class Database implements DataHandler { ...@@ -725,7 +726,7 @@ public class Database implements DataHandler {
} }
if (mvStore != null) { if (mvStore != null) {
mvStore.initTransactions(); mvStore.initTransactions();
mvStore.removeTemporaryMaps(); mvStore.removeTemporaryMaps(objectIds);
} }
recompileInvalidViews(systemSession); recompileInvalidViews(systemSession);
starting = false; starting = false;
...@@ -1325,8 +1326,12 @@ public class Database implements DataHandler { ...@@ -1325,8 +1326,12 @@ public class Database implements DataHandler {
} }
reconnectModified(false); reconnectModified(false);
if (mvStore != null) { if (mvStore != null) {
if (!readOnly && compactMode != 0) { if (!readOnly) {
mvStore.compactFile(dbSettings.maxCompactTime); if (compactMode == CommandInterface.SHUTDOWN_COMPACT) {
mvStore.compactFile(dbSettings.maxCompactTime);
} else if (compactMode == CommandInterface.SHUTDOWN_DEFRAG) {
mvStore.compactFile(Long.MAX_VALUE);
}
} }
mvStore.close(dbSettings.maxCompactTime); mvStore.close(dbSettings.maxCompactTime);
} }
......
...@@ -27,7 +27,7 @@ import org.h2.message.TraceSystem; ...@@ -27,7 +27,7 @@ import org.h2.message.TraceSystem;
import org.h2.mvstore.db.MVTable; import org.h2.mvstore.db.MVTable;
import org.h2.mvstore.db.TransactionStore.Change; import org.h2.mvstore.db.TransactionStore.Change;
import org.h2.mvstore.db.TransactionStore.Transaction; 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.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
...@@ -99,7 +99,7 @@ public class Session extends SessionWithState { ...@@ -99,7 +99,7 @@ public class Session extends SessionWithState {
private long transactionStart; private long transactionStart;
private long currentCommandStart; private long currentCommandStart;
private HashMap<String, Value> variables; private HashMap<String, Value> variables;
private HashSet<ResultInterface> temporaryResults; private HashSet<LocalResult> temporaryResults;
private int queryTimeout; private int queryTimeout;
private boolean commitOrRollbackDisabled; private boolean commitOrRollbackDisabled;
private Table waitForLock; private Table waitForLock;
...@@ -1268,7 +1268,7 @@ public class Session extends SessionWithState { ...@@ -1268,7 +1268,7 @@ public class Session extends SessionWithState {
* *
* @param result the temporary result set * @param result the temporary result set
*/ */
public void addTemporaryResult(ResultInterface result) { public void addTemporaryResult(LocalResult result) {
if (!result.needToClose()) { if (!result.needToClose()) {
return; return;
} }
...@@ -1283,7 +1283,7 @@ public class Session extends SessionWithState { ...@@ -1283,7 +1283,7 @@ public class Session extends SessionWithState {
private void closeTemporaryResults() { private void closeTemporaryResults() {
if (temporaryResults != null) { if (temporaryResults != null) {
for (ResultInterface result : temporaryResults) { for (LocalResult result : temporaryResults) {
result.close(); result.close();
} }
temporaryResults = null; temporaryResults = null;
......
...@@ -21,6 +21,7 @@ public class Cursor<K, V> implements Iterator<K> { ...@@ -21,6 +21,7 @@ public class Cursor<K, V> implements Iterator<K> {
private CursorPos pos; private CursorPos pos;
private K current, last; private K current, last;
private V currentValue, lastValue; private V currentValue, lastValue;
private Page lastPage;
private final Page root; private final Page root;
private boolean initialized; private boolean initialized;
...@@ -46,6 +47,7 @@ public class Cursor<K, V> implements Iterator<K> { ...@@ -46,6 +47,7 @@ public class Cursor<K, V> implements Iterator<K> {
K c = current; K c = current;
last = current; last = current;
lastValue = currentValue; lastValue = currentValue;
lastPage = pos == null ? null : pos.page;
fetchNext(); fetchNext();
return c; return c;
} }
...@@ -67,6 +69,10 @@ public class Cursor<K, V> implements Iterator<K> { ...@@ -67,6 +69,10 @@ public class Cursor<K, V> implements Iterator<K> {
public V getValue() { public V getValue() {
return lastValue; return lastValue;
} }
Page getPage() {
return lastPage;
}
/** /**
* Skip over that many entries. This method is relatively fast (for this map * 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> { ...@@ -147,5 +153,5 @@ public class Cursor<K, V> implements Iterator<K> {
} }
current = null; current = null;
} }
} }
...@@ -772,6 +772,72 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -772,6 +772,72 @@ public class MVMap<K, V> extends AbstractMap<K, V>
public Iterator<K> keyIterator(K from) { public Iterator<K> keyIterator(K from) {
return new Cursor<K, V>(this, root, 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. * Get a cursor to iterate over a number of keys and values.
......
...@@ -221,6 +221,10 @@ public class Page { ...@@ -221,6 +221,10 @@ public class Page {
Page p = childrenPages[index]; Page p = childrenPages[index];
return p != null ? p : map.readPage(children[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. * Get the child page at the given index, if it is live.
......
...@@ -14,11 +14,9 @@ import java.io.OutputStream; ...@@ -14,11 +14,9 @@ import java.io.OutputStream;
import java.io.Reader; import java.io.Reader;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.sql.Date;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
......
...@@ -320,5 +320,36 @@ public abstract class FilePath { ...@@ -320,5 +320,36 @@ public abstract class FilePath {
public FilePath unwrap() { public FilePath unwrap() {
return this; 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 @@ ...@@ -6,9 +6,7 @@
*/ */
package org.h2.table; package org.h2.table;
import java.sql.Date;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.Timestamp;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Parser; import org.h2.command.Parser;
......
...@@ -26,7 +26,6 @@ import org.h2.index.IndexType; ...@@ -26,7 +26,6 @@ import org.h2.index.IndexType;
import org.h2.index.ViewIndex; import org.h2.index.ViewIndex;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.schema.Schema; import org.h2.schema.Schema;
...@@ -46,41 +45,6 @@ public class TableView extends Table { ...@@ -46,41 +45,6 @@ public class TableView extends Table {
private static final long ROW_COUNT_APPROXIMATION = 100; 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 String querySQL;
private ArrayList<Table> tables; private ArrayList<Table> tables;
private String[] columnNames; private String[] columnNames;
...@@ -572,7 +536,7 @@ public class TableView extends Table { ...@@ -572,7 +536,7 @@ public class TableView extends Table {
this.recursiveResult = value; this.recursiveResult = value;
} }
public ResultInterface getRecursiveResult() { public LocalResult getRecursiveResult() {
return recursiveResult; return recursiveResult;
} }
...@@ -595,5 +559,49 @@ public class TableView extends Table { ...@@ -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 @@ ...@@ -4,6 +4,11 @@
* (http://h2database.com/html/license.html). * (http://h2database.com/html/license.html).
* Initial Developer: H2 Group * 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; package org.h2.tools;
//## AWT ## //## AWT ##
......
...@@ -362,10 +362,10 @@ java org.h2.test.TestAll timer ...@@ -362,10 +362,10 @@ java org.h2.test.TestAll timer
*/ */
String cacheType; String cacheType;
private Server server;
AbbaLockingDetector abbaLockingDetector; AbbaLockingDetector abbaLockingDetector;
private Server server;
/** /**
* Run all tests. * Run all tests.
* *
...@@ -385,7 +385,15 @@ java org.h2.test.TestAll timer ...@@ -385,7 +385,15 @@ java org.h2.test.TestAll timer
// use lower values, to better test those cases, // use lower values, to better test those cases,
// and to speed up the tests (for delays) // 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.check2", "true");
System.setProperty("h2.delayWrongPasswordMin", "0"); System.setProperty("h2.delayWrongPasswordMin", "0");
System.setProperty("h2.delayWrongPasswordMax", "0"); System.setProperty("h2.delayWrongPasswordMax", "0");
...@@ -610,7 +618,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -610,7 +618,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new TestAlterSchemaRename().runTest(this); new TestAlterSchemaRename().runTest(this);
new TestAutoRecompile().runTest(this); new TestAutoRecompile().runTest(this);
new TestBitField().runTest(this); new TestBitField().runTest(this);
new TestBnf().runTest(this);
new TestBackup().runTest(this); new TestBackup().runTest(this);
new TestBigDb().runTest(this); new TestBigDb().runTest(this);
new TestBigResult().runTest(this); new TestBigResult().runTest(this);
...@@ -752,6 +759,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -752,6 +759,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
// unit // unit
new TestAutoReconnect().runTest(this); new TestAutoReconnect().runTest(this);
new TestBnf().runTest(this);
new TestCache().runTest(this); new TestCache().runTest(this);
new TestClearReferences().runTest(this); new TestClearReferences().runTest(this);
new TestCollation().runTest(this); new TestCollation().runTest(this);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论