/*
* 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.datastructures;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.IgniteQueue;
import org.apache.ignite.configuration.CollectionConfiguration;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.G;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.lang.IgniteCallable;
import org.apache.ignite.resources.IgniteInstanceResource;
import org.apache.ignite.testframework.GridTestUtils;
/**
* Queue multi node tests.
*/
public abstract class GridCacheQueueRotativeMultiNodeAbstractTest extends IgniteCollectionAbstractTest {
/** */
protected static final int GRID_CNT = 4;
/** */
protected static final int RETRIES = 133;
/** */
private static final int QUEUE_CAPACITY = 100_000;
/** */
private static CountDownLatch lthTake;
/** {@inheritDoc} */
@Override protected int gridCount() {
return GRID_CNT;
}
/** {@inheritDoc} */
@Override protected void beforeTestsStarted() throws Exception {
// No-op.
}
/** {@inheritDoc} */
@Override protected void beforeTest() throws Exception {
for (int i = 0; i < GRID_CNT; i++)
startGrid(i);
assert G.allGrids().size() == GRID_CNT : G.allGrids().size();
}
/** {@inheritDoc} */
@Override protected void afterTest() throws Exception {
stopAllGrids();
assert G.allGrids().isEmpty();
}
/**
* JUnit.
*
* @throws Exception If failed.
*/
public void testPutRotativeNodes() throws Exception {
String queueName = UUID.randomUUID().toString();
IgniteQueue<Integer> queue =
grid(0).queue(queueName, QUEUE_CAPACITY, config(true));
assertTrue(queue.isEmpty());
// Start and stop GRID_CNT*2 new nodes.
for (int i = GRID_CNT; i < GRID_CNT * 3; i++) {
startGrid(i);
forLocal(grid(i)).call(new PutJob(queueName, config(true), RETRIES));
// last node must be alive.
if (i < (GRID_CNT * 3) - 1)
stopGrid(i);
}
queue = grid((GRID_CNT * 3) - 1).queue(queueName, 0, null);
assertEquals(RETRIES * GRID_CNT * 2, queue.size());
}
/**
* JUnit.
*
* @throws Exception If failed.
*/
public void testPutTakeRotativeNodes() throws Exception {
String queueName = UUID.randomUUID().toString();
IgniteQueue<Integer> queue =
grid(0).queue(queueName, QUEUE_CAPACITY, config(true));
assertTrue(queue.isEmpty());
// Start and stop GRID_CNT*2 new nodes.
for (int i = GRID_CNT; i < GRID_CNT * 3; i++) {
startGrid(i);
forLocal(grid(i)).call(new PutTakeJob(queueName, config(true), RETRIES));
// last node must be alive.
if (i < (GRID_CNT * 3) - 1)
stopGrid(i);
}
queue = grid((GRID_CNT * 3) - 1).queue(queueName, QUEUE_CAPACITY, config(true));
assertEquals(0, queue.size());
}
/**
* JUnit.
*
* @throws Exception If failed.
*/
public void testTakeRemoveRotativeNodes() throws Exception {
lthTake = new CountDownLatch(1);
final String queueName = UUID.randomUUID().toString();
final IgniteQueue<Integer> queue =
grid(0).queue(queueName, QUEUE_CAPACITY, config(true));
assertTrue(queue.isEmpty());
Thread th = new Thread(new Runnable() {
@Override public void run() {
try {
assert grid(1).compute().call(new TakeJob(queueName, config(true)));
}
catch (IgniteException e) {
error(e.getMessage(), e);
}
}
});
th.start();
assert lthTake.await(1, TimeUnit.MINUTES) : "Timeout happened.";
assertTrue(grid(2).compute().call(new RemoveQueueJob(queueName)));
GridTestUtils.assertThrows(log, new Callable<Void>() {
@Override public Void call() throws Exception {
queue.poll();
return null;
}
}, IllegalStateException.class, null);
info("Queue was removed: " + queue);
th.join();
}
/**
* Test job putting data to queue.
*/
protected static class PutJob implements IgniteCallable<Integer> {
/** */
@GridToStringExclude
@IgniteInstanceResource
private Ignite ignite;
/** Queue name. */
private final String queueName;
/** */
private final int retries;
/** */
private final CollectionConfiguration colCfg;
/**
* @param queueName Queue name.
* @param colCfg Collection configuration.
* @param retries Number of operations.
*/
PutJob(String queueName, CollectionConfiguration colCfg, int retries) {
this.queueName = queueName;
this.colCfg = colCfg;
this.retries = retries;
}
/** {@inheritDoc} */
@Override public Integer call() throws IgniteCheckedException {
assertNotNull(ignite);
ignite.log().info("Running job [node=" + ignite.cluster().localNode().id() + ", job=" + this + "]");
IgniteQueue<Integer> queue = ignite.queue(queueName, QUEUE_CAPACITY, colCfg);
assertNotNull(queue);
for (int i = 0; i < retries; i++)
queue.put(i);
return queue.size();
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(PutJob.class, this);
}
}
/**
* Test job putting and taking data to/from queue.
*/
protected static class PutTakeJob implements IgniteCallable<Integer> {
/** */
@GridToStringExclude
@IgniteInstanceResource
private Ignite ignite;
/** Queue name. */
private final String queueName;
/** */
private final int retries;
/** */
private final CollectionConfiguration colCfg;
/**
* @param queueName Queue name.
* @param colCfg Queue configuration.
* @param retries Number of operations.
*/
PutTakeJob(String queueName, CollectionConfiguration colCfg, int retries) {
this.queueName = queueName;
this.colCfg = colCfg;
this.retries = retries;
}
/** {@inheritDoc} */
@Override public Integer call() throws IgniteCheckedException {
assertNotNull(ignite);
ignite.log().info("Running job [node=" + ignite.cluster().localNode().id() + ", job=" + this + ']');
IgniteQueue<Integer> queue = ignite.queue(queueName, QUEUE_CAPACITY, colCfg);
assertNotNull(queue);
for (int i = 0; i < retries; i++) {
queue.put(i);
assertNotNull(queue.peek());
assertNotNull(queue.element());
assertNotNull(queue.take());
}
return queue.size();
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(PutTakeJob.class, this);
}
}
/**
* Test job taking data from queue.
*/
protected static class TakeJob implements IgniteCallable<Boolean> {
/** */
@IgniteInstanceResource
private Ignite ignite;
/** Queue name. */
private final String queueName;
/** */
private final CollectionConfiguration colCfg;
/**
* @param queueName Queue name.
* @param colCfg Collection configuration.
*/
TakeJob(String queueName, CollectionConfiguration colCfg) {
this.queueName = queueName;
this.colCfg = colCfg;
}
/** {@inheritDoc} */
@Override public Boolean call() throws IgniteCheckedException {
assertNotNull(ignite);
ignite.log().info("Running job [node=" + ignite.cluster().localNode().id() + ", job=" + this + ']');
IgniteQueue<Integer> queue = ignite.queue(queueName, QUEUE_CAPACITY, colCfg);
assertNotNull(queue);
try {
// Queue can be removed.
lthTake.countDown();
queue.take();
}
catch (IgniteException e) {
ignite.log().info("Caught expected exception: " + e.getMessage());
}
return queue.removed();
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(TakeJob.class, this);
}
}
/**
* Job removing queue.
*/
protected static class RemoveQueueJob implements IgniteCallable<Boolean> {
/** */
@IgniteInstanceResource
private Ignite ignite;
/** Queue name. */
private final String queueName;
/**
* @param queueName Queue name.
*/
RemoveQueueJob(String queueName) {
this.queueName = queueName;
}
/** {@inheritDoc} */
@Override public Boolean call() throws IgniteCheckedException {
assertNotNull(ignite);
ignite.log().info("Running job [node=" + ignite.cluster().localNode().id() + ", job=" + this + "]");
IgniteQueue<Integer> queue = ignite.queue(queueName, 0, null);
assert queue != null;
assert queue.capacity() == QUEUE_CAPACITY;
queue.close();
return true;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(RemoveQueueJob.class, this);
}
}
}