Skip to content

Commit

Permalink
INT-3604: Add transactionsfor RedisLockRegistry
Browse files Browse the repository at this point in the history
JIRA: https://jira.spring.io/browse/INT-3604

There is no test-case to cover the issue, because it isn't so easy to emulate the network glitch between `setIfAbsent` and `expire`
  • Loading branch information
kiakimov authored and artembilan committed Jan 13, 2015
1 parent ec8e8cc commit 48f9801
Showing 1 changed file with 31 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,8 +37,10 @@
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;
Expand Down Expand Up @@ -315,16 +317,39 @@ private boolean obtainLock() {
*/
this.lockedAt = System.currentTimeMillis();
this.threadName = currentThread.getName();
Boolean success = RedisLockRegistry.this.redisTemplate.boundValueOps(
constructLockKey()).setIfAbsent(this);

Boolean success = RedisLockRegistry.this.redisTemplate.execute(new SessionCallback<Boolean>() {

@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Boolean execute(RedisOperations ops) throws DataAccessException {
String key = constructLockKey();

ops.watch(key); //monitor key

ops.multi(); //transaction start

//can't rely on operations result inside transaction, execution is delayed till `exec()`
ops.opsForValue().setIfAbsent(key, RedisLock.this);

//set expire on key if exists
ops.expire(key, RedisLockRegistry.this.expireAfter, TimeUnit.MILLISECONDS);

//exec will contain all operations result or null - if execution has been aborted due to 'watch'
List result = ops.exec();

//check 'setIfAbsent' result (first in list)
return (result != null) && (!result.isEmpty()) && (Boolean.TRUE.equals(result.get(0)));
}

});

if (!success) {
this.lockedAt = 0;
this.threadName = null;
}
else {
this.thread = currentThread;
RedisLockRegistry.this.redisTemplate.expire(constructLockKey(),
RedisLockRegistry.this.expireAfter, TimeUnit.MILLISECONDS);
if (logger.isDebugEnabled()) {
logger.debug("New lock; " + this.toString());
}
Expand Down

0 comments on commit 48f9801

Please sign in to comment.