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

MVStore: atomic operations

上级 d3cde13e
......@@ -582,13 +582,22 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*/
public synchronized boolean remove(Object key, Object value) {
V old = get(key);
if (old.equals(value)) {
if (equalsValue(old, value)) {
remove(key);
return true;
}
return false;
}
private boolean equalsValue(Object a, Object b) {
if (a == b) {
return true;
} else if (a == null || b == null) {
return false;
}
return valueType.compare(a, b) == 0;
}
/**
* Replace a value for an existing key, if the value matches.
*
......@@ -599,7 +608,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*/
public synchronized boolean replace(K key, V oldValue, V newValue) {
V old = get(key);
if (old.equals(oldValue)) {
if (equalsValue(old, oldValue)) {
put(key, newValue);
return true;
}
......@@ -611,7 +620,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*
* @param key the key (may not be null)
* @param value the new value
* @return true if the value was replaced
* @return the old value, if the value was replaced, or null
*/
public synchronized V replace(K key, V value) {
V old = get(key);
......
......@@ -49,7 +49,7 @@ TODO:
- additional test async write / read algorithm for speed and errors
- move setters to the builder, except for setRetainVersion, setReuseSpace,
and settings that are persistent (setStoreVersion)
- test & document meta table rollback: it is changed after save; could rollback break it?
- test meta rollback: it is changed after save; could rollback break it?
- automated 'kill process' and 'power failure' test
- update checkstyle
- maybe split database into multiple files, to speed up compact
......@@ -94,6 +94,7 @@ TODO:
to store committed changes
- to save space when persisting very small transactions,
-- use a transaction log where only the deltas are stored
- serialization for lists, sets, sets, sorted sets, maps, sorted maps
*/
......@@ -1680,7 +1681,7 @@ public class MVStore {
if (closed || unsavedPageCount == 0) {
return;
}
// could also store when there are many unstored pages,
// could also store when there are many unsaved pages,
// but according to a test it doesn't really help
if (lastCommittedVersion >= currentVersion) {
return;
......
......@@ -16,19 +16,23 @@ public class StringDataType implements DataType {
public static final StringDataType INSTANCE = new StringDataType();
@Override
public int compare(Object a, Object b) {
return a.toString().compareTo(b.toString());
}
@Override
public int getMemory(Object obj) {
return 24 + 2 * obj.toString().length();
}
@Override
public String read(ByteBuffer buff) {
int len = DataUtils.readVarInt(buff);
return DataUtils.readString(buff, len);
}
@Override
public ByteBuffer write(ByteBuffer buff, Object obj) {
String s = obj.toString();
int len = s.length();
......
......@@ -221,7 +221,8 @@ public class TestConcurrent extends TestMVStore {
assertTrue(notDetected.get() * 10 <= detected.get());
}
private void testConcurrentWrite(final AtomicInteger detected, final AtomicInteger notDetected) throws InterruptedException {
private void testConcurrentWrite(final AtomicInteger detected,
final AtomicInteger notDetected) throws InterruptedException {
final MVStore s = openStore(null);
final MVMap<Integer, Integer> m = s.openMap("data");
final int size = 20;
......
......@@ -42,6 +42,7 @@ public class TestMVStore extends TestBase {
FileUtils.deleteRecursive(getBaseDir(), true);
FileUtils.createDirectories(getBaseDir());
testAtomicOperations();
testWriteBuffer();
testWriteDelay();
testEncryptedFile();
......@@ -79,6 +80,41 @@ public class TestMVStore extends TestBase {
testSimple();
}
private void testAtomicOperations() {
String fileName = getBaseDir() + "/testAtomicOperations.h3";
FileUtils.delete(fileName);
MVStore s;
MVMap<Integer, byte[]> m;
s = new MVStore.Builder().
fileName(fileName).
open();
m = s.openMap("data");
// putIfAbsent
assertNull(m.putIfAbsent(1, new byte[1]));
assertEquals(1, m.putIfAbsent(1, new byte[2]).length);
assertEquals(1, m.get(1).length);
// replace
assertNull(m.replace(2, new byte[2]));
assertNull(m.get(2));
assertEquals(1, m.replace(1, new byte[2]).length);
assertEquals(2, m.replace(1, new byte[3]).length);
assertEquals(3, m.replace(1, new byte[1]).length);
// replace with oldValue
assertFalse(m.replace(1, new byte[2], new byte[10]));
assertTrue(m.replace(1, new byte[1], new byte[2]));
assertTrue(m.replace(1, new byte[2], new byte[1]));
// remove
assertFalse(m.remove(1, new byte[2]));
assertTrue(m.remove(1, new byte[1]));
s.close();
FileUtils.delete(fileName);
}
private void testWriteBuffer() throws IOException {
String fileName = getBaseDir() + "/testAutoStoreBuffer.h3";
FileUtils.delete(fileName);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论