use of org.apache.activemq.artemis.api.core.ActiveMQDuplicateIdException in project activemq-artemis by apache.
the class AsynchronousFailoverTest method doTestTransactional.
private void doTestTransactional(final TestRunner runner) throws Throwable {
// For duplication detection
int executionId = 0;
while (!runner.isFailed()) {
ClientSession session = null;
executionId++;
log.info("#test doTestTransactional starting now. Execution " + executionId);
try {
boolean retry = false;
final int numMessages = 1000;
session = sf.createSession(false, false);
listener = new CountDownSessionFailureListener(session);
session.addFailureListener(listener);
do {
try {
ClientProducer producer = session.createProducer(FailoverTestBase.ADDRESS);
for (int i = 0; i < numMessages; i++) {
ClientMessage message = session.createMessage(true);
message.getBodyBuffer().writeString("message" + i);
message.putIntProperty("counter", i);
message.putStringProperty(Message.HDR_DUPLICATE_DETECTION_ID, new SimpleString("id:" + i + ",exec:" + executionId));
addPayload(message);
if (log.isDebugEnabled()) {
log.debug("Sending message " + message);
}
producer.send(message);
}
log.debug("Sending commit");
session.commit();
retry = false;
} catch (ActiveMQDuplicateIdException die) {
logAndSystemOut("#test duplicate id rejected on sending");
break;
} catch (ActiveMQTransactionRolledBackException trbe) {
log.info("#test transaction rollback retrying on sending");
// OK
retry = true;
} catch (ActiveMQUnBlockedException ube) {
log.info("#test transaction rollback retrying on sending");
// OK
retry = true;
} catch (ActiveMQTransactionOutcomeUnknownException toue) {
log.info("#test transaction rollback retrying on sending");
// OK
retry = true;
} catch (ActiveMQException e) {
log.info("#test Exception " + e, e);
throw e;
}
} while (retry);
logAndSystemOut("#test Finished sending, starting consumption now");
boolean blocked = false;
retry = false;
ClientConsumer consumer = null;
do {
ArrayList<Integer> msgs = new ArrayList<>();
try {
if (consumer == null) {
consumer = session.createConsumer(FailoverTestBase.ADDRESS);
session.start();
}
for (int i = 0; i < numMessages; i++) {
if (log.isDebugEnabled()) {
log.debug("Consumer receiving message " + i);
}
ClientMessage message = consumer.receive(10000);
if (message == null) {
break;
}
if (log.isDebugEnabled()) {
log.debug("Received message " + message);
}
int count = message.getIntProperty("counter");
if (count != i) {
log.warn("count was received out of order, " + count + "!=" + i);
}
msgs.add(count);
message.acknowledge();
}
log.info("#test commit");
try {
session.commit();
} catch (ActiveMQTransactionRolledBackException trbe) {
// we know the tx has been rolled back so we just consume again
retry = true;
continue;
} catch (ActiveMQException e) {
// This could eventually happen
// We will get rid of this when we implement 2 phase commit on failover
log.warn("exception during commit, it will be ignored for now" + e.getMessage(), e);
}
try {
if (blocked) {
assertTrue("msgs.size is expected to be 0 or " + numMessages + " but it was " + msgs.size(), msgs.size() == 0 || msgs.size() == numMessages);
} else {
assertTrue("msgs.size is expected to be " + numMessages + " but it was " + msgs.size(), msgs.size() == numMessages);
}
} catch (Throwable e) {
log.info(threadDump("Thread dump, messagesReceived = " + msgs.size()));
logAndSystemOut(e.getMessage() + " messages received");
for (Integer msg : msgs) {
logAndSystemOut(msg.toString());
}
throw e;
}
int i = 0;
for (Integer msg : msgs) {
assertEquals(i++, (int) msg);
}
retry = false;
blocked = false;
} catch (ActiveMQTransactionRolledBackException trbe) {
logAndSystemOut("Transaction rolled back with " + msgs.size(), trbe);
// TODO: https://jira.jboss.org/jira/browse/HORNETQ-369
// ATM RolledBack exception is being called with the transaction is committed.
// the test will fail if you remove this next line
blocked = true;
retry = true;
} catch (ActiveMQTransactionOutcomeUnknownException tou) {
logAndSystemOut("Transaction rolled back with " + msgs.size(), tou);
// TODO: https://jira.jboss.org/jira/browse/HORNETQ-369
// ATM RolledBack exception is being called with the transaction is committed.
// the test will fail if you remove this next line
blocked = true;
retry = true;
} catch (ActiveMQUnBlockedException ube) {
logAndSystemOut("Unblocked with " + msgs.size(), ube);
// TODO: https://jira.jboss.org/jira/browse/HORNETQ-369
// This part of the test is never being called.
blocked = true;
retry = true;
} catch (ActiveMQException e) {
logAndSystemOut(e.getMessage(), e);
throw e;
}
} while (retry);
} finally {
if (session != null) {
session.close();
}
}
listener = null;
}
}
use of org.apache.activemq.artemis.api.core.ActiveMQDuplicateIdException in project activemq-artemis by apache.
the class DuplicateDetectionTest method testPersistTransactional.
@Test
public void testPersistTransactional() throws Exception {
ClientSession session = sf.createSession(false, false, false);
session.start();
final SimpleString queueName = new SimpleString("DuplicateDetectionTestQueue");
session.createQueue(queueName, queueName, null, false);
ClientProducer producer = session.createProducer(queueName);
ClientConsumer consumer = session.createConsumer(queueName);
ClientMessage message = createMessage(session, 1);
SimpleString dupID = new SimpleString("abcdefg");
message.putBytesProperty(Message.HDR_DUPLICATE_DETECTION_ID, dupID.getData());
producer.send(message);
session.commit();
ClientMessage message2 = consumer.receive(1000);
message2.acknowledge();
session.commit();
Assert.assertEquals(1, message2.getObjectProperty(propKey));
message = createMessage(session, 2);
SimpleString dupID2 = new SimpleString("hijklmnopqr");
message.putBytesProperty(Message.HDR_DUPLICATE_DETECTION_ID, dupID2.getData());
producer.send(message);
session.commit();
message2 = consumer.receive(1000);
message2.acknowledge();
session.commit();
Assert.assertEquals(2, message2.getObjectProperty(propKey));
session.close();
sf.close();
server.stop();
waitForServerToStop(server);
server.start();
sf = createSessionFactory(locator);
session = sf.createSession(false, false, false);
session.start();
session.createQueue(queueName, queueName, null, false);
producer = session.createProducer(queueName);
consumer = session.createConsumer(queueName);
message = createMessage(session, 1);
message.putBytesProperty(Message.HDR_DUPLICATE_DETECTION_ID, dupID.getData());
producer.send(message);
try {
session.commit();
} catch (ActiveMQDuplicateIdException die) {
session.rollback();
} catch (ActiveMQException e) {
fail("Invalid Exception type:" + e.getType());
}
message2 = consumer.receiveImmediate();
Assert.assertNull(message2);
message = createMessage(session, 2);
message.putBytesProperty(Message.HDR_DUPLICATE_DETECTION_ID, dupID2.getData());
producer.send(message);
try {
session.commit();
} catch (ActiveMQDuplicateIdException die) {
session.rollback();
} catch (ActiveMQException e) {
fail("Invalid Exception type:" + e.getType());
}
message2 = consumer.receiveImmediate();
Assert.assertNull(message2);
}
use of org.apache.activemq.artemis.api.core.ActiveMQDuplicateIdException in project activemq-artemis by apache.
the class DuplicateDetectionTest method testEntireTransactionRejected.
/*
* Entire transaction should be rejected on duplicate detection
* Even if not all entries have dupl id header
*/
@Test
public void testEntireTransactionRejected() throws Exception {
ClientSession session = sf.createSession(false, false, false);
session.start();
final SimpleString queueName = new SimpleString("DuplicateDetectionTestQueue");
final SimpleString queue2 = new SimpleString("queue2");
session.createQueue(queueName, queueName, null, false);
session.createQueue(queue2, queue2, null, false);
ClientProducer producer = session.createProducer(queueName);
ClientMessage message = createMessage(session, 0);
SimpleString dupID = new SimpleString("abcdefg");
message.putBytesProperty(Message.HDR_DUPLICATE_DETECTION_ID, dupID.getData());
producer.send(message);
ClientMessage message2 = createMessage(session, 0);
ClientProducer producer2 = session.createProducer(queue2);
producer2.send(message2);
session.commit();
session.close();
session = sf.createSession(false, false, false);
session.start();
ClientConsumer consumer2 = session.createConsumer(queue2);
producer = session.createProducer(queueName);
message = createMessage(session, 1);
message.putBytesProperty(Message.HDR_DUPLICATE_DETECTION_ID, dupID.getData());
producer.send(message);
message = createMessage(session, 2);
producer.send(message);
message = createMessage(session, 3);
producer.send(message);
message = createMessage(session, 4);
producer.send(message);
message = consumer2.receive(5000);
assertNotNull(message);
message.acknowledge();
try {
session.commit();
} catch (ActiveMQDuplicateIdException die) {
session.rollback();
} catch (ActiveMQException e) {
fail("Invalid Exception type:" + e.getType());
}
ClientConsumer consumer = session.createConsumer(queueName);
message = consumer.receive(250);
Assert.assertEquals(0, message.getObjectProperty(propKey));
message = consumer.receiveImmediate();
Assert.assertNull(message);
message = consumer2.receive(5000);
assertNotNull(message);
message.acknowledge();
session.commit();
}
use of org.apache.activemq.artemis.api.core.ActiveMQDuplicateIdException in project activemq-artemis by apache.
the class PostOfficeImpl method checkDuplicateID.
private boolean checkDuplicateID(final Message message, final RoutingContext context, boolean rejectDuplicates, AtomicBoolean startedTX) throws Exception {
// Check the DuplicateCache for the Bridge first
Object bridgeDup = message.removeExtraBytesProperty(Message.HDR_BRIDGE_DUPLICATE_ID);
if (bridgeDup != null) {
// if the message is being sent from the bridge, we just ignore the duplicate id, and use the internal one
byte[] bridgeDupBytes = (byte[]) bridgeDup;
DuplicateIDCache cacheBridge = getDuplicateIDCache(BRIDGE_CACHE_STR.concat(context.getAddress(message).toString()));
if (context.getTransaction() == null) {
context.setTransaction(new TransactionImpl(storageManager));
startedTX.set(true);
}
if (!cacheBridge.atomicVerify(bridgeDupBytes, context.getTransaction())) {
context.getTransaction().rollback();
startedTX.set(false);
message.decrementRefCount();
return false;
}
} else {
// if used BridgeDuplicate, it's not going to use the regular duplicate
// since this will would break redistribution (re-setting the duplicateId)
byte[] duplicateIDBytes = message.getDuplicateIDBytes();
DuplicateIDCache cache = null;
boolean isDuplicate = false;
if (duplicateIDBytes != null) {
cache = getDuplicateIDCache(context.getAddress(message));
isDuplicate = cache.contains(duplicateIDBytes);
if (rejectDuplicates && isDuplicate) {
ActiveMQServerLogger.LOGGER.duplicateMessageDetected(message);
String warnMessage = "Duplicate message detected - message will not be routed. Message information:" + message.toString();
if (context.getTransaction() != null) {
context.getTransaction().markAsRollbackOnly(new ActiveMQDuplicateIdException(warnMessage));
}
message.decrementRefCount();
return false;
}
}
if (cache != null && !isDuplicate) {
if (context.getTransaction() == null) {
// We need to store the duplicate id atomically with the message storage, so we need to create a tx for this
context.setTransaction(new TransactionImpl(storageManager));
startedTX.set(true);
}
cache.addToCache(duplicateIDBytes, context.getTransaction(), false);
}
}
return true;
}
use of org.apache.activemq.artemis.api.core.ActiveMQDuplicateIdException in project activemq-artemis by apache.
the class FailoverTest method testCommitOccurredUnblockedAndResendNoDuplicates.
@Test(timeout = 120000)
public void testCommitOccurredUnblockedAndResendNoDuplicates() throws Exception {
locator.setBlockOnNonDurableSend(true).setBlockOnDurableSend(true).setReconnectAttempts(300).setRetryInterval(100).setBlockOnAcknowledge(true);
sf = createSessionFactoryAndWaitForTopology(locator, 2);
final ClientSession session = createSession(sf, false, false);
session.createQueue(FailoverTestBase.ADDRESS, RoutingType.MULTICAST, FailoverTestBase.ADDRESS, null, true);
ClientProducer producer = session.createProducer(FailoverTestBase.ADDRESS);
String txID = "my-tx-id";
for (int i = 0; i < NUM_MESSAGES; i++) {
ClientMessage message = session.createMessage(true);
if (i == 0) {
// Only need to add it on one message per tx
message.putStringProperty(Message.HDR_DUPLICATE_DETECTION_ID, new SimpleString(txID));
}
setBody(i, message);
message.putIntProperty("counter", i);
producer.send(message);
}
class Committer extends Thread {
DelayInterceptor2 interceptor = new DelayInterceptor2();
@Override
public void run() {
try {
sf.getServerLocator().addIncomingInterceptor(interceptor);
session.commit();
} catch (ActiveMQTransactionRolledBackException trbe) {
// Ok - now we retry the commit after removing the interceptor
sf.getServerLocator().removeIncomingInterceptor(interceptor);
try {
session.commit();
failed = false;
} catch (ActiveMQException e2) {
throw new RuntimeException(e2);
}
} catch (ActiveMQTransactionOutcomeUnknownException toue) {
// Ok - now we retry the commit after removing the interceptor
sf.getServerLocator().removeIncomingInterceptor(interceptor);
try {
session.commit();
failed = false;
} catch (ActiveMQException e2) {
throw new RuntimeException(e2);
}
} catch (ActiveMQException e) {
// ignore
}
}
volatile boolean failed = true;
}
Committer committer = new Committer();
// Commit will occur, but response will never get back, connection is failed, and commit
// should be unblocked with transaction rolled back
committer.start();
// Wait for the commit to occur and the response to be discarded
Assert.assertTrue(committer.interceptor.await());
crash(session);
committer.join();
Assert.assertFalse("second attempt succeed?", committer.failed);
session.close();
ClientSession session2 = createSession(sf, false, false);
producer = session2.createProducer(FailoverTestBase.ADDRESS);
for (int i = 0; i < NUM_MESSAGES; i++) {
ClientMessage message = session2.createMessage(true);
if (i == 0) {
// Only need to add it on one message per tx
message.putStringProperty(Message.HDR_DUPLICATE_DETECTION_ID, new SimpleString(txID));
}
setBody(i, message);
message.putIntProperty("counter", i);
producer.send(message);
}
try {
session2.commit();
Assert.fail("expecting DUPLICATE_ID_REJECTED exception");
} catch (ActiveMQDuplicateIdException dide) {
// ok
} catch (ActiveMQException e) {
Assert.fail("Invalid Exception type:" + e.getType());
}
ClientConsumer consumer = session2.createConsumer(FailoverTestBase.ADDRESS);
session2.start();
receiveMessages(consumer);
ClientMessage message = consumer.receiveImmediate();
Assert.assertNull(message);
}
Aggregations