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 {
}
private void requireUnique(SearchRow row, TransactionMap<Value, Value> map, ValueArray unique) {
Iterator<Value> it = map.keyIterator(unique);
if (it.hasNext()) {
ValueArray k = (ValueArray) it.next();
Value key = map.ceilingKey(unique);
if (key != null) {
ValueArray k = (ValueArray) key;
if (compareRows(row, convertToSearchRow(k)) == 0) {
// committed
throw getDuplicateKeyException(k.toString());
......
......@@ -1320,15 +1320,10 @@ public class TransactionStore {
*/
public K lastKey() {
K k = map.lastKey();
while (true) {
if (k == null) {
return null;
}
if (get(k) != null) {
return k;
}
while (k != null && get(k) == null) {
k = map.lowerKey(k);
}
return k;
}
/**
......@@ -1339,13 +1334,22 @@ public class TransactionStore {
* @return the result
*/
public K higherKey(K key) {
while (true) {
K k = map.higherKey(key);
if (k == null || get(k) != null) {
return k;
}
key = k;
do {
key = map.higherKey(key);
} while (key != null && get(key) == null);
return key;
}
/**
* 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 {
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
* such key exists.
......@@ -1373,13 +1393,10 @@ public class TransactionStore {
* @return the result
*/
public K lowerKey(K key) {
while (true) {
K k = map.lowerKey(key);
if (k == null || get(k) != null) {
return k;
}
key = k;
}
do {
key = map.lowerKey(key);
} while (key != null && get(key) == null);
return key;
}
/**
......
......@@ -22,6 +22,7 @@ import org.h2.mvstore.db.TransactionStore;
import org.h2.mvstore.db.TransactionStore.Change;
import org.h2.mvstore.db.TransactionStore.Transaction;
import org.h2.mvstore.db.TransactionStore.TransactionMap;
import org.h2.mvstore.type.ObjectDataType;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
import org.h2.util.New;
......@@ -44,6 +45,7 @@ public class TestTransactionStore extends TestBase {
@Override
public void test() throws Exception {
FileUtils.createDirectories(getBaseDir());
testHCLFKey();
testConcurrentAddRemove();
testConcurrentAdd();
testCountWithOpenTransactions();
......@@ -62,6 +64,52 @@ public class TestTransactionStore extends TestBase {
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 {
MVStore s = MVStore.open(null);
int threadCount = 3;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论