[jira] [Commented] (AMQ-5712) Broker can deadlock when using queues while producers wait on disk space
[ https://issues.apache.org/jira/browse/AMQ-5712?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=14492768#comment-14492768 ] Paul Gale commented on AMQ-5712: Perhaps I've missed something but if you're working with non-persistent messages then why not configure a policyEntry for the queue to use a vmCursor rather than the default storeCursor? Regardless, I agree that the temp store's implementation needs some work. Ideally it should honor the sendFailIfNoSpaceAfterTimeout when configured on the systemUsage element. Broker can deadlock when using queues while producers wait on disk space Key: AMQ-5712 URL: https://issues.apache.org/jira/browse/AMQ-5712 Project: ActiveMQ Issue Type: Bug Components: Broker Affects Versions: 5.11.1 Reporter: Christopher L. Shannon I am experiencing a deadlock when using a Queue with non-persistent messages. The queue has a cursor high memory water mark set (right now at 70%). When a producer is producing messages quickly to the queue and that limit gets hit, the broker can deadlock. I have tried setting producerWindowSize and alwaysSyncSend which did not seem to help. When the broker hits that limit, I am unable to do things like purge the queue. Consumers can also deadlock as well. Note that this appears to be the same issue as described in this ticket here: AMQ-2475 . The difference is that I am using a Queue and not a Topic and the fix for this appears to only have been for Topics. The problem appears to be in the Queue class on line 1852 inside the {{cursorAdd}} method. The method being called is {{return messages.addMessageLast(msg);}} which will block indefinitely if there is no space available, which in turn ties up the {{messagesLock}} from being used by any other threads. We have seen a deadlock where consumers can't consume because they are waiting on this lock. It looks like in AMQ-2475 part of the fix was to replace {{messages.addMessageLast(msg)}} with {{messages.tryAddMessageLast(msg, 10)}}. I also noticed that not all of the message cursors support {{tryAddMessageLast}}, which could be a problem. {{FilePendingMessageCursor}} implements it but the rest of the cursors (notably {{StoreQueueCursor}}) simply delegate back to {{addMessageLast}} in the parent class. So part of this fix may require implementing {{tryAddMessageLast}} across more cursors. Here is part of the thread dump showing the stuck producer: {code} ActiveMQ Transport: ssl:///192.168.3.142:38589 daemon prio=10 tid=0x7fb46c006000 nid=0x3b1a runnable [0x7fb4b8a0d000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for 0xcfb13cd0 (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2176) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:103) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:90) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:80) at org.apache.activemq.broker.region.cursors.FilePendingMessageCursor.tryAddMessageLast(FilePendingMessageCursor.java:235) - locked 0xd2015ee0 (a org.apache.activemq.broker.region.cursors.FilePendingMessageCursor) at org.apache.activemq.broker.region.cursors.FilePendingMessageCursor.addMessageLast(FilePendingMessageCursor.java:207) - locked 0xd2015ee0 (a org.apache.activemq.broker.region.cursors.FilePendingMessageCursor) at org.apache.activemq.broker.region.cursors.StoreQueueCursor.addMessageLast(StoreQueueCursor.java:97) - locked 0xd1f20908 (a org.apache.activemq.broker.region.cursors.StoreQueueCursor) {code} -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Commented] (AMQ-5712) Broker can deadlock when using queues while producers wait on disk space
[ https://issues.apache.org/jira/browse/AMQ-5712?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=14492866#comment-14492866 ] Paul Gale commented on AMQ-5712: I too have hit the same limitations of the temp store. In the interim you can always force the broker to treat all messages as persistent using the {{forcePersistencyModeBrokerPlugin}}. Alternatively use the broker component. Perhaps you might need to supplement it with (it's been a while) this to force the cursor to not use the temp store: {code} pendingQueuePolicy storeCursor/ /pendingQueuePolicy {code} Is PFC disabled for your queue? If so, why? Regardless, even if the temp store worked correctly both memory and disk are limited resources so you're only delaying the inevitable as one of them will eventually fill up - that is, not unless the producer is flow controlled. Broker can deadlock when using queues while producers wait on disk space Key: AMQ-5712 URL: https://issues.apache.org/jira/browse/AMQ-5712 Project: ActiveMQ Issue Type: Bug Components: Broker Affects Versions: 5.11.1 Reporter: Christopher L. Shannon I am experiencing a deadlock when using a Queue with non-persistent messages. The queue has a cursor high memory water mark set (right now at 70%). When a producer is producing messages quickly to the queue and that limit gets hit, the broker can deadlock. I have tried setting producerWindowSize and alwaysSyncSend which did not seem to help. When the broker hits that limit, I am unable to do things like purge the queue. Consumers can also deadlock as well. Note that this appears to be the same issue as described in this ticket here: AMQ-2475 . The difference is that I am using a Queue and not a Topic and the fix for this appears to only have been for Topics. The problem appears to be in the Queue class on line 1852 inside the {{cursorAdd}} method. The method being called is {{return messages.addMessageLast(msg);}} which will block indefinitely if there is no space available, which in turn ties up the {{messagesLock}} from being used by any other threads. We have seen a deadlock where consumers can't consume because they are waiting on this lock. It looks like in AMQ-2475 part of the fix was to replace {{messages.addMessageLast(msg)}} with {{messages.tryAddMessageLast(msg, 10)}}. I also noticed that not all of the message cursors support {{tryAddMessageLast}}, which could be a problem. {{FilePendingMessageCursor}} implements it but the rest of the cursors (notably {{StoreQueueCursor}}) simply delegate back to {{addMessageLast}} in the parent class. So part of this fix may require implementing {{tryAddMessageLast}} across more cursors. Here is part of the thread dump showing the stuck producer: {code} ActiveMQ Transport: ssl:///192.168.3.142:38589 daemon prio=10 tid=0x7fb46c006000 nid=0x3b1a runnable [0x7fb4b8a0d000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for 0xcfb13cd0 (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2176) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:103) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:90) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:80) at org.apache.activemq.broker.region.cursors.FilePendingMessageCursor.tryAddMessageLast(FilePendingMessageCursor.java:235) - locked 0xd2015ee0 (a org.apache.activemq.broker.region.cursors.FilePendingMessageCursor) at org.apache.activemq.broker.region.cursors.FilePendingMessageCursor.addMessageLast(FilePendingMessageCursor.java:207) - locked 0xd2015ee0 (a org.apache.activemq.broker.region.cursors.FilePendingMessageCursor) at org.apache.activemq.broker.region.cursors.StoreQueueCursor.addMessageLast(StoreQueueCursor.java:97) - locked 0xd1f20908 (a org.apache.activemq.broker.region.cursors.StoreQueueCursor) {code} -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Commented] (AMQ-5712) Broker can deadlock when using queues while producers wait on disk space
[ https://issues.apache.org/jira/browse/AMQ-5712?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=14493044#comment-14493044 ] Paul Gale commented on AMQ-5712: I don't see how this plugin puts a requirement on the producer. For example, setting {{forcePersistencyModeBrokerPlugin persistenceFlag=true/}} allows the producer to send either form. It simply makes all messages persistent (or non-persistent if {{false}}). Broker can deadlock when using queues while producers wait on disk space Key: AMQ-5712 URL: https://issues.apache.org/jira/browse/AMQ-5712 Project: ActiveMQ Issue Type: Bug Components: Broker Affects Versions: 5.11.1 Reporter: Christopher L. Shannon I am experiencing a deadlock when using a Queue with non-persistent messages. The queue has a cursor high memory water mark set (right now at 70%). When a producer is producing messages quickly to the queue and that limit gets hit, the broker can deadlock. I have tried setting producerWindowSize and alwaysSyncSend which did not seem to help. When the broker hits that limit, I am unable to do things like purge the queue. Consumers can also deadlock as well. Note that this appears to be the same issue as described in this ticket here: AMQ-2475 . The difference is that I am using a Queue and not a Topic and the fix for this appears to only have been for Topics. The problem appears to be in the Queue class on line 1852 inside the {{cursorAdd}} method. The method being called is {{return messages.addMessageLast(msg);}} which will block indefinitely if there is no space available, which in turn ties up the {{messagesLock}} from being used by any other threads. We have seen a deadlock where consumers can't consume because they are waiting on this lock. It looks like in AMQ-2475 part of the fix was to replace {{messages.addMessageLast(msg)}} with {{messages.tryAddMessageLast(msg, 10)}}. I also noticed that not all of the message cursors support {{tryAddMessageLast}}, which could be a problem. {{FilePendingMessageCursor}} implements it but the rest of the cursors (notably {{StoreQueueCursor}}) simply delegate back to {{addMessageLast}} in the parent class. So part of this fix may require implementing {{tryAddMessageLast}} across more cursors. Here is part of the thread dump showing the stuck producer: {code} ActiveMQ Transport: ssl:///192.168.3.142:38589 daemon prio=10 tid=0x7fb46c006000 nid=0x3b1a runnable [0x7fb4b8a0d000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for 0xcfb13cd0 (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2176) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:103) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:90) at org.apache.activemq.usage.Usage.waitForSpace(Usage.java:80) at org.apache.activemq.broker.region.cursors.FilePendingMessageCursor.tryAddMessageLast(FilePendingMessageCursor.java:235) - locked 0xd2015ee0 (a org.apache.activemq.broker.region.cursors.FilePendingMessageCursor) at org.apache.activemq.broker.region.cursors.FilePendingMessageCursor.addMessageLast(FilePendingMessageCursor.java:207) - locked 0xd2015ee0 (a org.apache.activemq.broker.region.cursors.FilePendingMessageCursor) at org.apache.activemq.broker.region.cursors.StoreQueueCursor.addMessageLast(StoreQueueCursor.java:97) - locked 0xd1f20908 (a org.apache.activemq.broker.region.cursors.StoreQueueCursor) {code} -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Created] (AMQ-5636) Upgrade the bundled DBCP component. The current one is very old and buggy.
Paul Gale created AMQ-5636: -- Summary: Upgrade the bundled DBCP component. The current one is very old and buggy. Key: AMQ-5636 URL: https://issues.apache.org/jira/browse/AMQ-5636 Project: ActiveMQ Issue Type: Improvement Components: JDBC, KahaDB Affects Versions: 5.11.0, 5.10.0 Reporter: Paul Gale Priority: Critical Fix For: 5.11.1, 5.12.0 The current DBCP component that ships with ActiveMQ is version 1.4. It dates from Feb 2010. After fours years of inactivity a number of releases were made in the last twelve months to the DBCP component. The most recent version, 2.1, was released on Feb 23rd 2015. Personally, I am seeing weird behavior with the DBCP 1.4 component when using it as a lease locker with KahaDB. When a connection is dropped the DBCP component doesn't always handle it correctly which manifests itself as a lease lock failure from the broker's standpoint. -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Created] (AMQ-5505) Add support for the BrokerView MBean to get the up-time in milliseconds
Paul Gale created AMQ-5505: -- Summary: Add support for the BrokerView MBean to get the up-time in milliseconds Key: AMQ-5505 URL: https://issues.apache.org/jira/browse/AMQ-5505 Project: ActiveMQ Issue Type: Improvement Components: Broker, JMX Affects Versions: 5.10.0 Reporter: Paul Gale Fix For: 5.11.0 Currently one can only get the broker's up-time as a formatted string via JMX. I need to be able to get the up-time in milliseconds as we're using DataDog as our monitoring tool (which doesn't understand the current up-time formatted string). The up-time formatted string will remain as-is. -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Updated] (AMQ-5174) Cannot use the JDBCIOExceptionHandler when kahadb is configured with lease-database-locker
[ https://issues.apache.org/jira/browse/AMQ-5174?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-5174: --- Affects Version/s: 5.10.0 Cannot use the JDBCIOExceptionHandler when kahadb is configured with lease-database-locker -- Key: AMQ-5174 URL: https://issues.apache.org/jira/browse/AMQ-5174 Project: ActiveMQ Issue Type: Bug Components: Message Store Affects Versions: 5.9.0, 5.9.1, 5.10.0 Reporter: Paul Gale Priority: Critical Fix For: 5.11.0 The {{JDBCIOExceptionHandler}} is limited to operating with the {{JDBCPersistenceAdapter}}. It should be allowed to work in combination with the {{KahaDBPersistenceAdapter}} if it's configured to use a {{LeaseDatabaseLocker}} as a locker. -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Commented] (AMQ-5030) Upgrade Camel to latest 2.12.x patch
[ https://issues.apache.org/jira/browse/AMQ-5030?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=14018830#comment-14018830 ] Paul Gale commented on AMQ-5030: Is there any reason why Camel cannot be upgraded to 2.13.1 instead of 2.12x? Upgrade Camel to latest 2.12.x patch Key: AMQ-5030 URL: https://issues.apache.org/jira/browse/AMQ-5030 Project: ActiveMQ Issue Type: Task Components: activemq-camel Reporter: Claus Ibsen Assignee: Hadrian Zbarcea Priority: Blocker Fix For: 5.10.0 We need to upgrade to latest Camel 2.12.3 release to pickup some very important fixes. -- This message was sent by Atlassian JIRA (v6.2#6252)
[jira] [Created] (AMQ-5174) Cannot use the JDBCIOExceptionHandler when kahadb is configured with lease-database-locker
Paul Gale created AMQ-5174: -- Summary: Cannot use the JDBCIOExceptionHandler when kahadb is configured with lease-database-locker Key: AMQ-5174 URL: https://issues.apache.org/jira/browse/AMQ-5174 Project: ActiveMQ Issue Type: Bug Components: Message Store Affects Versions: 5.9.1, 5.9.0 Reporter: Paul Gale Priority: Critical Fix For: 5.10.0 The {{JDBCIOExceptionHandler}} is limited to operating with the {{JDBCPersistenceAdapter}}. It should be allowed to work in combination with the {{KahaDBPersistenceAdapter}} if it's configured to use a {{LeaseDatabaseLocker}} as a locker. -- This message was sent by Atlassian JIRA (v6.2#6252)
[jira] [Commented] (AMQ-5091) Upgrade to jolokia 1.2
[ https://issues.apache.org/jira/browse/AMQ-5091?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13989434#comment-13989434 ] Paul Gale commented on AMQ-5091: It appears that jolokia 1.2.1 is still being built with json-simple 1.1.1. Therefore we can either ask the maintainers to update Jolokia to use json-simple 1.1.1 or ship our own version of Jolokia built against json-simple 1.1.1 instead? Version 1.1.1 of json-simple has been around for over two years and includes OSGI support which 1.1.0 does not. If that's too much of a headache then perhaps not. Just a thought. Upgrade to jolokia 1.2 -- Key: AMQ-5091 URL: https://issues.apache.org/jira/browse/AMQ-5091 Project: ActiveMQ Issue Type: Improvement Components: Broker Reporter: Claus Ibsen Assignee: Claus Ibsen Fix For: 5.10.0 Jolokia 1.2.0 has been released. -- This message was sent by Atlassian JIRA (v6.2#6252)
[jira] [Commented] (AMQ-4728) Develop a pluggable locker that can be shared broker-wide for both the persistence adapter as well as the redelivery plugin
[ https://issues.apache.org/jira/browse/AMQ-4728?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13939746#comment-13939746 ] Paul Gale commented on AMQ-4728: Now that I've re-read this I was wondering if a better solution might be to have the redelivery scheduler store its messages in the main message store rather than create a separate locker for its separate message store. Thoughts? If this is a lot of work then I think it would be best to move this out to the 5.11+ release. Develop a pluggable locker that can be shared broker-wide for both the persistence adapter as well as the redelivery plugin --- Key: AMQ-4728 URL: https://issues.apache.org/jira/browse/AMQ-4728 Project: ActiveMQ Issue Type: New Feature Components: Broker, Message Store Affects Versions: 5.8.0 Reporter: Paul Gale Fix For: 5.10.0 Modify the redelivery plugin so that it can be configured with a pluggable storage locker. Allow the same locker to optionally be configured at the broker level so that the same locker instance can be shared by all components that need it, e.g., the persistence adapter (including multi kaha) and the redelivery plugin. -- This message was sent by Atlassian JIRA (v6.2#6252)
[jira] [Commented] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a kahadb lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13870028#comment-13870028 ] Paul Gale commented on AMQ-4365: With this change in place does the broker handle the two scenarios where the database is either offline at start-up or goes offline at at some point after start-up? If so, how? If not, what modifications are needed for the broker to cope with these scenarios? I am trying to get an idea for the nature and magnitude of any required changes. Ideally the broker should attempt to (re)connect indefinitely in both scenarios. Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a kahadb lock Key: AMQ-4365 URL: https://issues.apache.org/jira/browse/AMQ-4365 Project: ActiveMQ Issue Type: Improvement Affects Versions: 5.8.0 Reporter: Gary Tully Assignee: Gary Tully Fix For: 5.9.0 The locker interface needs another configure option to provide a broker service, or needs to be brokerService aware so that a locker can get identity and access to the io exception handlers. The lease database locker is dependent on the jdbc pa to get statements and data source. It should be possible to configure these independently such that it can be used standalone as a broker lock. So setters for each. This will help sort out some of the dependencies between broker and lock implementations. also making it possible to use a lease lock with kahadb for example. some context: http://mail-archives.apache.org/mod_mbox/activemq-users/201303.mbox/%3ccaj5znhuruz+aewsaabajtwbbpkwn06ryyyt6nqsdg_su7vm...@mail.gmail.com%3E -- This message was sent by Atlassian JIRA (v6.1.5#6160)
[jira] [Commented] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13765545#comment-13765545 ] Paul Gale commented on AMQ-4710: Any movement on this? I'd like to know whether this patch is going to be accepted or if other feedback is available. The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq-4710.diff After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4710: --- Attachment: (was: amq-4710.diff) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4710: --- Attachment: amq-4710.diff Latest greatest, and hopefully final, version of test and fix. The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq-4710.diff After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Issue Comment Deleted] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4710: --- Comment: was deleted (was: Updated patch containing fix for Jira AMQ-4710. Improved the checking for when to recreate the write checker timer task. Previous patch attachment has been deleted.) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq-4710.diff After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4710: --- Attachment: (was: amq_4710_2.patch) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq-4710.diff After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4710: --- Attachment: amq-4710.diff Unit test and patch to fix this issue. The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq-4710.diff After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Commented] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13761912#comment-13761912 ] Paul Gale commented on AMQ-4710: Just realized I should have used a StompConnection object in the test. Trying again. The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq-4710.diff After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Issue Comment Deleted] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4710: --- Comment: was deleted (was: I have modified my last patch. The latest has been attached as amq_4710_2.patch) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq_4710_2.patch After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4710: --- Attachment: amq_4710_2.patch Patch containing fix for Jira AMQ-4710. Improved the checking for when to recreate the write checker timer task. The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq_4710_2.patch, amq_4710.patch After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Commented] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13758353#comment-13758353 ] Paul Gale commented on AMQ-4710: Sending a frame is sending data on the wire so the send of the RECEIPT frame prempts any need to send a KEEPALIVE frame. Agreed. However, once data has been sent in lieu of a KEEPALIVE frame the write checker timer should be adjusted accordingly, otherwise it will sleep for twice its configured interval. I have attached a patch file containing a failing unit test (of sorts) and a fix. The test is not the prettiest so adjust as necessary. The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq_4710.patch After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4710: --- Attachment: amq_4710.patch Patch file containing test and fix for this issue. The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson Attachments: amq_4710.patch After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Commented] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13757072#comment-13757072 ] Paul Gale commented on AMQ-4710: This problem doesn't just happen on startup. I've been able to induce this behavior in the broker. I modified the test to periodically send a frame to the broker containing a receipt header. This forces the broker to respond with a RECEIPT frame. After sending the RECEIPT frame the broker waits another 1ms (in this case) before issuing another write check. The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Commented] (AMQ-4710) The first heart-beat after a connection becomes idle isn't sent as quickly as it should be
[ https://issues.apache.org/jira/browse/AMQ-4710?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13757189#comment-13757189 ] Paul Gale commented on AMQ-4710: I believe the fix for this condition is as follows. I've tested it and it appears to work. However, feedback is welcome if there's a better way to handle this. {code} private final Runnable writeChecker = new Runnable() { long lastRunTime; @Override public void run() { long now = System.currentTimeMillis(); long sleepTime = now - lastRunTime; if (lastRunTime != 0 LOG.isDebugEnabled()) { LOG.debug(this + + sleepTime + ms elapsed since last write check.); } if (commandSent.get() sleepTime = getWriteCheckTime()) { LOG.trace(Resetting to prevent double sleep !!); commandSent.set(false); } lastRunTime = now; writeCheck(); } @Override public String toString() { return WriteChecker; } }; {code} The first heart-beat after a connection becomes idle isn't sent as quickly as it should be -- Key: AMQ-4710 URL: https://issues.apache.org/jira/browse/AMQ-4710 Project: ActiveMQ Issue Type: Bug Components: stomp Affects Versions: 5.8.0 Reporter: Andy Wilkinson After ActiveMQ sends a stomp frame, it may not send a heart-beat for up to almost 2x the negotiated interval. The following test should illustrate the problem: {code} import org.junit.Test; import static org.junit.Assert.*; public class ActiveMqHeartbeatTests { @Test public void heartbeats() throws Exception { BrokerService broker = createAndStartBroker(); Socket socket = null; try { socket = new Socket(localhost, 61613); byte[] connectFrame = CONNECT\nheart-beat:0,1\naccept-version:1.2\n\n\0.getBytes(); socket.getOutputStream().write(connectFrame); byte[] buffer = new byte[4096]; long lastReadTime = System.currentTimeMillis(); while (true) { int read = socket.getInputStream().read(buffer); byte[] frame = Arrays.copyOf(buffer, read); long now = System.currentTimeMillis(); long timeSinceLastRead = now - lastReadTime; lastReadTime = now; System.out.println(new String(frame)); System.out.println(Time since last read: + timeSinceLastRead + ms); if (timeSinceLastRead 15000) { fail(Data not received for + timeSinceLastRead + ms); } } } finally { if (socket != null) { socket.close(); } broker.stop(); } } private BrokerService createAndStartBroker() throws Exception { BrokerService broker = new BrokerService(); broker.addConnector(stomp://localhost:61613); broker.setStartAsync(false); broker.setDeleteAllMessagesOnStartup(true); broker.start(); return broker; } } {code} For the initial read of the CONNECTED frame I see: {noformat} Time since last read: 49ms {noformat} However, it's then almost 20 seconds before a heart-beat's sent: {noformat} Time since last read: 19994ms {noformat} If I comment out the fail(…) line in the test, after the first heartbeat taking almost 2ms to be sent, things settle down and a heartbeat's received every 1ms. It looks like the write checker wakes up every 1ms. The first time it wakes up, it notices that the CONNECTED frame was sent and does nothing. It then sleeps for a further 1ms before checking again. As the CONNECTED frame was sent very early in the first 1ms window, this leads to it taking almost 2ms for the first heart-beat to be sent. From this point, as no further data frames are sent, the write checker wakes up and sends a heart-beat every 1ms. In short, I don't think ActiveMQ is adhering to the requirement that the sender MUST send new data over the network connection at least every n milliseconds. -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more
[jira] [Commented] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13754986#comment-13754986 ] Paul Gale commented on AMQ-4365: See here: https://github.com/ppaul/amq-db-lease-locker I warn you, it's a hack but it does work. Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock Key: AMQ-4365 URL: https://issues.apache.org/jira/browse/AMQ-4365 Project: ActiveMQ Issue Type: Improvement Affects Versions: 5.8.0 Reporter: Gary Tully Assignee: Gary Tully Fix For: 5.9.0 The locker interface needs another configure option to provide a broker service, or needs to be brokerService aware so that a locker can get identity and access to the io exception handlers. The lease database locker is dependent on the jdbc pa to get statements and data source. It should be possible to configure these independently such that it can be used standalone as a broker lock. So setters for each. This will help sort out some of the dependencies between broker and lock implementations. also making it possible to use a lease lock with kahadb for example. some context: http://mail-archives.apache.org/mod_mbox/activemq-users/201303.mbox/%3ccaj5znhuruz+aewsaabajtwbbpkwn06ryyyt6nqsdg_su7vm...@mail.gmail.com%3E -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Commented] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13752512#comment-13752512 ] Paul Gale commented on AMQ-4365: Since making this initial request back in March I have completed the locker implementation. Therefore my earlier comment about needing a SQL script is no longer relevant. The locker auto-creates the table if it's missing in the same manner as the JDBCPersistenceAdapter. Note that my implementation is a total hack, e.g., no tests. It was designed to see me through until I can upgrade to ActiveMQ 5.9.0 at which point I plan to switch storage strategy to Replicated LevelDB. If there's any interest in seeing my implementation, let me know and I'll put it up on Github. Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock Key: AMQ-4365 URL: https://issues.apache.org/jira/browse/AMQ-4365 Project: ActiveMQ Issue Type: Improvement Affects Versions: 5.8.0 Reporter: Gary Tully Assignee: Gary Tully Fix For: 5.9.0 The locker interface needs another configure option to provide a broker service, or needs to be brokerService aware so that a locker can get identity and access to the io exception handlers. The lease database locker is dependent on the jdbc pa to get statements and data source. It should be possible to configure these independently such that it can be used standalone as a broker lock. So setters for each. This will help sort out some of the dependencies between broker and lock implementations. also making it possible to use a lease lock with kahadb for example. some context: http://mail-archives.apache.org/mod_mbox/activemq-users/201303.mbox/%3ccaj5znhuruz+aewsaabajtwbbpkwn06ryyyt6nqsdg_su7vm...@mail.gmail.com%3E -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Commented] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
[ https://issues.apache.org/jira/browse/AMQ-4674?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13745128#comment-13745128 ] Paul Gale commented on AMQ-4674: I think something has gone awry here. This implementation of a 'grace period' doesn't really help. What I am observing, after configuring the grace period with a value of 1.5, is that when a client connects (simplified): CONNECT heart-beat:5000,0 the broker responds with: CONNECTED heart-beat:0,7500 which is incorrect. The grace period multiplier should NOT affect the broker's response. The broker should have responded with 5000. The client therefore honors the broker's inflated interval (per the STOMP spec) and sends a read check every 7500ms. The broker, meanwhile, applies the grace period multiplier, a second time, to its inflated read check interval. In this case, it now performs a read check every 11250ms (as shown in the DEBUG logging of the AbstractInactivityMonitor). With the client idle the broker's activemq.log contains TRACE log entries that read A receive is in progress every 11250ms. I presume this is the ReadCheckTimer handling the read check sent from the client? If so, the log output could be a little more descriptive. ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol - Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: Bug Affects Versions: 5.8.0 Reporter: Paul Gale Assignee: Timothy Bish Labels: easyfix Fix For: 5.9.0 Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. As the broker aggressively enforces the heart beat timeouts false failover attempts can result. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Commented] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
[ https://issues.apache.org/jira/browse/AMQ-4674?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13745438#comment-13745438 ] Paul Gale commented on AMQ-4674: I have no idea how to write unit tests for ActiveMQ and this section of code in particular. Unfortunately I could not find any unit tests for this feature which is surprising given that it was added just the other day. How was it tested? It's a tad galling to be asked for some tests now. I don't mind modifying existing tests though. However, my personal experience with the unit test codebase is that they're rather flaky; they almost never pass whenever I've tried to run them which doesn't exactly entice me into wanting to try now. Nonetheless, from a quick analysis of the code it would appear that the offending code is in activemq-stomp/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java at line 929: hbReadInterval = (long) (Long.parseLong(keepAliveOpts[0]) * hbGracePeriodMultiplier); // Wrong! should be: hbReadInterval = (long) Long.parseLong(keepAliveOpts[0]); // Honor the client's read interval where keepAliveOpts[0] is the client specified heartbeat read-interval. When the inactivity monitor's read check time is calculated it's done correctly: StompInactivityMonitor monitor = this.stompTransport.getInactivityMonitor(); monitor.setReadCheckTime((long) (hbReadInterval * hbGracePeriodMultiplier)); // Correct monitor.setInitialDelayTime(Math.min(hbReadInterval, hbWriteInterval)); monitor.setWriteCheckTime(hbWriteInterval); monitor.startMonitoring(); Setup:keepAliveOpts[0] = 5000, hbGracePeriodMultiplier = 1.5 Expected: hbReadInterval == 5000, monitor.getReadCheckTime() == 7500 Actual: hbReadInterval == 7500, monitor.getReadCheckTime() == 11250 ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol - Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: Bug Affects Versions: 5.8.0 Reporter: Paul Gale Assignee: Timothy Bish Labels: easyfix Fix For: 5.9.0 Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. As the broker aggressively enforces the heart beat timeouts false failover attempts can result. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Comment Edited] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
[ https://issues.apache.org/jira/browse/AMQ-4674?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13745438#comment-13745438 ] Paul Gale edited comment on AMQ-4674 at 8/20/13 9:21 PM: - I have no idea how to write unit tests for ActiveMQ and this section of code in particular. Unfortunately I could not find any unit tests for this feature which is surprising given that it was added just the other day. How was it tested? It's a tad galling to be asked for some tests now. I don't mind modifying existing tests though. However, my personal experience with the unit test codebase is that they're rather flaky; they almost never pass whenever I've tried to run them which doesn't exactly entice me into wanting to try now. Nonetheless, from a quick analysis of the code it would appear that the offending code is in activemq-stomp/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java at line 929: {code:java|borderStyle=solid} hbReadInterval = (long) (Long.parseLong(keepAliveOpts[0]) * hbGracePeriodMultiplier); // Wrong! {code} should be: {code:java|borderStyle=solid} hbReadInterval = (long) Long.parseLong(keepAliveOpts[0]); // Honor the client's read interval {code} where keepAliveOpts[0] is the client specified heartbeat read-interval. When the inactivity monitor's read check time is calculated it's done correctly: {code:java|borderStyle=solid} StompInactivityMonitor monitor = this.stompTransport.getInactivityMonitor(); monitor.setReadCheckTime((long) (hbReadInterval * hbGracePeriodMultiplier)); // Correct monitor.setInitialDelayTime(Math.min(hbReadInterval, hbWriteInterval)); monitor.setWriteCheckTime(hbWriteInterval); monitor.startMonitoring(); {code} Setup:keepAliveOpts[0] = 5000, hbGracePeriodMultiplier = 1.5 Expected: hbReadInterval == 5000, monitor.getReadCheckTime() == 7500 Actual: hbReadInterval == 7500, monitor.getReadCheckTime() == 11250 was (Author: paulgale): I have no idea how to write unit tests for ActiveMQ and this section of code in particular. Unfortunately I could not find any unit tests for this feature which is surprising given that it was added just the other day. How was it tested? It's a tad galling to be asked for some tests now. I don't mind modifying existing tests though. However, my personal experience with the unit test codebase is that they're rather flaky; they almost never pass whenever I've tried to run them which doesn't exactly entice me into wanting to try now. Nonetheless, from a quick analysis of the code it would appear that the offending code is in activemq-stomp/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java at line 929: hbReadInterval = (long) (Long.parseLong(keepAliveOpts[0]) * hbGracePeriodMultiplier); // Wrong! should be: hbReadInterval = (long) Long.parseLong(keepAliveOpts[0]); // Honor the client's read interval where keepAliveOpts[0] is the client specified heartbeat read-interval. When the inactivity monitor's read check time is calculated it's done correctly: StompInactivityMonitor monitor = this.stompTransport.getInactivityMonitor(); monitor.setReadCheckTime((long) (hbReadInterval * hbGracePeriodMultiplier)); // Correct monitor.setInitialDelayTime(Math.min(hbReadInterval, hbWriteInterval)); monitor.setWriteCheckTime(hbWriteInterval); monitor.startMonitoring(); Setup:keepAliveOpts[0] = 5000, hbGracePeriodMultiplier = 1.5 Expected: hbReadInterval == 5000, monitor.getReadCheckTime() == 7500 Actual: hbReadInterval == 7500, monitor.getReadCheckTime() == 11250 ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol - Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: Bug Affects Versions: 5.8.0 Reporter: Paul Gale Assignee: Timothy Bish Labels: easyfix Fix For: 5.9.0 Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. As the broker aggressively enforces the heart beat timeouts false failover attempts can result. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! -- This message is automatically generated by JIRA. If you
[jira] [Comment Edited] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
[ https://issues.apache.org/jira/browse/AMQ-4674?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13745438#comment-13745438 ] Paul Gale edited comment on AMQ-4674 at 8/20/13 9:22 PM: - I have no idea how to write unit tests for ActiveMQ and this section of code in particular. Unfortunately I could not find any unit tests for this feature which is surprising given that it was added just the other day. How was it tested? It's a tad galling to be asked for some tests now. I don't mind modifying existing tests though. However, my personal experience with the unit test codebase is that they're rather flaky; they almost never pass whenever I've tried to run them which doesn't exactly entice me into wanting to try now. Nonetheless, from a quick analysis of the code it would appear that the offending code is in activemq-stomp/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java at line 929: {code:java|borderStyle=solid} hbReadInterval = (long) (Long.parseLong(keepAliveOpts[0]) * hbGracePeriodMultiplier); // Wrong! {code} should be: {code:java|borderStyle=solid} hbReadInterval = (long) Long.parseLong(keepAliveOpts[0]); // Honor the client's read interval {code} where keepAliveOpts[0] is the client specified heartbeat read-interval. When the inactivity monitor's read check time is calculated it's done correctly: {code:java|borderStyle=solid} StompInactivityMonitor monitor = this.stompTransport.getInactivityMonitor(); monitor.setReadCheckTime((long) (hbReadInterval * hbGracePeriodMultiplier)); // Correct monitor.setInitialDelayTime(Math.min(hbReadInterval, hbWriteInterval)); monitor.setWriteCheckTime(hbWriteInterval); monitor.startMonitoring(); {code} Setup:keepAliveOpts[0] = 5000, hbGracePeriodMultiplier = 1.5 Expected: hbReadInterval == 5000, monitor.getReadCheckTime() == 7500 Actual: hbReadInterval == 7500, monitor.getReadCheckTime() == 11250 was (Author: paulgale): I have no idea how to write unit tests for ActiveMQ and this section of code in particular. Unfortunately I could not find any unit tests for this feature which is surprising given that it was added just the other day. How was it tested? It's a tad galling to be asked for some tests now. I don't mind modifying existing tests though. However, my personal experience with the unit test codebase is that they're rather flaky; they almost never pass whenever I've tried to run them which doesn't exactly entice me into wanting to try now. Nonetheless, from a quick analysis of the code it would appear that the offending code is in activemq-stomp/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java at line 929: {code:java|borderStyle=solid} hbReadInterval = (long) (Long.parseLong(keepAliveOpts[0]) * hbGracePeriodMultiplier); // Wrong! {code} should be: {code:java|borderStyle=solid} hbReadInterval = (long) Long.parseLong(keepAliveOpts[0]); // Honor the client's read interval {code} where keepAliveOpts[0] is the client specified heartbeat read-interval. When the inactivity monitor's read check time is calculated it's done correctly: {code:java|borderStyle=solid} StompInactivityMonitor monitor = this.stompTransport.getInactivityMonitor(); monitor.setReadCheckTime((long) (hbReadInterval * hbGracePeriodMultiplier)); // Correct monitor.setInitialDelayTime(Math.min(hbReadInterval, hbWriteInterval)); monitor.setWriteCheckTime(hbWriteInterval); monitor.startMonitoring(); {code} Setup:keepAliveOpts[0] = 5000, hbGracePeriodMultiplier = 1.5 Expected: hbReadInterval == 5000, monitor.getReadCheckTime() == 7500 Actual: hbReadInterval == 7500, monitor.getReadCheckTime() == 11250 ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol - Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: Bug Affects Versions: 5.8.0 Reporter: Paul Gale Assignee: Timothy Bish Labels: easyfix Fix For: 5.9.0 Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. As the broker aggressively enforces the heart beat timeouts false failover attempts can result. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could
[jira] [Comment Edited] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
[ https://issues.apache.org/jira/browse/AMQ-4674?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13745438#comment-13745438 ] Paul Gale edited comment on AMQ-4674 at 8/20/13 9:24 PM: - I have no idea how to write unit tests for ActiveMQ and this section of code in particular. Unfortunately I could not find any unit tests for this feature which is surprising given that it was added just the other day. How was it tested? It's a tad galling to be asked for some tests now. I don't mind modifying existing tests though. However, my personal experience with the unit test codebase is that they're rather flaky; they almost never pass whenever I've tried to run them which doesn't exactly entice me into wanting to try now. Nonetheless, from a quick analysis of the code it would appear that the offending code is in activemq-stomp/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java at line 929: \\ {code:java|borderStyle=solid} hbReadInterval = (long) (Long.parseLong(keepAliveOpts[0]) * hbGracePeriodMultiplier); // Wrong! {code} should be: \\ {code:java|borderStyle=solid} hbReadInterval = (long) Long.parseLong(keepAliveOpts[0]); // Honor the client's read interval {code} where keepAliveOpts[0] is the client specified heartbeat read-interval. When the inactivity monitor's read check time is calculated it's done correctly: \\ {code:java|borderStyle=solid} StompInactivityMonitor monitor = this.stompTransport.getInactivityMonitor(); monitor.setReadCheckTime((long) (hbReadInterval * hbGracePeriodMultiplier)); // Correct monitor.setInitialDelayTime(Math.min(hbReadInterval, hbWriteInterval)); monitor.setWriteCheckTime(hbWriteInterval); monitor.startMonitoring(); {code} {noformat} Setup:keepAliveOpts[0] = 5000, hbGracePeriodMultiplier = 1.5 Expected: hbReadInterval == 5000, monitor.getReadCheckTime() == 7500 Actual: hbReadInterval == 7500, monitor.getReadCheckTime() == 11250 {noformat} was (Author: paulgale): I have no idea how to write unit tests for ActiveMQ and this section of code in particular. Unfortunately I could not find any unit tests for this feature which is surprising given that it was added just the other day. How was it tested? It's a tad galling to be asked for some tests now. I don't mind modifying existing tests though. However, my personal experience with the unit test codebase is that they're rather flaky; they almost never pass whenever I've tried to run them which doesn't exactly entice me into wanting to try now. Nonetheless, from a quick analysis of the code it would appear that the offending code is in activemq-stomp/src/main/java/org/apache/activemq/transport/stomp/ProtocolConverter.java at line 929: {code:java|borderStyle=solid} hbReadInterval = (long) (Long.parseLong(keepAliveOpts[0]) * hbGracePeriodMultiplier); // Wrong! {code} should be: {code:java|borderStyle=solid} hbReadInterval = (long) Long.parseLong(keepAliveOpts[0]); // Honor the client's read interval {code} where keepAliveOpts[0] is the client specified heartbeat read-interval. When the inactivity monitor's read check time is calculated it's done correctly: {code:java|borderStyle=solid} StompInactivityMonitor monitor = this.stompTransport.getInactivityMonitor(); monitor.setReadCheckTime((long) (hbReadInterval * hbGracePeriodMultiplier)); // Correct monitor.setInitialDelayTime(Math.min(hbReadInterval, hbWriteInterval)); monitor.setWriteCheckTime(hbWriteInterval); monitor.startMonitoring(); {code} Setup:keepAliveOpts[0] = 5000, hbGracePeriodMultiplier = 1.5 Expected: hbReadInterval == 5000, monitor.getReadCheckTime() == 7500 Actual: hbReadInterval == 7500, monitor.getReadCheckTime() == 11250 ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol - Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: Bug Affects Versions: 5.8.0 Reporter: Paul Gale Assignee: Timothy Bish Labels: easyfix Fix For: 5.9.0 Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. As the broker aggressively enforces the heart beat timeouts false failover attempts can result. Apparently Apollo supports an error margin of 1.5x the configured
[jira] [Created] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
Paul Gale created AMQ-4674: -- Summary: ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: New Feature Affects Versions: 5.8.0 Reporter: Paul Gale Fix For: NEEDS_REVIEWED Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
[ https://issues.apache.org/jira/browse/AMQ-4674?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4674: --- Fix Version/s: (was: NEEDS_REVIEWED) 5.9.0 ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol - Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: Bug Affects Versions: 5.8.0 Reporter: Paul Gale Labels: easyfix Fix For: 5.9.0 Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
[ https://issues.apache.org/jira/browse/AMQ-4674?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4674: --- Issue Type: Bug (was: New Feature) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol - Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: Bug Affects Versions: 5.8.0 Reporter: Paul Gale Labels: easyfix Fix For: NEEDS_REVIEWED Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Updated] (AMQ-4674) ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol
[ https://issues.apache.org/jira/browse/AMQ-4674?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Paul Gale updated AMQ-4674: --- Description: Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. As the broker aggressively enforces the heart beat timeouts false failover attempts can result. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! was: Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! ActiveMQ 5.x does not support the notion of a grace-period for heart beats as supported by the STOMP protocol - Key: AMQ-4674 URL: https://issues.apache.org/jira/browse/AMQ-4674 Project: ActiveMQ Issue Type: Bug Affects Versions: 5.8.0 Reporter: Paul Gale Labels: easyfix Fix For: 5.9.0 Regarding the configuration of heart beating the STOMP protocol spec states: - because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin However, it appears that ActiveMQ 5.x is not tolerant of any error margin. Despite the fact that the spec says SHOULD rather than MUST it would make the implementation of STOMP clients easier if the error margin was published. As the broker aggressively enforces the heart beat timeouts false failover attempts can result. Apparently Apollo supports an error margin of 1.5x the configured heart beat. If it could be made configurable that would be even better! -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Commented] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13597342#comment-13597342 ] Paul Gale commented on AMQ-4365: So I've been able to get a first cut at a lease database locker that works with the KahaDBPersistenceAdapter, as shown below. This is by no means the ideal solution but it works. Feedback welcome. Longer term, the signature of the configure method should be changed; there is no reason that I can see why it should be coupled to a PersistenceAdapter - that's too broad. Either provide a few overloaded versions of configure() with various arguments that a locker might require or create an interface to be implemented by a persistence provider that makes the contract between the two more explicit. public class MyLeaseDatabaseLocker extends LeaseDatabaseLocker implements BrokerServiceAware, LockDataSourceCapable { private static final Logger LOG = LoggerFactory.getLogger(MyLeaseDatabaseLocker.class); protected BrokerService brokerService; @Override public void configure(PersistenceAdapter ignore) throws IOException { this.statements = new Statements(); } @Override public boolean keepAlive() throws IOException { boolean result = false; final String sql = statements.getLeaseUpdateStatement(); LOG.debug(getLeaseHolderId() + , lease keepAlive Query is + sql); Connection connection = null; PreparedStatement statement = null; try { connection = getConnection(); initTimeDiff(connection); statement = connection.prepareStatement(sql); setQueryTimeout(statement); final long now = System.currentTimeMillis() + diffFromCurrentTime; statement.setString(1, getLeaseHolderId()); statement.setLong(2, now + lockAcquireSleepInterval); statement.setString(3, getLeaseHolderId()); result = (statement.executeUpdate() == 1); } catch(Exception e) { LOG.warn(getLeaseHolderId() + , failed to update lease: + e, e); IOException ioe = IOExceptionSupport.create(e); brokerService.handleIOException(ioe); throw ioe; } finally { close(statement); close(connection); } return result; } @Override public void setBrokerService(BrokerService brokerService) { this.brokerService = brokerService; } @Override public String getLeaseHolderId() { if(leaseHolderId == null brokerService != null) { leaseHolderId = brokerService.getBrokerName(); } return leaseHolderId; } @Override public void setLockDataSource(DataSource lockDataSource) { this.dataSource = lockDataSource; } @Override public DataSource getLockDataSource() { return this.dataSource; } private void setQueryTimeout(PreparedStatement statement) throws SQLException { if(queryTimeout 0) { statement.setQueryTimeout(queryTimeout); } } private Connection getConnection() throws SQLException { return dataSource.getConnection(); } private void close(Connection connection) { if(null == connection) return; try { connection.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + caught exception while closing connection: + e1, e1); } } private void close(PreparedStatement statement) { if(null == statement) return; try { statement.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + , caught while closing statement: + e1, e1); } } } public interface LockDataSourceCapable { public void setLockDataSource(DataSource lockDataSource); public DataSource getLockDataSource(); } The activemq.xml (with parts removed) is as follows: beans xmlns=http://www.springframework.org/schema/beans; xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance; xsi:schemaLocation=http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd; broker xmlns=http://activemq.apache.org/schema/core; id=theBroker persistenceAdapter kahaDB directory=${activemq.data}/kahadb lockKeepAlivePeriod=2500 useLock=true locker bean xmlns=http://www.springframework.org/schema/beans; class=com.example.activemq.MyLeaseDatabaseLocker property name=lockDataSource ref=mysql-ds/ property name=brokerService ref=theBroker/ property name=failIfLocked value=false/ property name=lockAcquireSleepInterval value=5000/ /bean /locker /kahaDB /persistenceAdapter /broker bean id=mysql-ds class=org.apache.commons.dbcp.BasicDataSource destroy-method=close property
[jira] [Comment Edited] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13597342#comment-13597342 ] Paul Gale edited comment on AMQ-4365 at 3/8/13 6:03 PM: So I've been able to get a first cut at a lease database locker that works with the KahaDBPersistenceAdapter, as shown below. This is by no means the ideal solution but it works. Feedback welcome. Longer term, the signature of the configure method should be changed; there is no reason that I can see why it should be coupled to a PersistenceAdapter - that's too broad. Either provide a few overloaded versions of configure() with various arguments that a locker might require or create an interface to be implemented by a persistence provider that makes the contract between the two more explicit. {code:title=MyLeaseDatabaseLocker.java|borderStyle=solid} public class MyLeaseDatabaseLocker extends LeaseDatabaseLocker implements BrokerServiceAware, LockDataSourceCapable { private static final Logger LOG = LoggerFactory.getLogger(MyLeaseDatabaseLocker.class); protected BrokerService brokerService; @Override public void configure(PersistenceAdapter ignore) throws IOException { this.statements = new Statements(); } @Override public boolean keepAlive() throws IOException { boolean result = false; final String sql = statements.getLeaseUpdateStatement(); LOG.debug(getLeaseHolderId() + , lease keepAlive Query is + sql); Connection connection = null; PreparedStatement statement = null; try { connection = getConnection(); initTimeDiff(connection); statement = connection.prepareStatement(sql); setQueryTimeout(statement); final long now = System.currentTimeMillis() + diffFromCurrentTime; statement.setString(1, getLeaseHolderId()); statement.setLong(2, now + lockAcquireSleepInterval); statement.setString(3, getLeaseHolderId()); result = (statement.executeUpdate() == 1); } catch(Exception e) { LOG.warn(getLeaseHolderId() + , failed to update lease: + e, e); IOException ioe = IOExceptionSupport.create(e); brokerService.handleIOException(ioe); throw ioe; } finally { close(statement); close(connection); } return result; } @Override public void setBrokerService(BrokerService brokerService) { this.brokerService = brokerService; } @Override public String getLeaseHolderId() { if(leaseHolderId == null brokerService != null) { leaseHolderId = brokerService.getBrokerName(); } return leaseHolderId; } @Override public void setLockDataSource(DataSource lockDataSource) { this.dataSource = lockDataSource; } @Override public DataSource getLockDataSource() { return this.dataSource; } private void setQueryTimeout(PreparedStatement statement) throws SQLException { if(queryTimeout 0) { statement.setQueryTimeout(queryTimeout); } } private Connection getConnection() throws SQLException { return dataSource.getConnection(); } private void close(Connection connection) { if(null == connection) return; try { connection.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + caught exception while closing connection: + e1, e1); } } private void close(PreparedStatement statement) { if(null == statement) return; try { statement.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + , caught while closing statement: + e1, e1); } } } {code} {code:title=LockDataSourceCapable.java|borderStyle=solid} public interface LockDataSourceCapable { public void setLockDataSource(DataSource lockDataSource); public DataSource getLockDataSource(); } {code} The activemq.xml (with parts removed) is as follows: {code:xml} beans xmlns=http://www.springframework.org/schema/beans; xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance; xsi:schemaLocation=http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd; broker xmlns=http://activemq.apache.org/schema/core; id=theBroker persistenceAdapter kahaDB directory=${activemq.data}/kahadb lockKeepAlivePeriod=2500 useLock=true locker bean xmlns=http://www.springframework.org/schema/beans; class=com.example.activemq.MyLeaseDatabaseLocker property name=lockDataSource ref=mysql-ds/ property name=brokerService ref=theBroker/ property name=failIfLocked value=false/ property name=lockAcquireSleepInterval value=5000/
[jira] [Comment Edited] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13597342#comment-13597342 ] Paul Gale edited comment on AMQ-4365 at 3/8/13 6:07 PM: So I've been able to get a first cut at a lease database locker that works with the KahaDBPersistenceAdapter, as shown below. This is by no means the ideal solution but it works. Feedback welcome. Longer term, the signature of the configure method should be changed; there is no reason that I can see why it should be coupled to a PersistenceAdapter - that's too broad. Either provide a few overloaded versions of configure() with various arguments that a locker might require or create an interface to be implemented by a persistence provider that makes the contract between the two more explicit. {code:title=MyLeaseDatabaseLocker.java} public class MyLeaseDatabaseLocker extends LeaseDatabaseLocker implements BrokerServiceAware, LockDataSourceCapable { private static final Logger LOG = LoggerFactory.getLogger(MyLeaseDatabaseLocker.class); protected BrokerService brokerService; @Override public void configure(PersistenceAdapter ignore) throws IOException { this.statements = new Statements(); } @Override public boolean keepAlive() throws IOException { boolean result = false; final String sql = statements.getLeaseUpdateStatement(); LOG.debug(getLeaseHolderId() + , lease keepAlive Query is + sql); Connection connection = null; PreparedStatement statement = null; try { connection = getConnection(); initTimeDiff(connection); statement = connection.prepareStatement(sql); setQueryTimeout(statement); final long now = System.currentTimeMillis() + diffFromCurrentTime; statement.setString(1, getLeaseHolderId()); statement.setLong(2, now + lockAcquireSleepInterval); statement.setString(3, getLeaseHolderId()); result = (statement.executeUpdate() == 1); } catch(Exception e) { LOG.warn(getLeaseHolderId() + , failed to update lease: + e, e); IOException ioe = IOExceptionSupport.create(e); brokerService.handleIOException(ioe); throw ioe; } finally { close(statement); close(connection); } return result; } @Override public void setBrokerService(BrokerService brokerService) { this.brokerService = brokerService; } @Override public String getLeaseHolderId() { if(leaseHolderId == null brokerService != null) { leaseHolderId = brokerService.getBrokerName(); } return leaseHolderId; } @Override public void setLockDataSource(DataSource lockDataSource) { this.dataSource = lockDataSource; } @Override public DataSource getLockDataSource() { return this.dataSource; } private void setQueryTimeout(PreparedStatement statement) throws SQLException { if(queryTimeout 0) { statement.setQueryTimeout(queryTimeout); } } private Connection getConnection() throws SQLException { return dataSource.getConnection(); } private void close(Connection connection) { if(null == connection) return; try { connection.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + caught exception while closing connection: + e1, e1); } } private void close(PreparedStatement statement) { if(null == statement) return; try { statement.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + , caught while closing statement: + e1, e1); } } } {code} {code:title=LockDataSourceCapable.java} public interface LockDataSourceCapable { public void setLockDataSource(DataSource lockDataSource); public DataSource getLockDataSource(); } {code} {code:xml:title=activemq.xml (with parts removed)} beans xmlns=http://www.springframework.org/schema/beans; xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance; xsi:schemaLocation=http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd; broker xmlns=http://activemq.apache.org/schema/core; id=theBroker persistenceAdapter kahaDB directory=${activemq.data}/kahadb lockKeepAlivePeriod=2500 useLock=true locker bean xmlns=http://www.springframework.org/schema/beans; class=com.example.activemq.MyLeaseDatabaseLocker property name=lockDataSource ref=mysql-ds/ property name=brokerService ref=theBroker/ property name=failIfLocked value=false/ property name=lockAcquireSleepInterval value=5000/ /bean /locker /kahaDB
[jira] [Comment Edited] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13597342#comment-13597342 ] Paul Gale edited comment on AMQ-4365 at 3/8/13 6:10 PM: So I've been able to get a first cut at a lease database locker that works with the KahaDBPersistenceAdapter, as shown below. This is by no means the ideal solution but it works. Feedback welcome. Longer term, the signature of the configure method should be changed; there is no reason that I can see why it should be coupled to a PersistenceAdapter - that's too broad. Either provide a few overloaded versions of configure() with various arguments that a locker might require or create an interface to be implemented by a persistence provider that makes the contract between the two more explicit. \\ \\ {code:title=MyLeaseDatabaseLocker.java} public class MyLeaseDatabaseLocker extends LeaseDatabaseLocker implements BrokerServiceAware, LockDataSourceCapable { private static final Logger LOG = LoggerFactory.getLogger(MyLeaseDatabaseLocker.class); protected BrokerService brokerService; @Override public void configure(PersistenceAdapter ignore) throws IOException { this.statements = new Statements(); } @Override public boolean keepAlive() throws IOException { boolean result = false; final String sql = statements.getLeaseUpdateStatement(); LOG.debug(getLeaseHolderId() + , lease keepAlive Query is + sql); Connection connection = null; PreparedStatement statement = null; try { connection = getConnection(); initTimeDiff(connection); statement = connection.prepareStatement(sql); setQueryTimeout(statement); final long now = System.currentTimeMillis() + diffFromCurrentTime; statement.setString(1, getLeaseHolderId()); statement.setLong(2, now + lockAcquireSleepInterval); statement.setString(3, getLeaseHolderId()); result = (statement.executeUpdate() == 1); } catch(Exception e) { LOG.warn(getLeaseHolderId() + , failed to update lease: + e, e); IOException ioe = IOExceptionSupport.create(e); brokerService.handleIOException(ioe); throw ioe; } finally { close(statement); close(connection); } return result; } @Override public void setBrokerService(BrokerService brokerService) { this.brokerService = brokerService; } @Override public String getLeaseHolderId() { if(leaseHolderId == null brokerService != null) { leaseHolderId = brokerService.getBrokerName(); } return leaseHolderId; } @Override public void setLockDataSource(DataSource lockDataSource) { this.dataSource = lockDataSource; } @Override public DataSource getLockDataSource() { return this.dataSource; } private void setQueryTimeout(PreparedStatement statement) throws SQLException { if(queryTimeout 0) { statement.setQueryTimeout(queryTimeout); } } private Connection getConnection() throws SQLException { return dataSource.getConnection(); } private void close(Connection connection) { if(null == connection) return; try { connection.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + caught exception while closing connection: + e1, e1); } } private void close(PreparedStatement statement) { if(null == statement) return; try { statement.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + , caught while closing statement: + e1, e1); } } } {code} {code:title=LockDataSourceCapable.java} public interface LockDataSourceCapable { public void setLockDataSource(DataSource lockDataSource); public DataSource getLockDataSource(); } {code} {code:xml|title=activemq.xml (with parts removed)} beans xmlns=http://www.springframework.org/schema/beans; xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance; xsi:schemaLocation=http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd; broker xmlns=http://activemq.apache.org/schema/core; id=theBroker persistenceAdapter kahaDB directory=${activemq.data}/kahadb lockKeepAlivePeriod=2500 useLock=true locker bean xmlns=http://www.springframework.org/schema/beans; class=com.example.activemq.MyLeaseDatabaseLocker property name=lockDataSource ref=mysql-ds/ property name=brokerService ref=theBroker/ property name=failIfLocked value=false/ property name=lockAcquireSleepInterval value=5000/ /bean /locker /kahaDB
[jira] [Commented] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13597376#comment-13597376 ] Paul Gale commented on AMQ-4365: Another point worth noting is that the JDBCPersistenAdapter creates the lock table in the database during initialization. As I had previously used this adapter the tables were already in the database. Therefore testing my custom lease database locker went smoothly. However anyone that uses the above implementation as-is will get an error if the tables are not there. Ideally the locker, not the persistence adapter, should be responsible for managing the creation of its own lock table. I have not addressed this and probably won't. For now I can live with a SQL script to create the schema. Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock Key: AMQ-4365 URL: https://issues.apache.org/jira/browse/AMQ-4365 Project: ActiveMQ Issue Type: Improvement Affects Versions: 5.8.0 Reporter: Gary Tully Fix For: 5.9.0 The locker interface needs another configure option to provide a broker service, or needs to be brokerService aware so that a locker can get identity and access to the io exception handlers. The lease database locker is dependent on the jdbc pa to get statements and data source. It should be possible to configure these independently such that it can be used standalone as a broker lock. So setters for each. This will help sort out some of the dependencies between broker and lock implementations. also making it possible to use a lease lock with kahadb for example. some context: http://mail-archives.apache.org/mod_mbox/activemq-users/201303.mbox/%3ccaj5znhuruz+aewsaabajtwbbpkwn06ryyyt6nqsdg_su7vm...@mail.gmail.com%3E -- This message is automatically generated by JIRA. If you think it was sent incorrectly, please contact your JIRA administrators For more information on JIRA, see: http://www.atlassian.com/software/jira
[jira] [Comment Edited] (AMQ-4365) Allow the Lease Locker to be used with out a JDBCPersistenceAdapter - so it can be a broker lock
[ https://issues.apache.org/jira/browse/AMQ-4365?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanelfocusedCommentId=13597342#comment-13597342 ] Paul Gale edited comment on AMQ-4365 at 3/8/13 6:28 PM: So I've been able to get a first cut at a lease database locker that works with the KahaDBPersistenceAdapter, as shown below. This is by no means the ideal solution but it works. Feedback welcome. Longer term, the signature of the configure method should be changed; there is no reason that I can see why it should be coupled to a PersistenceAdapter - that's too broad. Either provide a few overloaded versions of configure() with various arguments that a locker might require or create an interface to be implemented by a persistence adapter that makes the contract between the two more explicit. \\ \\ {code:title=MyLeaseDatabaseLocker.java} public class MyLeaseDatabaseLocker extends LeaseDatabaseLocker implements BrokerServiceAware, LockDataSourceCapable { private static final Logger LOG = LoggerFactory.getLogger(MyLeaseDatabaseLocker.class); protected BrokerService brokerService; @Override public void configure(PersistenceAdapter ignore) throws IOException { this.statements = new Statements(); } @Override public boolean keepAlive() throws IOException { boolean result = false; final String sql = statements.getLeaseUpdateStatement(); LOG.debug(getLeaseHolderId() + , lease keepAlive Query is + sql); Connection connection = null; PreparedStatement statement = null; try { connection = getConnection(); initTimeDiff(connection); statement = connection.prepareStatement(sql); setQueryTimeout(statement); final long now = System.currentTimeMillis() + diffFromCurrentTime; statement.setString(1, getLeaseHolderId()); statement.setLong(2, now + lockAcquireSleepInterval); statement.setString(3, getLeaseHolderId()); result = (statement.executeUpdate() == 1); } catch(Exception e) { LOG.warn(getLeaseHolderId() + , failed to update lease: + e, e); IOException ioe = IOExceptionSupport.create(e); brokerService.handleIOException(ioe); throw ioe; } finally { close(statement); close(connection); } return result; } @Override public void setBrokerService(BrokerService brokerService) { this.brokerService = brokerService; } @Override public String getLeaseHolderId() { if(leaseHolderId == null brokerService != null) { leaseHolderId = brokerService.getBrokerName(); } return leaseHolderId; } @Override public void setLockDataSource(DataSource lockDataSource) { this.dataSource = lockDataSource; } @Override public DataSource getLockDataSource() { return this.dataSource; } private void setQueryTimeout(PreparedStatement statement) throws SQLException { if(queryTimeout 0) { statement.setQueryTimeout(queryTimeout); } } private Connection getConnection() throws SQLException { return dataSource.getConnection(); } private void close(Connection connection) { if(null == connection) return; try { connection.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + caught exception while closing connection: + e1, e1); } } private void close(PreparedStatement statement) { if(null == statement) return; try { statement.close(); } catch(SQLException e1) { LOG.debug(getLeaseHolderId() + , caught while closing statement: + e1, e1); } } } {code} {code:title=LockDataSourceCapable.java} public interface LockDataSourceCapable { public void setLockDataSource(DataSource lockDataSource); public DataSource getLockDataSource(); } {code} {code:xml|title=activemq.xml (with parts removed)} beans xmlns=http://www.springframework.org/schema/beans; xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance; xsi:schemaLocation=http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd; broker xmlns=http://activemq.apache.org/schema/core; id=theBroker persistenceAdapter kahaDB directory=${activemq.data}/kahadb lockKeepAlivePeriod=2500 useLock=true locker bean xmlns=http://www.springframework.org/schema/beans; class=com.example.activemq.MyLeaseDatabaseLocker property name=lockDataSource ref=mysql-ds/ property name=brokerService ref=theBroker/ property name=failIfLocked value=false/ property name=lockAcquireSleepInterval value=5000/ /bean /locker /kahaDB