From 3d4d30e21690052c5277be327891770406aec9d7 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Tue, 15 Mar 2011 23:43:02 +0200 Subject: [PATCH] + add atomic key/check/rename to abstract redis collection (sort of messy) --- .../collections/AbstractRedisCollection.java | 54 +++++++++++++++++-- .../redis/support/BoundKeyOperationsTest.java | 33 ++++++------ .../redis/support/BoundKeyParams.java | 12 ++--- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/support/collections/AbstractRedisCollection.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/support/collections/AbstractRedisCollection.java index 3bd04f14d..2ef2337dc 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/support/collections/AbstractRedisCollection.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/support/collections/AbstractRedisCollection.java @@ -18,9 +18,12 @@ package org.springframework.data.keyvalue.redis.support.collections; import java.util.AbstractCollection; import java.util.Collection; import java.util.Date; +import java.util.List; import java.util.concurrent.TimeUnit; +import org.springframework.dao.DataAccessException; import org.springframework.data.keyvalue.redis.core.RedisOperations; +import org.springframework.data.keyvalue.redis.core.SessionCallback; /** * Base implementation for {@link RedisCollection}. @@ -140,14 +143,57 @@ public abstract class AbstractRedisCollection extends AbstractCollection i } @Override - public void rename(String newKey) { - operations.rename(key, newKey); + public void rename(final String newKey) { + operations.execute(new SessionCallback() { + @SuppressWarnings("unchecked") + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + do { + operations.watch(key); + + if (operations.hasKey(key)) { + operations.multi(); + operations.rename(key, newKey); + } + else { + operations.multi(); + } + } while (operations.exec() == null); + return null; + } + }); key = newKey; } @Override - public Boolean renameIfAbsent(String newKey) { - Boolean result = operations.renameIfAbsent(key, newKey); + public Boolean renameIfAbsent(final String newKey) { + Boolean result = operations.execute(new SessionCallback() { + @Override + public Boolean execute(RedisOperations operations) throws DataAccessException { + List exec = null; + do { + operations.watch(key); + + if (operations.hasKey(key)) { + operations.multi(); + operations.renameIfAbsent(key, newKey); + } + else { + operations.watch(newKey); + operations.multi(); + operations.hasKey(newKey); + operations.hasKey(newKey); + } + exec = operations.exec(); + } while (exec == null); + + boolean result = ((Long) exec.get(0) == 1); + if (exec.size()>1) { + result = !result; + } + return result; + } + }); if (Boolean.TRUE.equals(result)) { key = newKey; diff --git a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/support/BoundKeyOperationsTest.java b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/support/BoundKeyOperationsTest.java index 535cb4cf2..8f36bad53 100644 --- a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/support/BoundKeyOperationsTest.java +++ b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/support/BoundKeyOperationsTest.java @@ -27,9 +27,8 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.springframework.data.keyvalue.redis.ConnectionFactoryTracker; -import org.springframework.data.keyvalue.redis.connection.RedisConnection; -import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory; import org.springframework.data.keyvalue.redis.core.BoundKeyOperations; +import org.springframework.data.keyvalue.redis.core.RedisTemplate; import org.springframework.data.keyvalue.redis.support.collections.ObjectFactory; /** @@ -37,22 +36,20 @@ import org.springframework.data.keyvalue.redis.support.collections.ObjectFactory */ @RunWith(Parameterized.class) public class BoundKeyOperationsTest { - private RedisConnectionFactory factory; private BoundKeyOperations keyOps; private ObjectFactory objFactory; + private RedisTemplate template; public BoundKeyOperationsTest(BoundKeyOperations keyOps, ObjectFactory objFactory, - RedisConnectionFactory factory) { - this.factory = factory; + RedisTemplate template) { this.objFactory = objFactory; this.keyOps = keyOps; - ConnectionFactoryTracker.add(factory); + this.template = template; + ConnectionFactoryTracker.add(template.getConnectionFactory()); } @After public void stop() { - RedisConnection connection = factory.getConnection(); - connection.close(); } @AfterClass @@ -81,7 +78,8 @@ public class BoundKeyOperationsTest { Object key = keyOps.getKey(); assertNotNull(key); Object newName = objFactory.instance(); - keyOps.renameIfAbsent(newName); + assertFalse(template.hasKey(newName)); + assertTrue("cannot rename to key " + newName, keyOps.renameIfAbsent(newName)); assertEquals(newName, keyOps.getKey()); keyOps.rename(key); } @@ -89,17 +87,20 @@ public class BoundKeyOperationsTest { @Test public void testExpire() throws Exception { assertEquals(Long.valueOf(-1), keyOps.getExpire()); - assertTrue(keyOps.expire(10, TimeUnit.SECONDS)); - long expire = keyOps.getExpire().longValue(); - assertTrue(expire <= 10 && expire > 5); + if (keyOps.expire(10, TimeUnit.SECONDS)) { + long expire = keyOps.getExpire().longValue(); + assertTrue(expire <= 10 && expire > 5); + } } @Test public void testPersist() throws Exception { - assertEquals(Long.valueOf(-1), keyOps.getExpire()); - assertTrue(keyOps.expire(10, TimeUnit.SECONDS)); - assertTrue(keyOps.getExpire().longValue() > 0); keyOps.persist(); - assertTrue(keyOps.getExpire().longValue() > 0); + assertEquals(Long.valueOf(-1), keyOps.getExpire()); + if (keyOps.expire(10, TimeUnit.SECONDS)) { + assertTrue(keyOps.getExpire().longValue() > 0); + } + keyOps.persist(); + assertEquals(-1, keyOps.getExpire().longValue()); } } \ No newline at end of file diff --git a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/support/BoundKeyParams.java b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/support/BoundKeyParams.java index 21aa9462b..df2156509 100644 --- a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/support/BoundKeyParams.java +++ b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/support/BoundKeyParams.java @@ -55,18 +55,14 @@ public class BoundKeyParams { StringObjectFactory sof = new StringObjectFactory(); DefaultRedisMap mapJS = new DefaultRedisMap("bound:key:map", templateJS); - mapJS.put("foo", "bar"); DefaultRedisSet setJS = new DefaultRedisSet("bound:key:set", templateJS); - setJS.add("foo"); - + RedisList list = new DefaultRedisList("bound:key:list", templateJS); - list.add("foo"); return Arrays.asList(new Object[][] { - { new RedisAtomicInteger("bound:key:int", jedisConnFactory), sof, jedisConnFactory }, - { new RedisAtomicLong("bound:key:long", jedisConnFactory), sof, jedisConnFactory }, - { list, sof, jedisConnFactory }, - { setJS, sof, jedisConnFactory }, { mapJS, sof, jedisConnFactory } }); + { new RedisAtomicInteger("bound:key:int", jedisConnFactory), sof, templateJS }, + { new RedisAtomicLong("bound:key:long", jedisConnFactory), sof, templateJS }, + { list, sof, templateJS }, { setJS, sof, templateJS }, { mapJS, sof, templateJS } }); } }