Unverified 提交 d5276a72 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1476 from katzyn/mv

Add TransactionStore to MVStore jar
...@@ -14,8 +14,10 @@ Bundle-Vendor: H2 Group ...@@ -14,8 +14,10 @@ Bundle-Vendor: H2 Group
Bundle-Version: ${version} Bundle-Version: ${version}
Bundle-License: http://www.h2database.com/html/license.html Bundle-License: http://www.h2database.com/html/license.html
Bundle-Category: utility Bundle-Category: utility
Multi-Release: true
Import-Package: javax.crypto, Import-Package: javax.crypto,
javax.crypto.spec javax.crypto.spec
Export-Package: org.h2.mvstore;version="${version}", Export-Package: org.h2.mvstore;version="${version}",
org.h2.mvstore.tx;version="${version}",
org.h2.mvstore.type;version="${version}", org.h2.mvstore.type;version="${version}",
org.h2.mvstore.rtree;version="${version}" org.h2.mvstore.rtree;version="${version}"
...@@ -391,6 +391,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -391,6 +391,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* *
* @param key the key * @param key the key
* @return the value, or null if not found * @return the value, or null if not found
* @throws ClassCastException if type of the specified key is not compatible with this map
*/ */
@Override @Override
public final V get(Object key) { public final V get(Object key) {
...@@ -403,6 +404,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -403,6 +404,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* @param p the root of a snapshot * @param p the root of a snapshot
* @param key the key * @param key the key
* @return the value, or null if not found * @return the value, or null if not found
* @throws ClassCastException if type of the specified key is not compatible with this map
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public V get(Page p, Object key) { public V get(Page p, Object key) {
...@@ -445,6 +447,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -445,6 +447,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* *
* @param key the key (may not be null) * @param key the key (may not be null)
* @return the old value if the key existed, or null otherwise * @return the old value if the key existed, or null otherwise
* @throws ClassCastException if type of the specified key is not compatible with this map
*/ */
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -950,10 +953,11 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -950,10 +953,11 @@ public class MVMap<K, V> extends AbstractMap<K, V>
} }
/** /**
* Get the number of entries, as a integer. Integer.MAX_VALUE is returned if * Get the number of entries, as a integer. {@link Integer#MAX_VALUE} is
* there are more than this entries. * returned if there are more than this entries.
* *
* @return the number of entries, as an integer * @return the number of entries, as an integer
* @see #sizeAsLong()
*/ */
@Override @Override
public final int size() { public final int size() {
......
...@@ -12,18 +12,27 @@ import org.h2.mvstore.Page; ...@@ -12,18 +12,27 @@ import org.h2.mvstore.Page;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.BitSet; import java.util.BitSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set;
/** /**
* A map that supports transactions. * A map that supports transactions.
* *
* <p>
* <b>Methods of this class may be changed at any time without notice.</b> If
* you use this class directly make sure that your application or library
* requires exactly the same version of MVStore or H2 jar as the version that
* you use during its development and build.
* </p>
*
* @param <K> the key type * @param <K> the key type
* @param <V> the value type * @param <V> the value type
*/ */
public class TransactionMap<K, V> { public class TransactionMap<K, V> extends AbstractMap<K, V> {
/** /**
* The map used for writing (the latest version). * The map used for writing (the latest version).
...@@ -53,6 +62,19 @@ public class TransactionMap<K, V> { ...@@ -53,6 +62,19 @@ public class TransactionMap<K, V> {
return new TransactionMap<>(transaction, map); return new TransactionMap<>(transaction, map);
} }
/**
* Get the number of entries, as a integer. {@link Integer#MAX_VALUE} is
* returned if there are more than this entries.
*
* @return the number of entries, as an integer
* @see #sizeAsLong()
*/
@Override
public final int size() {
long size = sizeAsLong();
return size > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) size;
}
/** /**
* Get the size of the raw map. This includes uncommitted entries, and * Get the size of the raw map. This includes uncommitted entries, and
* transiently removed entries, so it is the maximum number of entries. * transiently removed entries, so it is the maximum number of entries.
...@@ -177,8 +199,10 @@ public class TransactionMap<K, V> { ...@@ -177,8 +199,10 @@ public class TransactionMap<K, V> {
* *
* @param key the key * @param key the key
* @throws IllegalStateException if a lock timeout occurs * @throws IllegalStateException if a lock timeout occurs
* @throws ClassCastException if type of the specified key is not compatible with this map
*/ */
public V remove(K key) { @Override
public V remove(Object key) {
return set(key, (V)null); return set(key, (V)null);
} }
...@@ -193,6 +217,7 @@ public class TransactionMap<K, V> { ...@@ -193,6 +217,7 @@ public class TransactionMap<K, V> {
* @return the old value * @return the old value
* @throws IllegalStateException if a lock timeout occurs * @throws IllegalStateException if a lock timeout occurs
*/ */
@Override
public V put(K key, V value) { public V put(K key, V value) {
DataUtils.checkArgument(value != null, "The value may not be null"); DataUtils.checkArgument(value != null, "The value may not be null");
return set(key, value); return set(key, value);
...@@ -207,6 +232,7 @@ public class TransactionMap<K, V> { ...@@ -207,6 +232,7 @@ public class TransactionMap<K, V> {
* @param value the new value (not null) * @param value the new value (not null)
* @return the old value * @return the old value
*/ */
// Do not add @Override, code should be compatible with Java 7
public V putIfAbsent(K key, V value) { public V putIfAbsent(K key, V value) {
DataUtils.checkArgument(value != null, "The value may not be null"); DataUtils.checkArgument(value != null, "The value may not be null");
TxDecisionMaker decisionMaker = new TxDecisionMaker.PutIfAbsentDecisionMaker(map.getId(), key, value, TxDecisionMaker decisionMaker = new TxDecisionMaker.PutIfAbsentDecisionMaker(map.getId(), key, value,
...@@ -245,12 +271,12 @@ public class TransactionMap<K, V> { ...@@ -245,12 +271,12 @@ public class TransactionMap<K, V> {
return result; return result;
} }
private V set(K key, V value) { private V set(Object key, V value) {
TxDecisionMaker decisionMaker = new TxDecisionMaker.PutDecisionMaker(map.getId(), key, value, transaction); TxDecisionMaker decisionMaker = new TxDecisionMaker.PutDecisionMaker(map.getId(), key, value, transaction);
return set(key, decisionMaker); return set(key, decisionMaker);
} }
private V set(K key, TxDecisionMaker decisionMaker) { private V set(Object key, TxDecisionMaker decisionMaker) {
TransactionStore store = transaction.store; TransactionStore store = transaction.store;
Transaction blockingTransaction; Transaction blockingTransaction;
long sequenceNumWhenStarted; long sequenceNumWhenStarted;
...@@ -262,7 +288,9 @@ public class TransactionMap<K, V> { ...@@ -262,7 +288,9 @@ public class TransactionMap<K, V> {
// since TxDecisionMaker has it embedded, // since TxDecisionMaker has it embedded,
// MVRTreeMap has weird traversal logic based on it, // MVRTreeMap has weird traversal logic based on it,
// and any non-null value will do // and any non-null value will do
result = map.put(key, VersionedValue.DUMMY, decisionMaker); @SuppressWarnings("unchecked")
K k = (K) key;
result = map.put(k, VersionedValue.DUMMY, decisionMaker);
MVMap.Decision decision = decisionMaker.getDecision(); MVMap.Decision decision = decisionMaker.getDecision();
assert decision != null; assert decision != null;
...@@ -342,9 +370,11 @@ public class TransactionMap<K, V> { ...@@ -342,9 +370,11 @@ public class TransactionMap<K, V> {
* *
* @param key the key * @param key the key
* @return the value or null * @return the value or null
* @throws ClassCastException if type of the specified key is not compatible with this map
*/ */
@Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public V get(K key) { public V get(Object key) {
VersionedValue data = map.get(key); VersionedValue data = map.get(key);
if (data == null) { if (data == null) {
// doesn't exist or deleted by a committed transaction // doesn't exist or deleted by a committed transaction
...@@ -369,8 +399,10 @@ public class TransactionMap<K, V> { ...@@ -369,8 +399,10 @@ public class TransactionMap<K, V> {
* *
* @param key the key * @param key the key
* @return true if the map contains an entry for this key * @return true if the map contains an entry for this key
* @throws ClassCastException if type of the specified key is not compatible with this map
*/ */
public boolean containsKey(K key) { @Override
public boolean containsKey(Object key) {
return get(key) != null; return get(key) != null;
} }
...@@ -403,11 +435,34 @@ public class TransactionMap<K, V> { ...@@ -403,11 +435,34 @@ public class TransactionMap<K, V> {
/** /**
* Clear the map. * Clear the map.
*/ */
@Override
public void clear() { public void clear() {
// TODO truncate transactionally? // TODO truncate transactionally?
map.clear(); map.clear();
} }
@Override
public Set<Entry<K, V>> entrySet() {
return new AbstractSet<Entry<K, V>>() {
@Override
public Iterator<Entry<K, V>> iterator() {
return entryIterator(null, null);
}
@Override
public int size() {
return TransactionMap.this.size();
}
@Override
public boolean contains(Object o) {
return TransactionMap.this.containsKey(o);
}
};
}
/** /**
* Get the first key. * Get the first key.
* *
...@@ -693,4 +748,5 @@ public class TransactionMap<K, V> { ...@@ -693,4 +748,5 @@ public class TransactionMap<K, V> {
"Removal is not supported"); "Removal is not supported");
} }
} }
} }
...@@ -12,7 +12,7 @@ import org.h2.mvstore.MVMap; ...@@ -12,7 +12,7 @@ import org.h2.mvstore.MVMap;
* *
* @author <a href='mailto:andrei.tokar@gmail.com'>Andrei Tokar</a> * @author <a href='mailto:andrei.tokar@gmail.com'>Andrei Tokar</a>
*/ */
public abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
private final int mapId; private final int mapId;
private final Object key; private final Object key;
final Object value; final Object value;
......
...@@ -13,6 +13,7 @@ import java.sql.Statement; ...@@ -13,6 +13,7 @@ import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry;
import java.util.Random; import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
...@@ -235,6 +236,7 @@ public class TestTransactionStore extends TestBase { ...@@ -235,6 +236,7 @@ public class TestTransactionStore extends TestBase {
Random r = new Random(1); Random r = new Random(1);
for (int i = 0; i < size * 3; i++) { for (int i = 0; i < size * 3; i++) {
assertEquals("op: " + i, size, map1.size());
assertEquals("op: " + i, size, (int) map1.sizeAsLong()); assertEquals("op: " + i, size, (int) map1.sizeAsLong());
// keep the first 10%, and add 10% // keep the first 10%, and add 10%
int k = size / 10 + r.nextInt(size); int k = size / 10 + r.nextInt(size);
...@@ -507,6 +509,7 @@ public class TestTransactionStore extends TestBase { ...@@ -507,6 +509,7 @@ public class TestTransactionStore extends TestBase {
Transaction tx, tx2; Transaction tx, tx2;
TransactionMap<String, String> m, m2; TransactionMap<String, String> m, m2;
Iterator<String> it, it2; Iterator<String> it, it2;
Iterator<Entry<String, String>> entryIt;
tx = ts.begin(); tx = ts.begin();
m = tx.openMap("test"); m = tx.openMap("test");
...@@ -532,6 +535,15 @@ public class TestTransactionStore extends TestBase { ...@@ -532,6 +535,15 @@ public class TestTransactionStore extends TestBase {
assertEquals("3", it.next()); assertEquals("3", it.next());
assertFalse(it.hasNext()); assertFalse(it.hasNext());
entryIt = m.entrySet().iterator();
assertTrue(entryIt.hasNext());
assertEquals("1", entryIt.next().getKey());
assertTrue(entryIt.hasNext());
assertEquals("2", entryIt.next().getKey());
assertTrue(entryIt.hasNext());
assertEquals("3", entryIt.next().getKey());
assertFalse(entryIt.hasNext());
it2 = m2.keyIterator(null); it2 = m2.keyIterator(null);
assertTrue(it2.hasNext()); assertTrue(it2.hasNext());
assertEquals("1", it2.next()); assertEquals("1", it2.next());
......
...@@ -240,8 +240,7 @@ public class Build extends BuildBase { ...@@ -240,8 +240,7 @@ public class Build extends BuildBase {
String classpath = "temp"; String classpath = "temp";
FileList files; FileList files;
files = files("src/main/org/h2/mvstore"). files = files("src/main/org/h2/mvstore").
exclude("src/main/org/h2/mvstore/db/*"). exclude("src/main/org/h2/mvstore/db/*");
exclude("src/main/org/h2/mvstore/tx/*");
StringList args = args(); StringList args = args();
if (debugInfo) { if (debugInfo) {
args = args.plus("-Xlint:unchecked", "-d", "temp", "-sourcepath", args = args.plus("-Xlint:unchecked", "-d", "temp", "-sourcepath",
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论