diff --git a/hazelcast-client/src/test/java/com/hazelcast/client/txn/ClientTxnMapTest.java b/hazelcast-client/src/test/java/com/hazelcast/client/txn/ClientTxnMapTest.java index 3259edbd22c99..b88651c5d1142 100644 --- a/hazelcast-client/src/test/java/com/hazelcast/client/txn/ClientTxnMapTest.java +++ b/hazelcast-client/src/test/java/com/hazelcast/client/txn/ClientTxnMapTest.java @@ -18,6 +18,8 @@ import com.hazelcast.client.config.ClientConfig; import com.hazelcast.client.test.TestHazelcastFactory; +import com.hazelcast.config.Config; +import com.hazelcast.config.NearCacheConfig; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.IMap; import com.hazelcast.core.TransactionalMap; @@ -46,6 +48,7 @@ import static com.hazelcast.test.HazelcastTestSupport.randomString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -74,7 +77,6 @@ public void setup() { client = hazelcastFactory.newHazelcastClient(clientConfig); } - @Test public void testUnlockAfterRollback() { final String mapName = randomString(); @@ -553,4 +555,52 @@ public void testKeyValuesPredicateNull() throws Exception { txMap.values(null); } + @Test + public void txn_map_get_skips_server_side_near_cache() { + String mapName = "test"; + int keyInServerNearCache = 1; + + IMap serverMap = prepareServerAndGetServerMap(mapName, keyInServerNearCache); + TransactionalMap clientTxnMap = getClientTransactionalMap(mapName); + + assertNotNull(clientTxnMap.get(keyInServerNearCache)); + assertEquals(0, serverMap.getLocalMapStats().getNearCacheStats().getHits()); + } + + @Test + public void txn_map_containsKey_skips_server_side_near_cache() { + String mapName = "test"; + int keyInServerNearCache = 1; + + IMap serverMap = prepareServerAndGetServerMap(mapName, keyInServerNearCache); + TransactionalMap clientTxnMap = getClientTransactionalMap(mapName); + + assertTrue(clientTxnMap.containsKey(keyInServerNearCache)); + assertEquals(0, serverMap.getLocalMapStats().getNearCacheStats().getHits()); + } + + private IMap prepareServerAndGetServerMap(String mapName, int keyInServerNearCache) { + NearCacheConfig nearCacheConfig = new NearCacheConfig(); + nearCacheConfig.setCacheLocalEntries(true); + + Config serverConfig = new Config(); + serverConfig.getMapConfig(mapName).setNearCacheConfig(nearCacheConfig); + + HazelcastInstance server = hazelcastFactory.newHazelcastInstance(serverConfig); + + // populate server near cache. + IMap map = server.getMap(mapName); + map.put(keyInServerNearCache, 1); + map.get(keyInServerNearCache); + + return map; + } + + private TransactionalMap getClientTransactionalMap(String mapName) { + HazelcastInstance client = hazelcastFactory.newHazelcastClient(); + + TransactionContext clientTxnContext = client.newTransactionContext(); + clientTxnContext.beginTransaction(); + return clientTxnContext.getMap(mapName); + } } diff --git a/hazelcast/src/main/java/com/hazelcast/client/impl/protocol/task/transactionalmap/TransactionalMapContainsKeyMessageTask.java b/hazelcast/src/main/java/com/hazelcast/client/impl/protocol/task/transactionalmap/TransactionalMapContainsKeyMessageTask.java index 994d12dcc0430..81eb3329c1f80 100644 --- a/hazelcast/src/main/java/com/hazelcast/client/impl/protocol/task/transactionalmap/TransactionalMapContainsKeyMessageTask.java +++ b/hazelcast/src/main/java/com/hazelcast/client/impl/protocol/task/transactionalmap/TransactionalMapContainsKeyMessageTask.java @@ -22,6 +22,7 @@ import com.hazelcast.core.TransactionalMap; import com.hazelcast.instance.Node; import com.hazelcast.map.impl.MapService; +import com.hazelcast.map.impl.tx.TransactionalMapProxy; import com.hazelcast.nio.Connection; import com.hazelcast.security.permission.ActionConstants; import com.hazelcast.security.permission.MapPermission; @@ -40,7 +41,7 @@ public TransactionalMapContainsKeyMessageTask(ClientMessage clientMessage, Node protected Object innerCall() throws Exception { final TransactionContext context = endpoint.getTransactionContext(parameters.txnId); final TransactionalMap map = context.getMap(parameters.name); - return map.containsKey(parameters.key); + return ((TransactionalMapProxy) map).containsKey(parameters.key, true); } @Override diff --git a/hazelcast/src/main/java/com/hazelcast/client/impl/protocol/task/transactionalmap/TransactionalMapGetMessageTask.java b/hazelcast/src/main/java/com/hazelcast/client/impl/protocol/task/transactionalmap/TransactionalMapGetMessageTask.java index 823fb7e0408e8..16c46763ac216 100644 --- a/hazelcast/src/main/java/com/hazelcast/client/impl/protocol/task/transactionalmap/TransactionalMapGetMessageTask.java +++ b/hazelcast/src/main/java/com/hazelcast/client/impl/protocol/task/transactionalmap/TransactionalMapGetMessageTask.java @@ -22,6 +22,7 @@ import com.hazelcast.core.TransactionalMap; import com.hazelcast.instance.Node; import com.hazelcast.map.impl.MapService; +import com.hazelcast.map.impl.tx.TransactionalMapProxy; import com.hazelcast.nio.Connection; import com.hazelcast.security.permission.ActionConstants; import com.hazelcast.security.permission.MapPermission; @@ -40,7 +41,7 @@ public TransactionalMapGetMessageTask(ClientMessage clientMessage, Node node, Co protected Object innerCall() throws Exception { final TransactionContext context = endpoint.getTransactionContext(parameters.txnId); final TransactionalMap map = context.getMap(parameters.name); - Object response = map.get(parameters.key); + Object response = ((TransactionalMapProxy) map).get(parameters.key, true); return serializationService.toData(response); } diff --git a/hazelcast/src/main/java/com/hazelcast/map/impl/tx/TransactionalMapProxy.java b/hazelcast/src/main/java/com/hazelcast/map/impl/tx/TransactionalMapProxy.java index 321d14c39e8ce..71500e43627a9 100644 --- a/hazelcast/src/main/java/com/hazelcast/map/impl/tx/TransactionalMapProxy.java +++ b/hazelcast/src/main/java/com/hazelcast/map/impl/tx/TransactionalMapProxy.java @@ -60,6 +60,10 @@ public TransactionalMapProxy(String name, MapService mapService, NodeEngine node @Override public boolean containsKey(Object key) { + return containsKey(key, false); + } + + public boolean containsKey(Object key, boolean skipNearCacheLookup) { checkTransactionState(); checkNotNull(key, "key can't be null"); @@ -68,7 +72,7 @@ public boolean containsKey(Object key) { if (valueWrapper != null) { return (valueWrapper.type != Type.REMOVED); } - return containsKeyInternal(keyData, key); + return containsKeyInternal(keyData, key, skipNearCacheLookup); } @Override @@ -97,17 +101,20 @@ public boolean isEmpty() { @Override public Object get(Object key) { + return get(key, false); + } + + public Object get(Object key, boolean skipNearCacheLookup) { checkTransactionState(); checkNotNull(key, "key can't be null"); Object nearCacheKey = toNearCacheKeyWithStrategy(key); Data keyData = mapServiceContext.toData(nearCacheKey, partitionStrategy); - TxnValueWrapper currentValue = txMap.get(keyData); if (currentValue != null) { return checkIfRemoved(currentValue); } - return toObjectIfNeeded(getInternal(nearCacheKey, keyData)); + return toObjectIfNeeded(getInternal(nearCacheKey, keyData, skipNearCacheLookup)); } @Override diff --git a/hazelcast/src/main/java/com/hazelcast/map/impl/tx/TransactionalMapProxySupport.java b/hazelcast/src/main/java/com/hazelcast/map/impl/tx/TransactionalMapProxySupport.java index 9ec4d0ae00930..a83276d5676aa 100644 --- a/hazelcast/src/main/java/com/hazelcast/map/impl/tx/TransactionalMapProxySupport.java +++ b/hazelcast/src/main/java/com/hazelcast/map/impl/tx/TransactionalMapProxySupport.java @@ -66,6 +66,7 @@ public abstract class TransactionalMapProxySupport extends TransactionalDistribu private final boolean nearCacheEnabled; private final boolean serializeKeys; + private final boolean nearCacheEnabled; private final RecordComparator recordComparator; TransactionalMapProxySupport(String name, MapService mapService, NodeEngine nodeEngine, Transaction transaction) { @@ -105,8 +106,8 @@ void checkTransactionState() { } } - boolean containsKeyInternal(Data dataKey, Object objectKey) { - if (nearCacheEnabled) { + boolean containsKeyInternal(Data dataKey, Object objectKey, boolean skipNearCacheLookup) { + if (!skipNearCacheLookup && nearCacheEnabled) { Object nearCacheKey = serializeKeys ? dataKey : objectKey; Object cachedValue = getCachedValue(nearCacheKey, false); if (cachedValue != NOT_CACHED) { @@ -125,8 +126,8 @@ boolean containsKeyInternal(Data dataKey, Object objectKey) { } } - Object getInternal(Object nearCacheKey, Data keyData) { - if (nearCacheEnabled) { + Object getInternal(Object nearCacheKey, Data keyData, boolean skipNearCacheLookup) { + if (!skipNearCacheLookup && nearCacheEnabled) { Object value = getCachedValue(nearCacheKey, true); if (value != NOT_CACHED) { return value;