Skip to content

Commit 7024ef3

Browse files
christophstroblmp911de
authored andcommitted
DATAREDIS-468 - Guard multi/exec bocks in RedisCache to allow usage with cluster.
We now guard multi/exec blocks by checking the connection type. This allows to skip those commands when running in cluster. Original pull request: spring-projects#173.
1 parent 02742e3 commit 7024ef3

File tree

2 files changed

+68
-5
lines changed

2 files changed

+68
-5
lines changed

src/main/java/org/springframework/data/redis/cache/RedisCache.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.cache.support.SimpleValueWrapper;
2929
import org.springframework.dao.DataAccessException;
3030
import org.springframework.data.redis.RedisSystemException;
31+
import org.springframework.data.redis.connection.RedisClusterConnection;
3132
import org.springframework.data.redis.connection.RedisConnection;
3233
import org.springframework.data.redis.connection.ReturnType;
3334
import org.springframework.data.redis.core.RedisCallback;
@@ -670,14 +671,18 @@ public RedisCachePutCallback(BinaryRedisCacheElement element, RedisCacheMetadata
670671
@Override
671672
public Void doInRedis(BinaryRedisCacheElement element, RedisConnection connection) throws DataAccessException {
672673

673-
connection.multi();
674+
if (!isClusterConnection(connection)) {
675+
connection.multi();
676+
}
674677

675678
connection.set(element.getKeyBytes(), element.get());
676679

677680
processKeyExpiration(element, connection);
678681
maintainKnownKeys(element, connection);
679682

680-
connection.exec();
683+
if (!isClusterConnection(connection)) {
684+
connection.exec();
685+
}
681686
return null;
682687
}
683688
}
@@ -742,16 +747,21 @@ public byte[] doInRedis(BinaryRedisCacheElement element, RedisConnection connect
742747
return value;
743748
}
744749

745-
connection.watch(element.getKeyBytes());
746-
connection.multi();
750+
if (!isClusterConnection(connection)) {
751+
752+
connection.watch(element.getKeyBytes());
753+
connection.multi();
754+
}
747755

748756
value = element.get();
749757
connection.set(element.getKeyBytes(), value);
750758

751759
processKeyExpiration(element, connection);
752760
maintainKnownKeys(element, connection);
753761

754-
connection.exec();
762+
if (!isClusterConnection(connection)) {
763+
connection.exec();
764+
}
755765

756766
return value;
757767
} catch (RuntimeException e) {
@@ -799,4 +809,8 @@ public RuntimeException create(Object key, Callable<?> valueLoader, Throwable ca
799809
}
800810
}
801811

812+
private static boolean isClusterConnection(RedisConnection connection) {
813+
return connection instanceof RedisClusterConnection;
814+
}
815+
802816
}

src/test/java/org/springframework/data/redis/cache/RedisCacheUnitTests.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.mockito.Mock;
3232
import org.mockito.runners.MockitoJUnitRunner;
3333
import org.springframework.data.redis.RedisSystemException;
34+
import org.springframework.data.redis.connection.RedisClusterConnection;
3435
import org.springframework.data.redis.connection.RedisConnection;
3536
import org.springframework.data.redis.connection.RedisConnectionFactory;
3637
import org.springframework.data.redis.connection.ReturnType;
@@ -217,4 +218,52 @@ public void getWithCallableShouldNotReadValueFromCallableWhenAlreadyPresent() {
217218
verifyZeroInteractions(callableMock);
218219
}
219220

221+
/**
222+
* @see DATAREDIS-468
223+
*/
224+
@Test
225+
public void noMultiExecForCluster() {
226+
227+
RedisClusterConnection clusterConnectionMock = mock(RedisClusterConnection.class);
228+
when(connectionFactoryMock.getConnection()).thenReturn(clusterConnectionMock);
229+
230+
cache = new RedisCache(CACHE_NAME, NO_PREFIX_BYTES, templateSpy, 0L);
231+
232+
when(connectionMock.exists(KEY_BYTES)).thenReturn(true);
233+
when(connectionMock.get(KEY_BYTES)).thenReturn(null).thenReturn(VALUE_BYTES);
234+
235+
cache.put(KEY, VALUE);
236+
237+
verify(clusterConnectionMock, times(1)).set(eq(KEY_BYTES), eq(VALUE_BYTES));
238+
verify(clusterConnectionMock, never()).multi();
239+
verify(clusterConnectionMock, never()).exec();
240+
verifyZeroInteractions(connectionMock);
241+
}
242+
243+
/**
244+
* @see DATAREDIS-468
245+
*/
246+
@Test
247+
public void getWithCallableForCluster() {
248+
249+
RedisClusterConnection clusterConnectionMock = mock(RedisClusterConnection.class);
250+
when(connectionFactoryMock.getConnection()).thenReturn(clusterConnectionMock);
251+
252+
cache = new RedisCache(CACHE_NAME, NO_PREFIX_BYTES, templateSpy, 0L);
253+
254+
cache.get(KEY, new Callable<Object>() {
255+
@Override
256+
public Object call() throws Exception {
257+
return VALUE;
258+
}
259+
});
260+
261+
verify(clusterConnectionMock, times(2)).get(eq(KEY_BYTES));
262+
verify(clusterConnectionMock, times(1)).set(eq(KEY_BYTES), eq(VALUE_BYTES));
263+
264+
verify(clusterConnectionMock, never()).multi();
265+
verify(clusterConnectionMock, never()).exec();
266+
verifyZeroInteractions(connectionMock);
267+
}
268+
220269
}

0 commit comments

Comments
 (0)