Unverified 提交 ce5690e6 authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #797 from katzyn/TransactionMap2

Add ceilingKey() and floorKey() to TransactionMap (version 2)
...@@ -228,9 +228,9 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -228,9 +228,9 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex {
} }
private void requireUnique(SearchRow row, TransactionMap<Value, Value> map, ValueArray unique) { private void requireUnique(SearchRow row, TransactionMap<Value, Value> map, ValueArray unique) {
Iterator<Value> it = map.keyIterator(unique); Value key = map.ceilingKey(unique);
if (it.hasNext()) { if (key != null) {
ValueArray k = (ValueArray) it.next(); ValueArray k = (ValueArray) key;
if (compareRows(row, convertToSearchRow(k)) == 0) { if (compareRows(row, convertToSearchRow(k)) == 0) {
// committed // committed
throw getDuplicateKeyException(k.toString()); throw getDuplicateKeyException(k.toString());
......
...@@ -1320,15 +1320,10 @@ public class TransactionStore { ...@@ -1320,15 +1320,10 @@ public class TransactionStore {
*/ */
public K lastKey() { public K lastKey() {
K k = map.lastKey(); K k = map.lastKey();
while (true) { while (k != null && get(k) == null) {
if (k == null) {
return null;
}
if (get(k) != null) {
return k;
}
k = map.lowerKey(k); k = map.lowerKey(k);
} }
return k;
} }
/** /**
...@@ -1339,13 +1334,22 @@ public class TransactionStore { ...@@ -1339,13 +1334,22 @@ public class TransactionStore {
* @return the result * @return the result
*/ */
public K higherKey(K key) { public K higherKey(K key) {
while (true) { do {
K k = map.higherKey(key); key = map.higherKey(key);
if (k == null || get(k) != null) { } while (key != null && get(key) == null);
return k; return key;
}
key = k;
} }
/**
* Get the smallest key that is larger than or equal to this key,
* or null if no such key exists.
*
* @param key the key (may not be null)
* @return the result
*/
public K ceilingKey(K key) {
Iterator<K> it = keyIterator(key);
return it.hasNext() ? it.next() : null;
} }
/** /**
...@@ -1365,6 +1369,22 @@ public class TransactionStore { ...@@ -1365,6 +1369,22 @@ public class TransactionStore {
return map.getKey(index + offset); return map.getKey(index + offset);
} }
/**
* Get the largest key that is smaller than or equal to this key,
* or null if no such key exists.
*
* @param key the key (may not be null)
* @return the result
*/
public K floorKey(K key) {
key = map.floorKey(key);
while (key != null && get(key) == null) {
// Use lowerKey() for the next attempts, otherwise we'll get an infinite loop
key = map.lowerKey(key);
}
return key;
}
/** /**
* Get the largest key that is smaller than the given key, or null if no * Get the largest key that is smaller than the given key, or null if no
* such key exists. * such key exists.
...@@ -1373,13 +1393,10 @@ public class TransactionStore { ...@@ -1373,13 +1393,10 @@ public class TransactionStore {
* @return the result * @return the result
*/ */
public K lowerKey(K key) { public K lowerKey(K key) {
while (true) { do {
K k = map.lowerKey(key); key = map.lowerKey(key);
if (k == null || get(k) != null) { } while (key != null && get(key) == null);
return k; return key;
}
key = k;
}
} }
/** /**
......
...@@ -22,6 +22,7 @@ import org.h2.mvstore.db.TransactionStore; ...@@ -22,6 +22,7 @@ import org.h2.mvstore.db.TransactionStore;
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.mvstore.db.TransactionStore.TransactionMap; import org.h2.mvstore.db.TransactionStore.TransactionMap;
import org.h2.mvstore.type.ObjectDataType;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.util.New; import org.h2.util.New;
...@@ -44,6 +45,7 @@ public class TestTransactionStore extends TestBase { ...@@ -44,6 +45,7 @@ public class TestTransactionStore extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
FileUtils.createDirectories(getBaseDir()); FileUtils.createDirectories(getBaseDir());
testHCLFKey();
testConcurrentAddRemove(); testConcurrentAddRemove();
testConcurrentAdd(); testConcurrentAdd();
testCountWithOpenTransactions(); testCountWithOpenTransactions();
...@@ -62,6 +64,52 @@ public class TestTransactionStore extends TestBase { ...@@ -62,6 +64,52 @@ public class TestTransactionStore extends TestBase {
testStoreMultiThreadedReads(); testStoreMultiThreadedReads();
} }
private void testHCLFKey() {
MVStore s = MVStore.open(null);
final TransactionStore ts = new TransactionStore(s);
ts.init();
Transaction t = ts.begin();
ObjectDataType keyType = new ObjectDataType();
TransactionMap<Long, Long> map = t.openMap("test", keyType, keyType);
// firstKey()
assertNull(map.firstKey());
// lastKey()
assertNull(map.lastKey());
map.put(10L, 100L);
map.put(20L, 200L);
map.put(30L, 300L);
map.put(40L, 400L);
t.commit();
t = ts.begin();
map = t.openMap("test", keyType, keyType);
map.put(15L, 150L);
// The same transaction
assertEquals((Object) 15L, map.higherKey(10L));
t = ts.begin();
map = t.openMap("test", keyType, keyType);
// Another transaction
// higherKey()
assertEquals((Object) 20L, map.higherKey(10L));
assertEquals((Object) 20L, map.higherKey(15L));
assertNull(map.higherKey(40L));
// ceilingKey()
assertEquals((Object) 10L, map.ceilingKey(10L));
assertEquals((Object) 20L, map.ceilingKey(15L));
assertEquals((Object) 40L, map.ceilingKey(40L));
assertNull(map.higherKey(45L));
// lowerKey()
assertNull(map.lowerKey(10L));
assertEquals((Object) 10L, map.lowerKey(15L));
assertEquals((Object) 10L, map.lowerKey(20L));
assertEquals((Object) 20L, map.lowerKey(25L));
// floorKey()
assertNull(map.floorKey(5L));
assertEquals((Object) 10L, map.floorKey(10L));
assertEquals((Object) 10L, map.floorKey(15L));
assertEquals((Object) 30L, map.floorKey(35L));
s.close();
}
private static void testConcurrentAddRemove() throws InterruptedException { private static void testConcurrentAddRemove() throws InterruptedException {
MVStore s = MVStore.open(null); MVStore s = MVStore.open(null);
int threadCount = 3; int threadCount = 3;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论