protected boolean updateGlobalTransactionDO()

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);
        }
    }