+ add initial draft for ConcurrentMap contract to RedisMap
+ add disabled integration tests (need to find a way to reuse the same connection) w/o transactions
This commit is contained in:
@@ -28,6 +28,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.keyvalue.redis.connection.RedisConnection;
|
||||
import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.keyvalue.redis.serializer.RedisSerializer;
|
||||
@@ -320,7 +321,13 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
|
||||
@Override
|
||||
public Object exec() {
|
||||
throw new UnsupportedOperationException();
|
||||
return execute(new RedisCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInRedis(RedisConnection connection) throws DataAccessException {
|
||||
return connection.exec();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -379,7 +386,13 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
|
||||
|
||||
@Override
|
||||
public void multi() {
|
||||
throw new UnsupportedOperationException();
|
||||
execute(new RedisCallback<Object>() {
|
||||
@Override
|
||||
public Object doInRedis(RedisConnection connection) throws DataAccessException {
|
||||
connection.multi();
|
||||
return null;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -83,15 +83,6 @@ public class DefaultRedisMap<K, V> implements RedisMap<K, V> {
|
||||
return hashOps.increment(key, delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putIfAbsent(K key, V value) {
|
||||
if (!hashOps.hasKey(key)) {
|
||||
put(key, value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return hashOps.getKey();
|
||||
@@ -203,4 +194,104 @@ public class DefaultRedisMap<K, V> implements RedisMap<K, V> {
|
||||
sb.append(getKey());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putIfAbsent(K key, V value) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
// RedisOperations<String, ?> ops = hashOps.getOperations();
|
||||
//
|
||||
// for (;;) {
|
||||
// ops.watch(getKey());
|
||||
// V v = get(key);
|
||||
// if (v == null) {
|
||||
// ops.multi();
|
||||
// put(key, value);
|
||||
// if (ops.exec() != null) {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// return v;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object key, Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
// if (value == null){
|
||||
// throw new NullPointerException();
|
||||
// }
|
||||
//
|
||||
// RedisOperations<String, ?> ops = hashOps.getOperations();
|
||||
//
|
||||
// for (;;) {
|
||||
// ops.watch(getKey());
|
||||
// V v = get(key);
|
||||
// if (value.equals(v)) {
|
||||
// ops.multi();
|
||||
// remove(key);
|
||||
// if (ops.exec() != null) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replace(K key, V oldValue, V newValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
// if (newValue == null || oldValue == null) {
|
||||
// throw new NullPointerException();
|
||||
// }
|
||||
//
|
||||
// RedisOperations<String, ?> ops = hashOps.getOperations();
|
||||
//
|
||||
// for (;;) {
|
||||
// ops.watch(getKey());
|
||||
// V v = get(key);
|
||||
// if (oldValue.equals(v)) {
|
||||
// ops.multi();
|
||||
// put(key, newValue);
|
||||
// if (ops.exec() != null) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public V replace(K key, V value) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
|
||||
// if (value == null) {
|
||||
// throw new NullPointerException();
|
||||
// }
|
||||
//
|
||||
// RedisOperations<String, ?> ops = hashOps.getOperations();
|
||||
//
|
||||
// for (;;) {
|
||||
// ops.watch(getKey());
|
||||
// if (containsKey(key)) {
|
||||
// ops.multi();
|
||||
// V oldValue = put(key, value);
|
||||
// if (ops.exec() != null) {
|
||||
// return oldValue;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,9 @@ public class RedisAtomicInteger extends Number implements Serializable {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,9 @@ public class RedisAtomicLong extends Number implements Serializable {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,16 +15,15 @@
|
||||
*/
|
||||
package org.springframework.data.keyvalue.redis.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
|
||||
/**
|
||||
* Map view of a Redis hash.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public interface RedisMap<K, V> extends RedisStore<String>, Map<K, V> {
|
||||
|
||||
boolean putIfAbsent(K key, V value);
|
||||
public interface RedisMap<K, V> extends RedisStore<String>, ConcurrentMap<K, V> {
|
||||
|
||||
Integer increment(K key, int delta);
|
||||
}
|
||||
|
||||
@@ -269,25 +269,6 @@ public abstract class AbstractRedisMapTests<K, V> {
|
||||
assertEquals(v2, map.get(k2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutIfAbsent() {
|
||||
K k1 = getKey();
|
||||
K k2 = getKey();
|
||||
|
||||
V v1 = getValue();
|
||||
V v2 = getValue();
|
||||
|
||||
assertNull(map.get(k1));
|
||||
assertTrue(map.putIfAbsent(k1, v1));
|
||||
assertFalse(map.putIfAbsent(k1, v2));
|
||||
assertEquals(v1, map.get(k1));
|
||||
|
||||
assertTrue(map.putIfAbsent(k2, v2));
|
||||
assertFalse(map.putIfAbsent(k2, v1));
|
||||
|
||||
assertEquals(v2, map.get(k2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemove() {
|
||||
K k1 = getKey();
|
||||
@@ -375,4 +356,65 @@ public abstract class AbstractRedisMapTests<K, V> {
|
||||
assertThat(values, hasItem(v1));
|
||||
assertThat(values, not(hasItem(v2)));
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testConcurrentPutIfAbsent() {
|
||||
K k1 = getKey();
|
||||
K k2 = getKey();
|
||||
|
||||
V v1 = getValue();
|
||||
V v2 = getValue();
|
||||
|
||||
assertNull(map.get(k1));
|
||||
assertNull(map.putIfAbsent(k1, v1));
|
||||
assertEquals(v1, map.putIfAbsent(k1, v2));
|
||||
assertEquals(v1, map.get(k1));
|
||||
|
||||
assertNull(map.putIfAbsent(k2, v2));
|
||||
assertEquals(v2, map.putIfAbsent(k2, v1));
|
||||
|
||||
assertEquals(v2, map.get(k2));
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testConcurrentRemove() {
|
||||
K k1 = getKey();
|
||||
V v1 = getValue();
|
||||
V v2 = getValue();
|
||||
|
||||
map.put(k1, v1);
|
||||
assertFalse(map.remove(k1, v1));
|
||||
assertEquals(v1, map.get(k1));
|
||||
assertTrue(map.remove(k1, v1));
|
||||
assertNull(map.get(k1));
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testConcurrentReplaceTwoArgs() {
|
||||
K k1 = getKey();
|
||||
V v1 = getValue();
|
||||
V v2 = getValue();
|
||||
|
||||
map.put(k1, v1);
|
||||
|
||||
assertFalse(map.replace(k1, v2, v1));
|
||||
assertEquals(v1, map.get(k1));
|
||||
assertTrue(map.replace(k1, v1, v2));
|
||||
assertEquals(v2, map.get(k1));
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testConcurrentReplaceOneArg() {
|
||||
K k1 = getKey();
|
||||
V v1 = getValue();
|
||||
V v2 = getValue();
|
||||
|
||||
assertNull(map.replace(k1, v1));
|
||||
map.put(k1, v1);
|
||||
assertNull(map.replace(getKey(), v1));
|
||||
assertEquals(v1, map.replace(k1, v2));
|
||||
assertEquals(v2, map.get(k1));
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user