/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.ignite.internal.processors.cache.distributed.near;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.cache.CachePeekMode;
import org.apache.ignite.cache.affinity.Affinity;
import org.apache.ignite.cache.affinity.AffinityKeyMapped;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.util.typedef.F;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
import static org.apache.ignite.cache.CacheMode.REPLICATED;
import static org.apache.ignite.cache.CachePeekMode.BACKUP;
import static org.apache.ignite.cache.CachePeekMode.NEAR;
import static org.apache.ignite.cache.CachePeekMode.PRIMARY;
import static org.apache.ignite.cache.CacheRebalanceMode.SYNC;
/**
* Multi-node tests for partitioned cache.
*/
public class GridCachePartitionedMultiNodeFullApiSelfTest extends GridCachePartitionedFullApiSelfTest {
/** {@inheritDoc} */
@Override protected int gridCount() {
return 4;
}
/** {@inheritDoc} */
@Override protected CacheConfiguration cacheConfiguration(String igniteInstanceName) throws Exception {
CacheConfiguration cc = super.cacheConfiguration(igniteInstanceName);
cc.setRebalanceMode(SYNC);
return cc;
}
/**
* @return Affinity nodes for this cache.
*/
public Collection<ClusterNode> affinityNodes() {
return grid(0).cluster().nodes();
}
/**
* @throws Exception If failed.
*/
public void testPutAllRemoveAll() throws Exception {
for (int i = 0; i < gridCount(); i++)
info(">>>>> Grid" + i + ": " + grid(i).localNode().id());
Map<Integer, Integer> putMap = new LinkedHashMap<>();
int size = 100;
for (int i = 0; i < size; i++)
putMap.put(i, i * i);
IgniteCache<Object, Object> c0 = grid(0).cache(DEFAULT_CACHE_NAME);
IgniteCache<Object, Object> c1 = grid(1).cache(DEFAULT_CACHE_NAME);
c0.putAll(putMap);
c1.removeAll(new HashSet<>(putMap.keySet()));
for (int i = 0; i < size; i++) {
assertNull(c0.get(i));
assertNull(c1.get(i));
}
}
/**
* @throws Exception If failed.
*/
public void testPutAllPutAll() throws Exception {
for (int i = 0; i < gridCount(); i++)
info(">>>>> Grid" + i + ": " + grid(i).localNode().id());
Map<Integer, Integer> putMap = new LinkedHashMap<>();
int size = 100;
for (int i = 0; i < size; i++)
putMap.put(i, i);
IgniteCache<Object, Object> prj0 = grid(0).cache(DEFAULT_CACHE_NAME);
IgniteCache<Object, Object> prj1 = grid(1).cache(DEFAULT_CACHE_NAME);
prj0.putAll(putMap);
for (int i = 0; i < size; i++) {
assertEquals(i, prj0.get(i));
assertEquals(i, prj1.get(i));
}
for (int i = 0; i < size; i++)
putMap.put(i, i * i);
info(">>> Before second put.");
prj1.putAll(putMap);
info(">>> After second put.");
for (int i = 0; i < size; i++) {
assertEquals(i * i, prj0.get(i));
assertEquals(i * i, prj1.get(i));
}
}
/**
* @throws Exception If failed.
*/
public void testPutDebug() throws Exception {
for (int i = 0; i < gridCount(); i++)
info(">>>>> Grid" + i + ": " + grid(i).localNode().id());
final int size = 10;
IgniteCache<Object, Object> cache0 = grid(0).cache(DEFAULT_CACHE_NAME);
for (int i = 0; i < size; i++) {
info("Putting value [i=" + i + ']');
cache0.put(i, i);
info("Finished putting value [i=" + i + ']');
}
for (int i = 0; i < gridCount(); i++)
executeOnLocalOrRemoteJvm(i, new CheckAffinityTask(size));
for (int i = 0; i < size; i++) {
info("Putting value 2 [i=" + i + ']');
assertEquals(i, cache0.getAndPutIfAbsent(i, i * i));
info("Finished putting value 2 [i=" + i + ']');
}
for (int i = 0; i < size; i++)
assertEquals(i, cache0.get(i));
}
/**
* @throws Exception If failed.
*/
public void testPeekPartitionedModes() throws Exception {
jcache().put("key", 1);
for (int i = 0; i < gridCount(); i++) {
IgniteCache<String, Integer> c = jcache(i);
assertEquals((Integer)1, c.get("key"));
boolean nearEnabled = nearEnabled(c);
if (nearEnabled)
executeOnLocalOrRemoteJvm(i, new IsNearTask());
Integer nearPeekVal = nearEnabled ? 1 : null;
Affinity<Object> aff = ignite(i).affinity(DEFAULT_CACHE_NAME);
info("Affinity nodes [nodes=" + F.nodeIds(aff.mapKeyToPrimaryAndBackups("key")) +
", locNode=" + ignite(i).cluster().localNode().id() + ']');
if (aff.isBackup(grid(i).localNode(), "key")) {
assertNull(c.localPeek("key", NEAR));
assertEquals((Integer)1, c.localPeek("key", BACKUP));
}
else if (!aff.isPrimaryOrBackup(grid(i).localNode(), "key")) {
// Initialize near reader.
assertEquals((Integer)1, c.get("key"));
assertEquals("Failed to validate near value for node: " + i, nearPeekVal, c.localPeek("key", NEAR));
assertNull(c.localPeek("key", PRIMARY, BACKUP));
}
}
}
/**
* @throws Exception If failed.
*/
public void testPeekAsyncPartitionedModes() throws Exception {
jcache().put("key", 1);
for (int i = 0; i < gridCount(); i++) {
boolean nearEnabled = nearEnabled(jcache(i));
Integer nearPeekVal = nearEnabled ? 1 : null;
IgniteCache<String, Integer> c = jcache(i);
if (grid(i).affinity(DEFAULT_CACHE_NAME).isBackup(grid(i).localNode(), "key")) {
assert c.localPeek("key", NEAR) == null;
assert c.localPeek("key", PRIMARY, BACKUP) == 1;
}
else if (!grid(i).affinity(DEFAULT_CACHE_NAME).isPrimaryOrBackup(grid(i).localNode(), "key")) {
// Initialize near reader.
assertEquals((Integer)1, jcache(i).get("key"));
assertEquals(nearPeekVal, c.localPeek("key", NEAR));
assert c.localPeek("key", PRIMARY, BACKUP) == null;
}
}
}
/**
* @throws Exception If failed.
*/
@SuppressWarnings("unchecked")
public void testNearDhtKeySize() throws Exception {
List<String> keys = new ArrayList<>(5);
info("Generating keys for test...");
IgniteEx ignite0 = null;
IgniteEx ignite1 = null;
IgniteEx ignite2 = null;
for (int i = 0; i < gridCount(); i++) {
IgniteEx ignite = grid(i);
if (!Boolean.TRUE.equals(ignite.configuration().isClientMode())) {
if (ignite0 == null)
ignite0 = ignite;
else if (ignite1 == null)
ignite1 = ignite;
else {
ignite2 = ignite;
break;
}
}
}
assertNotNull(ignite0);
assertNotNull(ignite1);
assertNotNull(ignite2);
info("Generating keys for test [nodes=" + ignite0.name() + ", " + ignite1.name() + ", " + ignite2.name() + ']');
IgniteCache<String, Integer> cache0 = ignite0.cache(DEFAULT_CACHE_NAME);
int val = 0;
for (int i = 0; i < 10_000 && keys.size() < 5; i++) {
String key = String.valueOf(i);
if (ignite(0).affinity(DEFAULT_CACHE_NAME).isPrimary(ignite0.localNode(), key) &&
ignite(0).affinity(DEFAULT_CACHE_NAME).isBackup(ignite1.localNode(), key)) {
keys.add(key);
cache0.put(key, val++);
}
}
assertEquals(5, keys.size());
info("Finished generating keys for test.");
IgniteCache<String, Integer> cache2 = ignite2.cache(DEFAULT_CACHE_NAME);
assertEquals(Integer.valueOf(0), cache2.get(keys.get(0)));
assertEquals(Integer.valueOf(1), cache2.get(keys.get(1)));
assertEquals(0, cache0.localSize(NEAR));
assertEquals(5, cache0.localSize(CachePeekMode.ALL) - cache0.localSize(NEAR));
IgniteCache<String, Integer> cache1 = ignite1.cache(DEFAULT_CACHE_NAME);
assertEquals(0, cache1.localSize(NEAR));
assertEquals(5, cache1.localSize(CachePeekMode.ALL) - cache1.localSize(NEAR));
boolean nearEnabled = cache2.getConfiguration(CacheConfiguration.class).getNearConfiguration() != null;
assertEquals(nearEnabled ? 2 : 0, cache2.localSize(NEAR));
if (cacheMode() != REPLICATED)
assertEquals(0, cache2.localSize(CachePeekMode.ALL) - cache2.localSize(NEAR));
}
/**
* @throws Exception If failed.
*/
public void testAffinity() throws Exception {
for (int i = 0; i < gridCount(); i++)
info("Grid " + i + ": " + grid(i).localNode().id());
final Object affKey = new Object() {
@Override public boolean equals(Object obj) {
return obj == this;
}
@Override public int hashCode() {
return 1;
}
};
Object key = new Object() {
/** */
@SuppressWarnings("UnusedDeclaration")
@AffinityKeyMapped
private final Object key0 = affKey;
@Override public boolean equals(Object obj) {
return obj == this;
}
@Override public int hashCode() {
return 2;
}
};
if (!isMultiJvm())
info("All affinity nodes: " + affinityNodes());
IgniteCache<Object, Object> cache = grid(0).cache(DEFAULT_CACHE_NAME);
info("Cache affinity nodes: " + affinity(cache).mapKeyToPrimaryAndBackups(key));
Affinity<Object> aff = affinity(cache);
Collection<ClusterNode> nodes = aff.mapKeyToPrimaryAndBackups(key);
info("Got nodes from affinity: " + nodes);
assertEquals(cacheMode() == PARTITIONED ? 2 : affinityNodes().size(), nodes.size());
ClusterNode primary = F.first(nodes);
ClusterNode backup = F.last(nodes);
assertNotSame(primary, backup);
ClusterNode other = null;
for (int i = 0; i < gridCount(); i++) {
ClusterNode node = grid(i).localNode();
if (!node.equals(primary) && !node.equals(backup)) {
other = node;
break;
}
}
assertNotSame(other, primary);
assertNotSame(other, backup);
assertNotNull(primary);
assertNotNull(backup);
assertNotNull(other);
assertTrue(affinity(cache).isPrimary(primary, key));
assertFalse(affinity(cache).isBackup(primary, key));
assertTrue(affinity(cache).isPrimaryOrBackup(primary, key));
assertFalse(affinity(cache).isPrimary(backup, key));
assertTrue(affinity(cache).isBackup(backup, key));
assertTrue(affinity(cache).isPrimaryOrBackup(backup, key));
assertFalse(affinity(cache).isPrimary(other, key));
if (cacheMode() == PARTITIONED) {
assertFalse(affinity(cache).isBackup(other, key));
assertFalse(affinity(cache).isPrimaryOrBackup(other, key));
}
}
/**
*
*/
private static class CheckAffinityTask extends TestIgniteIdxRunnable {
/** Size. */
private final int size;
/**
* @param size Size.
*/
public CheckAffinityTask(int size) {
this.size = size;
}
/** {@inheritDoc} */
@Override public void run(int idx) throws Exception {
assertEquals(0, ((IgniteKernal)ignite).<String, Integer>internalCache(DEFAULT_CACHE_NAME).context().tm().idMapSize());
IgniteCache<Object, Object> cache = ignite.cache(DEFAULT_CACHE_NAME);
ClusterNode node = ((IgniteKernal)ignite).localNode();
for (int k = 0; k < size; k++) {
if (affinity(cache).isPrimaryOrBackup(node, k))
assertEquals("Check failed for node: " + node.id(), k,
cache.localPeek(k, CachePeekMode.ONHEAP, CachePeekMode.OFFHEAP));
}
}
}
/**
*
*/
private static class IsNearTask extends TestIgniteIdxRunnable {
/** {@inheritDoc} */
@Override public void run(int idx) throws Exception {
assertTrue(((IgniteKernal)ignite).internalCache(DEFAULT_CACHE_NAME).context().isNear());
}
}
}