in server/src/main/java/org/apache/seata/server/storage/redis/store/RedisTransactionStoreManager.java [337:407]
protected boolean updateGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) {
String xid = globalTransactionDO.getXid();
String globalKey = buildGlobalKeyByTransactionId(globalTransactionDO.getTransactionId());
Integer status = globalTransactionDO.getStatus();
try (Jedis jedis = JedisPooledFactory.getJedisInstance()) {
// Defensive watch to prevent other TC server operating concurrently,Fail fast
jedis.watch(globalKey);
List<String> statusAndGmtModified = jedis.hmget(globalKey, REDIS_KEY_GLOBAL_STATUS, REDIS_KEY_GLOBAL_GMT_MODIFIED);
String previousStatus = statusAndGmtModified.get(0);
if (StringUtils.isEmpty(previousStatus)) {
jedis.unwatch();
throw new StoreException("Global transaction is not exist, update global transaction failed.");
}
if (previousStatus.equals(String.valueOf(status))) {
jedis.unwatch();
return true;
}
GlobalStatus before = GlobalStatus.get(Integer.parseInt(previousStatus));
GlobalStatus after = GlobalStatus.get(status);
if (!SessionStatusValidator.validateUpdateStatus(before, after)) {
throw new StoreException("Illegal changing of global status, update global transaction failed."
+ " beforeStatus[" + before.name() + "] cannot be changed to afterStatus[" + after.name() + "]");
}
String previousGmtModified = statusAndGmtModified.get(1);
Transaction multi = jedis.multi();
Map<String,String> map = new HashMap<>(2);
map.put(REDIS_KEY_GLOBAL_STATUS,String.valueOf(globalTransactionDO.getStatus()));
map.put(REDIS_KEY_GLOBAL_GMT_MODIFIED,String.valueOf((new Date()).getTime()));
multi.hmset(globalKey, map);
multi.lrem(buildGlobalStatus(Integer.valueOf(previousStatus)), 0, xid);
multi.rpush(buildGlobalStatus(globalTransactionDO.getStatus()), xid);
multi.zrem(REDIS_SEATA_BEGIN_TRANSACTIONS_KEY, globalKey);
List<Object> exec = multi.exec();
if (CollectionUtils.isEmpty(exec)) {
//The data has changed by another tc, so we still think the modification is successful.
LOGGER.warn("The global transaction xid = {}, maybe changed by another TC. It does not affect the results", xid);
return true;
}
String hmset = exec.get(0).toString();
long lrem = (long) exec.get(1);
long rpush = (long) exec.get(2);
if (OK.equalsIgnoreCase(hmset) && lrem > 0 && rpush > 0) {
return true;
} else {
// pipeline mode
if (OK.equalsIgnoreCase(hmset)) {
// Defensive watch to prevent other TC server operating concurrently,give up this operate
jedis.watch(globalKey);
String xid2 = jedis.hget(globalKey, REDIS_KEY_GLOBAL_XID);
if (StringUtils.isNotEmpty(xid2)) {
Map<String, String> mapPrevious = new HashMap<>(2, 1);
mapPrevious.put(REDIS_KEY_GLOBAL_STATUS, previousStatus);
mapPrevious.put(REDIS_KEY_GLOBAL_GMT_MODIFIED, previousGmtModified);
Transaction multi2 = jedis.multi();
multi2.hmset(globalKey, mapPrevious);
multi2.exec();
}
}
if (lrem > 0) {
jedis.rpush(buildGlobalStatus(Integer.valueOf(previousStatus)), xid);
}
if (rpush > 0) {
jedis.lrem(buildGlobalStatus(status), 0, xid);
}
return false;
}
} catch (Exception ex) {
throw new RedisException(ex);
}
}