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