Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.redisson.transaction.BaseTransactionalMap Maven / Gradle / Ivy
Go to download
Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC
/**
* Copyright (c) 2013-2024 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.transaction;
import io.netty.buffer.ByteBuf;
import org.redisson.RedissonMap;
import org.redisson.RedissonObject;
import org.redisson.ScanResult;
import org.redisson.api.RFuture;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.client.RedisClient;
import org.redisson.client.protocol.convertor.NumberConvertor;
import org.redisson.client.protocol.decoder.MapScanResult;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.CompletableFutureWrapper;
import org.redisson.misc.Hash;
import org.redisson.misc.HashValue;
import org.redisson.transaction.operation.*;
import org.redisson.transaction.operation.map.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
*
* @author Nikita Koksharov
*
* @param key type
* @param value type
*/
public class BaseTransactionalMap extends BaseTransactionalObject {
public static class MapEntry {
public static final MapEntry NULL = new MapEntry(null, null);
private final Object key;
private final Object value;
public MapEntry(Object key, Object value) {
super();
this.key = key;
this.value = value;
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
}
private final long timeout;
final List operations;
final Map state = new HashMap<>();
final RMap map;
Boolean deleted;
boolean hasExpiration;
public BaseTransactionalMap(CommandAsyncExecutor commandExecutor, long timeout, List operations, RMap map, String transactionId) {
super(transactionId, getLockName(map.getName()), commandExecutor);
this.timeout = timeout;
this.operations = operations;
this.map = map;
}
HashValue toKeyHash(Object key) {
ByteBuf keyState = ((RedissonObject) map).encodeMapKey(key);
try {
return new HashValue(Hash.hash128(keyState));
} finally {
keyState.release();
}
}
public RFuture isExistsAsync() {
if (deleted != null) {
return new CompletableFutureWrapper<>(!deleted);
}
return map.isExistsAsync();
}
public RFuture unlinkAsync(CommandAsyncExecutor commandExecutor) {
return deleteAsync(commandExecutor, new UnlinkOperation(map.getName()));
}
public RFuture touchAsync(CommandAsyncExecutor commandExecutor) {
if (deleted != null && deleted) {
operations.add(new TouchOperation(map.getName()));
return new CompletableFutureWrapper<>(false);
}
CompletionStage f = map.isExistsAsync().thenApply(exists -> {
operations.add(new TouchOperation(map.getName()));
if (!exists) {
return isExists();
}
return true;
});
return new CompletableFutureWrapper<>(f);
}
public RFuture deleteAsync(CommandAsyncExecutor commandExecutor) {
return deleteAsync(commandExecutor, new DeleteOperation(map.getName()));
}
protected RFuture deleteAsync(CommandAsyncExecutor commandExecutor, TransactionalOperation operation) {
if (deleted != null) {
operations.add(operation);
CompletableFuture result = new CompletableFuture<>();
result.complete(!deleted);
deleted = true;
return new CompletableFutureWrapper<>(result);
}
CompletionStage f = map.isExistsAsync().thenApply(res -> {
operations.add(operation);
state.replaceAll((k, v) -> MapEntry.NULL);
deleted = true;
return res;
});
return new CompletableFutureWrapper<>(f);
}
protected ScanResult> scanIterator(String name, RedisClient client,
String startPos, String pattern, int count) {
ScanResult> res = ((RedissonMap, ?>) map).scanIterator(name, client, startPos, pattern, count);
Map newstate = new HashMap<>(state);
Map newres = null;
for (Iterator> iterator = res.getValues().iterator(); iterator.hasNext();) {
Map.Entry entry = iterator.next();
MapEntry mapEntry = newstate.remove(toKeyHash(entry.getKey()));
if (mapEntry != null) {
if (mapEntry == MapEntry.NULL) {
iterator.remove();
continue;
}
if (newres == null) {
newres = new HashMap<>();
for (Entry e : res.getValues()) {
newres.put(e.getKey(), e.getValue());
}
}
newres.put(entry.getKey(), mapEntry.getValue());
}
}
if ("0".equals(startPos)) {
for (Entry entry : newstate.entrySet()) {
if (entry.getValue() == MapEntry.NULL) {
continue;
}
if (newres == null) {
newres = new HashMap<>();
for (Entry e : res.getValues()) {
newres.put(e.getKey(), e.getValue());
}
}
newres.put(entry.getValue().getKey(), entry.getValue().getValue());
}
}
if (newres != null) {
return new MapScanResult<>(res.getPos(), newres);
}
return res;
}
public RFuture containsKeyAsync(Object key) {
HashValue keyHash = toKeyHash(key);
MapEntry currentValue = state.get(keyHash);
if (currentValue != null) {
if (currentValue == MapEntry.NULL) {
return new CompletableFutureWrapper<>(false);
} else {
return new CompletableFutureWrapper<>(true);
}
}
return map.containsKeyAsync(key);
}
public RFuture containsValueAsync(Object value) {
for (MapEntry entry : state.values()) {
if (entry != MapEntry.NULL && isEqual(entry.getValue(), value)) {
return new CompletableFutureWrapper<>(true);
}
}
return map.containsValueAsync(value);
}
protected RFuture addAndGetOperationAsync(K key, Number value) {
long threadId = Thread.currentThread().getId();
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
BigDecimal currentValue = BigDecimal.ZERO;
if (entry != MapEntry.NULL) {
currentValue = (BigDecimal) entry.getValue();
}
BigDecimal res = currentValue.add(new BigDecimal(value.toString()));
operations.add(new MapAddAndGetOperation(map, key, value, transactionId, threadId));
state.put(keyHash, new MapEntry(key, res));
if (deleted != null) {
deleted = false;
}
NumberConvertor convertor = new NumberConvertor(value.getClass());
return CompletableFuture.completedFuture((V) convertor.convert(res.toPlainString()));
}
return map.getAsync(key).thenApply(r -> {
BigDecimal currentValue = new BigDecimal(r.toString());
BigDecimal res = currentValue.add(new BigDecimal(value.toString()));
operations.add(new MapAddAndGetOperation(map, key, value, transactionId, threadId));
state.put(keyHash, new MapEntry(key, res));
if (deleted != null) {
deleted = false;
}
NumberConvertor convertor = new NumberConvertor(value.getClass());
return (V) convertor.convert(res.toPlainString());
});
});
}
protected RFuture putIfExistsOperationAsync(K key, V value) {
long threadId = Thread.currentThread().getId();
return putIfExistsOperationAsync(key, value, new MapPutIfExistsOperation(map, key, value, transactionId, threadId));
}
protected RFuture putIfExistsOperationAsync(K key, V value, MapOperation mapOperation) {
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
operations.add(mapOperation);
if (entry != MapEntry.NULL) {
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
return CompletableFuture.completedFuture((V) entry.getValue());
}
return CompletableFuture.completedFuture(null);
}
return map.getAsync(key).thenApply(res -> {
operations.add(mapOperation);
if (res != null) {
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
}
return res;
});
});
}
protected RFuture putIfAbsentOperationAsync(K key, V value) {
long threadId = Thread.currentThread().getId();
return putIfAbsentOperationAsync(key, value, new MapPutIfAbsentOperation(map, key, value, transactionId, threadId));
}
protected RFuture putIfAbsentOperationAsync(K key, V value, MapOperation mapOperation) {
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
operations.add(mapOperation);
if (entry == MapEntry.NULL) {
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
return CompletableFuture.completedFuture(null);
}
return CompletableFuture.completedFuture((V) entry.getValue());
}
return map.getAsync(key).thenApply(res -> {
operations.add(mapOperation);
if (res == null) {
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
}
return res;
});
});
}
protected final RFuture putOperationAsync(K key, V value) {
long threadId = Thread.currentThread().getId();
return putOperationAsync(key, value, new MapPutOperation(map, key, value, transactionId, threadId));
}
protected RFuture putOperationAsync(K key, V value, MapOperation operation) {
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
operations.add(operation);
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
if (entry == MapEntry.NULL) {
return CompletableFuture.completedFuture(null);
}
return CompletableFuture.completedFuture((V) entry.getValue());
}
return map.getAsync(key).thenApply(res -> {
operations.add(operation);
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
return res;
});
});
}
protected RFuture fastPutIfExistsOperationAsync(K key, V value) {
long threadId = Thread.currentThread().getId();
return fastPutIfExistsOperationAsync(key, value, new MapFastPutIfExistsOperation(map, key, value, transactionId, threadId));
}
protected RFuture fastPutIfExistsOperationAsync(K key, V value, MapOperation mapOperation) {
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
operations.add(mapOperation);
if (entry != MapEntry.NULL) {
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
return CompletableFuture.completedFuture(true);
}
return CompletableFuture.completedFuture(false);
}
return map.getAsync(key).thenApply(res -> {
operations.add(mapOperation);
if (res != null) {
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
}
return true;
});
});
}
protected RFuture fastPutIfAbsentOperationAsync(K key, V value) {
long threadId = Thread.currentThread().getId();
return fastPutIfAbsentOperationAsync(key, value, new MapFastPutIfAbsentOperation(map, key, value, transactionId, threadId));
}
protected RFuture fastPutIfAbsentOperationAsync(K key, V value, MapOperation mapOperation) {
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
operations.add(mapOperation);
if (entry == MapEntry.NULL) {
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
return CompletableFuture.completedFuture(true);
}
return CompletableFuture.completedFuture(false);
}
return map.getAsync(key).thenApply(res -> {
operations.add(mapOperation);
boolean isUpdated = res == null;
if (isUpdated) {
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
}
return isUpdated;
});
});
}
protected RFuture fastPutOperationAsync(K key, V value) {
long threadId = Thread.currentThread().getId();
return fastPutOperationAsync(key, value, new MapFastPutOperation(map, key, value, transactionId, threadId));
}
protected RFuture fastPutOperationAsync(K key, V value, MapOperation operation) {
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
operations.add(operation);
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
return CompletableFuture.completedFuture(entry == MapEntry.NULL);
}
return map.getAsync(key).thenApply(res -> {
operations.add(operation);
state.put(keyHash, new MapEntry(key, value));
if (deleted != null) {
deleted = false;
}
boolean isNew = res == null;
return isNew;
});
});
}
@SuppressWarnings("unchecked")
protected RFuture fastRemoveOperationAsync(K... keys) {
long threadId = Thread.currentThread().getId();
List locks = Arrays.stream(keys).map(k -> getLock(k)).collect(Collectors.toList());
return executeLocked(timeout, () -> {
AtomicLong counter = new AtomicLong();
List keyList = new ArrayList<>(Arrays.asList(keys));
for (Iterator iterator = keyList.iterator(); iterator.hasNext();) {
K key = iterator.next();
HashValue keyHash = toKeyHash(key);
MapEntry currentValue = state.get(keyHash);
if (currentValue != null && currentValue != MapEntry.NULL) {
operations.add(new MapFastRemoveOperation(map, key, transactionId, threadId));
state.put(keyHash, MapEntry.NULL);
counter.incrementAndGet();
iterator.remove();
}
}
// TODO optimize
return map.getAllAsync(new HashSet<>(keyList)).thenApply(res -> {
for (K key : res.keySet()) {
HashValue keyHash = toKeyHash(key);
operations.add(new MapFastRemoveOperation(map, key, transactionId, threadId));
counter.incrementAndGet();
state.put(keyHash, MapEntry.NULL);
}
return counter.get();
});
}, locks);
}
public RFuture valueSizeAsync(K key) {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
if (entry == MapEntry.NULL) {
return new CompletableFutureWrapper<>((Integer) null);
} else {
ByteBuf valueState = ((RedissonObject) map).encodeMapValue(entry.getValue());
try {
return new CompletableFutureWrapper<>(valueState.readableBytes());
} finally {
valueState.release();
}
}
}
return map.valueSizeAsync(key);
}
protected RFuture getOperationAsync(K key) {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
if (entry == MapEntry.NULL) {
return new CompletableFutureWrapper<>((V) null);
} else {
return new CompletableFutureWrapper<>((V) entry.getValue());
}
}
return ((RedissonMap) map).getOperationAsync(key);
}
public RFuture> readAllKeySetAsync() {
RFuture> future = map.readAllKeySetAsync();
CompletionStage> f = future.thenApply(res -> {
Map newstate = new HashMap<>(state);
for (Iterator iterator = res.iterator(); iterator.hasNext();) {
K key = iterator.next();
MapEntry value = newstate.remove(toKeyHash(key));
if (value == MapEntry.NULL) {
iterator.remove();
}
}
for (MapEntry entry : newstate.values()) {
if (entry == MapEntry.NULL) {
continue;
}
res.add((K) entry.getKey());
}
return res;
});
return new CompletableFutureWrapper<>(f);
}
public RFuture>> readAllEntrySetAsync() {
RFuture> future = readAllMapAsync();
CompletionStage>> f = future.thenApply(res -> res.entrySet());
return new CompletableFutureWrapper<>(f);
}
public RFuture> readAllValuesAsync() {
RFuture> future = readAllMapAsync();
CompletionStage> f = future.thenApply(res -> res.values());
return new CompletableFutureWrapper<>(f);
}
public RFuture> readAllMapAsync() {
RFuture> future = map.readAllMapAsync();
CompletionStage> f = future.thenApply(map -> {
Map newstate = new HashMap<>(state);
for (Iterator iterator = map.keySet().iterator(); iterator.hasNext();) {
K key = iterator.next();
MapEntry entry = newstate.remove(toKeyHash(key));
if (entry == MapEntry.NULL) {
iterator.remove();
} else if (entry != null) {
map.put(key, (V) entry.getValue());
}
}
for (MapEntry entry : newstate.values()) {
if (entry == MapEntry.NULL) {
continue;
}
map.put((K) entry.getKey(), (V) entry.getValue());
}
return map;
});
return new CompletableFutureWrapper<>(f);
}
protected RFuture> getAllOperationAsync(Set keys) {
Set keysToLoad = new HashSet<>();
Map map = new HashMap<>();
for (K key : keys) {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
if (entry != MapEntry.NULL) {
map.put(key, (V) entry.getValue());
}
} else {
keysToLoad.add(key);
}
}
if (keysToLoad.isEmpty()) {
return new CompletableFutureWrapper<>(map);
}
RFuture> future = ((RedissonMap) this.map).getAllOperationAsync(keysToLoad);
CompletionStage> f = future.thenApply(res -> {
map.putAll(res);
return map;
});
return new CompletableFutureWrapper<>(f);
}
protected Set keySet(String pattern, int count) {
Set keys = map.keySet(pattern, count);
return keys.stream()
.filter(k -> {
HashValue hash = toKeyHash(k);
if (state.get(hash) == null
|| state.get(hash) != BaseTransactionalMap.MapEntry.NULL) {
return true;
}
return false;
})
.collect(Collectors.toSet());
}
protected RFuture removeOperationAsync(K key) {
long threadId = Thread.currentThread().getId();
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
operations.add(new MapRemoveOperation(map, key, transactionId, threadId));
if (entry == MapEntry.NULL) {
return CompletableFuture.completedFuture(null);
}
state.put(keyHash, MapEntry.NULL);
return CompletableFuture.completedFuture((V) entry.getValue());
}
return map.getAsync(key).thenApply(res -> {
operations.add(new MapRemoveOperation(map, key, transactionId, threadId));
if (res != null) {
state.put(keyHash, MapEntry.NULL);
}
return res;
});
});
}
protected RFuture removeOperationAsync(Object key, Object value) {
long threadId = Thread.currentThread().getId();
return executeLocked((K) key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
if (entry == MapEntry.NULL) {
return CompletableFuture.completedFuture(false);
}
operations.add(new MapRemoveOperation(map, key, value, transactionId, threadId));
if (isEqual(entry.getValue(), value)) {
state.put(keyHash, MapEntry.NULL);
return CompletableFuture.completedFuture(true);
}
return CompletableFuture.completedFuture(false);
}
return map.getAsync((K) key).thenApply(r -> {
operations.add(new MapRemoveOperation(map, key, value, transactionId, threadId));
boolean res = isEqual(r, value);
if (res) {
state.put(keyHash, MapEntry.NULL);
}
return res;
});
});
}
private boolean isEqual(Object value, Object oldValue) {
ByteBuf valueBuf = ((RedissonObject) map).encodeMapValue(value);
ByteBuf oldValueBuf = ((RedissonObject) map).encodeMapValue(oldValue);
try {
return valueBuf.equals(oldValueBuf);
} finally {
valueBuf.readableBytes();
oldValueBuf.readableBytes();
}
}
protected RFuture putAllOperationAsync(Map extends K, ? extends V> entries) {
long threadId = Thread.currentThread().getId();
List list = entries.keySet().stream().map(k -> getLock(k)).collect(Collectors.toList());
return executeLocked(timeout, () -> {
for (Entry extends K, ? extends V> entry : entries.entrySet()) {
operations.add(new MapPutOperation(map, entry.getKey(), entry.getValue(), transactionId, threadId));
HashValue keyHash = toKeyHash(entry.getKey());
state.put(keyHash, new MapEntry(entry.getKey(), entry.getValue()));
}
if (deleted != null) {
deleted = false;
}
return CompletableFuture.completedFuture(null);
}, list);
}
protected RFuture replaceOperationAsync(K key, V oldValue, V newValue) {
long threadId = Thread.currentThread().getId();
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
if (entry != null) {
if (entry == MapEntry.NULL) {
return CompletableFuture.completedFuture(false);
}
operations.add(new MapReplaceOperation(map, key, newValue, oldValue, transactionId, threadId));
if (isEqual(entry.getValue(), oldValue)) {
state.put(keyHash, new MapEntry(key, newValue));
return CompletableFuture.completedFuture(true);
}
return CompletableFuture.completedFuture(false);
}
return map.getAsync(key).thenApply(r -> {
operations.add(new MapReplaceOperation(map, key, newValue, oldValue, transactionId, threadId));
boolean res = isEqual(r, oldValue);
if (res) {
state.put(keyHash, new MapEntry(key, newValue));
}
return res;
});
});
}
protected RFuture replaceOperationAsync(K key, V value) {
long threadId = Thread.currentThread().getId();
return executeLocked(key, () -> {
HashValue keyHash = toKeyHash(key);
MapEntry entry = state.get(keyHash);
operations.add(new MapReplaceOperation(map, key, value, transactionId, threadId));
if (entry != null) {
if (entry == MapEntry.NULL) {
return CompletableFuture.completedFuture(null);
}
state.put(keyHash, new MapEntry(key, value));
return CompletableFuture.completedFuture((V) entry.getValue());
}
return map.getAsync(key).thenApply(res -> {
operations.add(new MapReplaceOperation(map, key, value, transactionId, threadId));
if (res != null) {
state.put(keyHash, new MapEntry(key, value));
}
return res;
});
});
}
protected RFuture executeLocked(K key, Supplier> runnable) {
RLock lock = getLock(key);
return executeLocked(timeout, runnable, lock);
}
protected RLock getLock(K key) {
String lockName = ((RedissonMap) map).getLockByMapKey(key, "lock");
return new RedissonTransactionalLock(commandExecutor, lockName, transactionId);
}
private boolean isExists() {
boolean notExists = state.values().stream().noneMatch(v -> v != MapEntry.NULL);
return !notExists;
}
public RFuture expireAsync(long timeToLive, TimeUnit timeUnit, String param, String... keys) {
long currentThreadId = Thread.currentThread().getId();
return executeLocked(timeout, () -> {
if (isExists()) {
operations.add(new ExpireOperation(map.getName(), null, lockName, currentThreadId, transactionId, timeToLive, timeUnit, param, keys));
hasExpiration = true;
return CompletableFuture.completedFuture(true);
}
return isExistsAsync().thenApply(res -> {
operations.add(new ExpireOperation(map.getName(), null, lockName, currentThreadId, transactionId, timeToLive, timeUnit, param, keys));
hasExpiration = res;
return res;
});
}, getWriteLock());
}
public RFuture expireAtAsync(long timestamp, String param, String... keys) {
long currentThreadId = Thread.currentThread().getId();
return executeLocked(timeout, () -> {
if (isExists()) {
operations.add(new ExpireAtOperation(map.getName(), null, lockName, currentThreadId, transactionId, timestamp, param, keys));
hasExpiration = true;
return CompletableFuture.completedFuture(true);
}
return isExistsAsync().thenApply(res -> {
operations.add(new ExpireAtOperation(map.getName(), null, lockName, currentThreadId, transactionId, timestamp, param, keys));
hasExpiration = res;
return res;
});
}, getWriteLock());
}
public RFuture clearExpireAsync() {
long currentThreadId = Thread.currentThread().getId();
return executeLocked(timeout, () -> {
if (hasExpiration) {
operations.add(new ClearExpireOperation(map.getName(), null, lockName, currentThreadId, transactionId));
hasExpiration = false;
return CompletableFuture.completedFuture(true);
}
return map.remainTimeToLiveAsync().thenApply(res -> {
operations.add(new ClearExpireOperation(map.getName(), null, lockName, currentThreadId, transactionId));
hasExpiration = false;
return res > 0;
});
}, getWriteLock());
}
}