Search in sources :

Example 1 with TransactionalOperation

use of org.redisson.transaction.operation.TransactionalOperation in project redisson by redisson.

the class RedissonTransaction method rollback.

public void rollback(List<TransactionalOperation> operations) {
    checkState();
    CommandBatchService executorService = new CommandBatchService(commandExecutor);
    for (TransactionalOperation transactionalOperation : operations) {
        transactionalOperation.rollback(executorService);
    }
    try {
        executorService.execute();
    } catch (Exception e) {
        throw new TransactionException("Unable to rollback transaction", e);
    }
    operations.clear();
    executed.set(true);
}
Also used : TransactionalOperation(org.redisson.transaction.operation.TransactionalOperation) CommandBatchService(org.redisson.command.CommandBatchService)

Example 2 with TransactionalOperation

use of org.redisson.transaction.operation.TransactionalOperation in project redisson by redisson.

the class RedissonTransaction method disableLocalCacheAsync.

private CompletableFuture<Map<HashKey, HashValue>> disableLocalCacheAsync(String requestId, Set<String> localCaches, List<TransactionalOperation> operations) {
    if (localCaches.isEmpty()) {
        return CompletableFuture.completedFuture(Collections.emptyMap());
    }
    CompletableFuture<Map<HashKey, HashValue>> result = new CompletableFuture<>();
    Map<HashKey, HashValue> hashes = new HashMap<>(localCaches.size());
    RedissonBatch batch = createBatch();
    for (TransactionalOperation transactionalOperation : operations) {
        if (localCaches.contains(transactionalOperation.getName())) {
            MapOperation mapOperation = (MapOperation) transactionalOperation;
            RedissonLocalCachedMap<?, ?> map = (RedissonLocalCachedMap<?, ?>) mapOperation.getMap();
            HashKey hashKey = new HashKey(transactionalOperation.getName(), transactionalOperation.getCodec());
            byte[] key = map.getLocalCacheView().toCacheKey(mapOperation.getKey()).getKeyHash();
            HashValue value = hashes.get(hashKey);
            if (value == null) {
                value = new HashValue();
                hashes.put(hashKey, value);
            }
            value.getKeyIds().add(key);
            String disabledKeysName = RedissonObject.suffixName(transactionalOperation.getName(), RedissonLocalCachedMap.DISABLED_KEYS_SUFFIX);
            RMultimapCacheAsync<LocalCachedMapDisabledKey, String> multimap = batch.getListMultimapCache(disabledKeysName, transactionalOperation.getCodec());
            LocalCachedMapDisabledKey localCacheKey = new LocalCachedMapDisabledKey(requestId, options.getResponseTimeout());
            multimap.putAsync(localCacheKey, ByteBufUtil.hexDump(key));
            multimap.expireKeyAsync(localCacheKey, options.getResponseTimeout(), TimeUnit.MILLISECONDS);
        }
    }
    RFuture<BatchResult<?>> batchListener = batch.executeAsync();
    batchListener.onComplete((res, e) -> {
        if (e != null) {
            result.completeExceptionally(e);
            return;
        }
        AsyncCountDownLatch latch = new AsyncCountDownLatch();
        latch.latch(() -> {
            result.complete(hashes);
        }, hashes.size());
        List<CompletableFuture<?>> subscriptionFutures = new ArrayList<>();
        List<RTopic> topics = new ArrayList<>();
        for (Entry<HashKey, HashValue> entry : hashes.entrySet()) {
            String disabledAckName = RedissonObject.suffixName(entry.getKey().getName(), requestId + RedissonLocalCachedMap.DISABLED_ACK_SUFFIX);
            RTopic topic = RedissonTopic.createRaw(LocalCachedMessageCodec.INSTANCE, commandExecutor, disabledAckName);
            topics.add(topic);
            RFuture<Integer> topicFuture = topic.addListenerAsync(Object.class, (channel, msg) -> {
                AtomicInteger counter = entry.getValue().getCounter();
                if (counter.decrementAndGet() == 0) {
                    latch.countDown();
                }
            });
            subscriptionFutures.add(topicFuture.toCompletableFuture());
        }
        CompletableFuture<Void> subscriptionFuture = CompletableFuture.allOf(subscriptionFutures.toArray(new CompletableFuture[0]));
        subscriptionFuture.whenComplete((r, ex) -> {
            RedissonBatch publishBatch = createBatch();
            for (Entry<HashKey, HashValue> entry : hashes.entrySet()) {
                String disabledKeysName = RedissonObject.suffixName(entry.getKey().getName(), RedissonLocalCachedMap.DISABLED_KEYS_SUFFIX);
                RMultimapCacheAsync<LocalCachedMapDisabledKey, String> multimap = publishBatch.getListMultimapCache(disabledKeysName, entry.getKey().getCodec());
                LocalCachedMapDisabledKey localCacheKey = new LocalCachedMapDisabledKey(requestId, options.getResponseTimeout());
                multimap.removeAllAsync(localCacheKey);
                RTopicAsync topic = publishBatch.getTopic(RedissonObject.suffixName(entry.getKey().getName(), RedissonLocalCachedMap.TOPIC_SUFFIX), LocalCachedMessageCodec.INSTANCE);
                RFuture<Long> publishFuture = topic.publishAsync(new LocalCachedMapDisable(requestId, entry.getValue().getKeyIds().toArray(new byte[entry.getValue().getKeyIds().size()][]), options.getResponseTimeout()));
                publishFuture.onComplete((receivers, exc) -> {
                    if (ex != null) {
                        return;
                    }
                    AtomicInteger counter = entry.getValue().getCounter();
                    if (counter.addAndGet(receivers.intValue()) == 0) {
                        latch.countDown();
                    }
                });
            }
            RFuture<BatchResult<?>> publishFuture = publishBatch.executeAsync();
            publishFuture.onComplete((res2, ex2) -> {
                result.whenComplete((res3, ex3) -> {
                    for (RTopic topic : topics) {
                        topic.removeAllListeners();
                    }
                });
                if (ex2 != null) {
                    result.completeExceptionally(ex2);
                    return;
                }
                commandExecutor.getConnectionManager().newTimeout(new TimerTask() {

                    @Override
                    public void run(Timeout timeout) throws Exception {
                        result.completeExceptionally(new TransactionTimeoutException("Unable to execute transaction within " + options.getResponseTimeout() + "ms"));
                    }
                }, options.getResponseTimeout(), TimeUnit.MILLISECONDS);
            });
        });
    });
    return result;
}
Also used : MapOperation(org.redisson.transaction.operation.map.MapOperation) TimerTask(io.netty.util.TimerTask) LocalCachedMapDisabledKey(org.redisson.cache.LocalCachedMapDisabledKey) LocalCachedMapDisable(org.redisson.cache.LocalCachedMapDisable) RedissonBatch(org.redisson.RedissonBatch) Timeout(io.netty.util.Timeout) TransactionalOperation(org.redisson.transaction.operation.TransactionalOperation) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AsyncCountDownLatch(org.redisson.misc.AsyncCountDownLatch) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RedissonLocalCachedMap(org.redisson.RedissonLocalCachedMap) RedissonLocalCachedMap(org.redisson.RedissonLocalCachedMap)

Example 3 with TransactionalOperation

use of org.redisson.transaction.operation.TransactionalOperation in project redisson by redisson.

the class RedissonTransaction method commit.

public void commit(Set<String> localCaches, List<TransactionalOperation> operations) {
    checkState();
    checkTimeout();
    BatchOptions batchOptions = createOptions();
    CommandBatchService transactionExecutor = new CommandBatchService(commandExecutor, batchOptions);
    for (TransactionalOperation transactionalOperation : operations) {
        transactionalOperation.commit(transactionExecutor);
    }
    String id = generateId();
    Map<HashKey, HashValue> hashes = disableLocalCache(id, localCaches, operations);
    try {
        checkTimeout();
    } catch (TransactionTimeoutException e) {
        enableLocalCache(id, hashes);
        throw e;
    }
    try {
        transactionExecutor.execute();
    } catch (Exception e) {
        throw new TransactionException("Unable to execute transaction", e);
    }
    enableLocalCache(id, hashes);
    executed.set(true);
}
Also used : TransactionalOperation(org.redisson.transaction.operation.TransactionalOperation) CommandBatchService(org.redisson.command.CommandBatchService)

Example 4 with TransactionalOperation

use of org.redisson.transaction.operation.TransactionalOperation in project redisson by redisson.

the class RedissonTransaction method disableLocalCache.

private Map<HashKey, HashValue> disableLocalCache(String requestId, Set<String> localCaches, List<TransactionalOperation> operations) {
    if (localCaches.isEmpty()) {
        return Collections.emptyMap();
    }
    Map<HashKey, HashValue> hashes = new HashMap<>(localCaches.size());
    RedissonBatch batch = createBatch();
    for (TransactionalOperation transactionalOperation : operations) {
        if (localCaches.contains(transactionalOperation.getName())) {
            MapOperation mapOperation = (MapOperation) transactionalOperation;
            RedissonLocalCachedMap<?, ?> map = (RedissonLocalCachedMap<?, ?>) mapOperation.getMap();
            HashKey hashKey = new HashKey(transactionalOperation.getName(), transactionalOperation.getCodec());
            byte[] key = map.getLocalCacheView().toCacheKey(mapOperation.getKey()).getKeyHash();
            HashValue value = hashes.get(hashKey);
            if (value == null) {
                value = new HashValue();
                hashes.put(hashKey, value);
            }
            value.getKeyIds().add(key);
            String disabledKeysName = RedissonObject.suffixName(transactionalOperation.getName(), RedissonLocalCachedMap.DISABLED_KEYS_SUFFIX);
            RMultimapCacheAsync<LocalCachedMapDisabledKey, String> multimap = batch.getListMultimapCache(disabledKeysName, transactionalOperation.getCodec());
            LocalCachedMapDisabledKey localCacheKey = new LocalCachedMapDisabledKey(requestId, options.getResponseTimeout());
            multimap.putAsync(localCacheKey, ByteBufUtil.hexDump(key));
            multimap.expireKeyAsync(localCacheKey, options.getResponseTimeout(), TimeUnit.MILLISECONDS);
        }
    }
    try {
        batch.execute();
    } catch (Exception e) {
        throw new TransactionException("Unable to execute transaction over local cached map objects: " + localCaches, e);
    }
    CountDownLatch latch = new CountDownLatch(hashes.size());
    List<RTopic> topics = new ArrayList<>();
    for (Entry<HashKey, HashValue> entry : hashes.entrySet()) {
        RTopic topic = RedissonTopic.createRaw(LocalCachedMessageCodec.INSTANCE, commandExecutor, RedissonObject.suffixName(entry.getKey().getName(), requestId + RedissonLocalCachedMap.DISABLED_ACK_SUFFIX));
        topics.add(topic);
        topic.addListener(Object.class, new MessageListener<Object>() {

            @Override
            public void onMessage(CharSequence channel, Object msg) {
                AtomicInteger counter = entry.getValue().getCounter();
                if (counter.decrementAndGet() == 0) {
                    latch.countDown();
                }
            }
        });
    }
    RedissonBatch publishBatch = createBatch();
    for (Entry<HashKey, HashValue> entry : hashes.entrySet()) {
        String disabledKeysName = RedissonObject.suffixName(entry.getKey().getName(), RedissonLocalCachedMap.DISABLED_KEYS_SUFFIX);
        RMultimapCacheAsync<LocalCachedMapDisabledKey, String> multimap = publishBatch.getListMultimapCache(disabledKeysName, entry.getKey().getCodec());
        LocalCachedMapDisabledKey localCacheKey = new LocalCachedMapDisabledKey(requestId, options.getResponseTimeout());
        multimap.removeAllAsync(localCacheKey);
        RTopicAsync topic = publishBatch.getTopic(RedissonObject.suffixName(entry.getKey().getName(), RedissonLocalCachedMap.TOPIC_SUFFIX), LocalCachedMessageCodec.INSTANCE);
        RFuture<Long> future = topic.publishAsync(new LocalCachedMapDisable(requestId, entry.getValue().getKeyIds().toArray(new byte[entry.getValue().getKeyIds().size()][]), options.getResponseTimeout()));
        future.onComplete((res, e) -> {
            if (e != null) {
                return;
            }
            int receivers = res.intValue();
            AtomicInteger counter = entry.getValue().getCounter();
            if (counter.addAndGet(receivers) == 0) {
                latch.countDown();
            }
        });
    }
    try {
        publishBatch.execute();
    } catch (Exception e) {
        throw new TransactionException("Unable to execute transaction over local cached map objects: " + localCaches, e);
    }
    for (RTopic topic : topics) {
        topic.removeAllListeners();
    }
    try {
        latch.await(options.getResponseTimeout(), TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    return hashes;
}
Also used : MapOperation(org.redisson.transaction.operation.map.MapOperation) LocalCachedMapDisabledKey(org.redisson.cache.LocalCachedMapDisabledKey) LocalCachedMapDisable(org.redisson.cache.LocalCachedMapDisable) RedissonBatch(org.redisson.RedissonBatch) AsyncCountDownLatch(org.redisson.misc.AsyncCountDownLatch) TransactionalOperation(org.redisson.transaction.operation.TransactionalOperation) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RedissonLocalCachedMap(org.redisson.RedissonLocalCachedMap) RedissonObject(org.redisson.RedissonObject)

Example 5 with TransactionalOperation

use of org.redisson.transaction.operation.TransactionalOperation in project redisson by redisson.

the class RedissonTransaction method commitAsync.

@Override
public RFuture<Void> commitAsync() {
    checkState();
    checkTimeout();
    BatchOptions batchOptions = createOptions();
    CommandBatchService transactionExecutor = new CommandBatchService(commandExecutor, batchOptions);
    for (TransactionalOperation transactionalOperation : operations) {
        transactionalOperation.commit(transactionExecutor);
    }
    String id = generateId();
    RPromise<Void> result = new RedissonPromise<>();
    CompletableFuture<Map<HashKey, HashValue>> future = disableLocalCacheAsync(id, localCaches, operations);
    future.whenComplete((hashes, ex) -> {
        if (ex != null) {
            result.tryFailure(new TransactionException("Unable to execute transaction", ex));
            return;
        }
        try {
            checkTimeout();
        } catch (TransactionTimeoutException e) {
            enableLocalCacheAsync(id, hashes);
            result.tryFailure(e);
            return;
        }
        RFuture<BatchResult<?>> transactionFuture = transactionExecutor.executeAsync();
        transactionFuture.onComplete((r, exc) -> {
            if (exc != null) {
                result.tryFailure(new TransactionException("Unable to execute transaction", exc));
                return;
            }
            enableLocalCacheAsync(id, hashes);
            executed.set(true);
            result.trySuccess(null);
        });
    });
    return result;
}
Also used : RedissonPromise(org.redisson.misc.RedissonPromise) CommandBatchService(org.redisson.command.CommandBatchService) TransactionalOperation(org.redisson.transaction.operation.TransactionalOperation) RedissonLocalCachedMap(org.redisson.RedissonLocalCachedMap)

Aggregations

TransactionalOperation (org.redisson.transaction.operation.TransactionalOperation)7 CommandBatchService (org.redisson.command.CommandBatchService)4 RedissonLocalCachedMap (org.redisson.RedissonLocalCachedMap)3 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 RedissonBatch (org.redisson.RedissonBatch)2 LocalCachedMapDisable (org.redisson.cache.LocalCachedMapDisable)2 LocalCachedMapDisabledKey (org.redisson.cache.LocalCachedMapDisabledKey)2 AsyncCountDownLatch (org.redisson.misc.AsyncCountDownLatch)2 RedissonPromise (org.redisson.misc.RedissonPromise)2 MapOperation (org.redisson.transaction.operation.map.MapOperation)2 Timeout (io.netty.util.Timeout)1 TimerTask (io.netty.util.TimerTask)1 RedissonObject (org.redisson.RedissonObject)1