summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKim van der Riet <kpvdr@apache.org>2012-08-27 15:40:33 +0000
committerKim van der Riet <kpvdr@apache.org>2012-08-27 15:40:33 +0000
commit868ce7469262d6fd2fe3f2e7f04cfe7af654d59f (patch)
tree63e6b5e62554609beb21e8c8d0610569f36d2743
parent2e5ff8f1b328831043e6d7e323249d62187234c6 (diff)
downloadqpid-python-868ce7469262d6fd2fe3f2e7f04cfe7af654d59f.tar.gz
QPID-3858: Updated code to include recent refactoring by Gordon (gsim) - see QPID-4178.
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/asyncstore@1377715 13f79535-47bb-0310-9956-ffa450edef68
-rwxr-xr-xbin/release.sh4
-rw-r--r--cpp/CMakeLists.txt1
-rw-r--r--cpp/configure.ac48
-rw-r--r--cpp/include/qpid/client/SubscriptionManager.h4
-rw-r--r--cpp/src/CMakeLists.txt59
-rw-r--r--cpp/src/Makefile.am33
-rw-r--r--cpp/src/asyncstore.cmake1
-rw-r--r--cpp/src/cluster.cmake175
-rw-r--r--cpp/src/cluster.mk115
-rw-r--r--cpp/src/qpid/acl/Acl.cpp7
-rw-r--r--cpp/src/qpid/acl/Acl.h2
-rw-r--r--cpp/src/qpid/acl/AclConnectionCounter.cpp41
-rw-r--r--cpp/src/qpid/acl/AclConnectionCounter.h1
-rw-r--r--cpp/src/qpid/acl/AclData.cpp183
-rw-r--r--cpp/src/qpid/acl/AclData.h15
-rw-r--r--cpp/src/qpid/acl/AclReader.cpp9
-rw-r--r--cpp/src/qpid/asyncStore/PersistableMessageContext.cpp39
-rw-r--r--cpp/src/qpid/asyncStore/PersistableMessageContext.h32
-rw-r--r--cpp/src/qpid/broker/AclModule.h8
-rw-r--r--cpp/src/qpid/broker/AsyncCompletion.h3
-rw-r--r--cpp/src/qpid/broker/Broker.cpp44
-rw-r--r--cpp/src/qpid/broker/Broker.h15
-rw-r--r--cpp/src/qpid/broker/Connection.cpp8
-rw-r--r--cpp/src/qpid/broker/Consumer.h29
-rw-r--r--cpp/src/qpid/broker/Deliverable.h11
-rw-r--r--cpp/src/qpid/broker/DeliverableMessage.cpp12
-rw-r--r--cpp/src/qpid/broker/DeliverableMessage.h11
-rw-r--r--cpp/src/qpid/broker/DeliveryAdapter.h53
-rw-r--r--cpp/src/qpid/broker/DeliveryRecord.cpp90
-rw-r--r--cpp/src/qpid/broker/DeliveryRecord.h16
-rw-r--r--cpp/src/qpid/broker/DtxAck.h1
-rw-r--r--cpp/src/qpid/broker/Exchange.cpp21
-rw-r--r--cpp/src/qpid/broker/Exchange.h5
-rw-r--r--cpp/src/qpid/broker/ExpiryPolicy.cpp2
-rw-r--r--cpp/src/qpid/broker/ExpiryPolicy.h2
-rw-r--r--cpp/src/qpid/broker/Fairshare.cpp94
-rw-r--r--cpp/src/qpid/broker/Fairshare.h11
-rw-r--r--cpp/src/qpid/broker/FifoDistributor.cpp21
-rw-r--r--cpp/src/qpid/broker/FifoDistributor.h10
-rw-r--r--cpp/src/qpid/broker/HeadersExchange.cpp130
-rw-r--r--cpp/src/qpid/broker/HeadersExchange.h3
-rw-r--r--cpp/src/qpid/broker/IndexedDeque.h226
-rw-r--r--cpp/src/qpid/broker/LegacyLVQ.cpp127
-rw-r--r--cpp/src/qpid/broker/LegacyLVQ.h60
-rw-r--r--cpp/src/qpid/broker/Link.cpp4
-rw-r--r--cpp/src/qpid/broker/LinkRegistry.cpp14
-rw-r--r--cpp/src/qpid/broker/LinkRegistry.h1
-rw-r--r--cpp/src/qpid/broker/LossyQueue.cpp86
-rw-r--r--cpp/src/qpid/broker/LossyQueue.h (renamed from cpp/src/qpid/cluster/Quorum_null.h)33
-rw-r--r--cpp/src/qpid/broker/Lvq.cpp64
-rw-r--r--cpp/src/qpid/broker/Lvq.h (renamed from cpp/src/qpid/cluster/ExpiryPolicy.h)44
-rw-r--r--cpp/src/qpid/broker/MapHandler.h57
-rw-r--r--cpp/src/qpid/broker/Message.cpp542
-rw-r--r--cpp/src/qpid/broker/Message.h229
-rw-r--r--cpp/src/qpid/broker/MessageBuilder.cpp19
-rw-r--r--cpp/src/qpid/broker/MessageBuilder.h13
-rw-r--r--cpp/src/qpid/broker/MessageDeque.cpp207
-rw-r--r--cpp/src/qpid/broker/MessageDeque.h32
-rw-r--r--cpp/src/qpid/broker/MessageDistributor.h35
-rw-r--r--cpp/src/qpid/broker/MessageGroupManager.cpp176
-rw-r--r--cpp/src/qpid/broker/MessageGroupManager.h28
-rw-r--r--cpp/src/qpid/broker/MessageMap.cpp146
-rw-r--r--cpp/src/qpid/broker/MessageMap.h30
-rw-r--r--cpp/src/qpid/broker/Messages.h79
-rw-r--r--cpp/src/qpid/broker/Persistable.h2
-rw-r--r--cpp/src/qpid/broker/PersistableMessage.cpp171
-rw-r--r--cpp/src/qpid/broker/PersistableMessage.h97
-rw-r--r--cpp/src/qpid/broker/PriorityQueue.cpp256
-rw-r--r--cpp/src/qpid/broker/PriorityQueue.h72
-rw-r--r--cpp/src/qpid/broker/Queue.cpp1293
-rw-r--r--cpp/src/qpid/broker/Queue.h170
-rw-r--r--cpp/src/qpid/broker/QueueAsyncContext.cpp6
-rw-r--r--cpp/src/qpid/broker/QueueAsyncContext.h12
-rw-r--r--cpp/src/qpid/broker/QueueCursor.cpp (renamed from cpp/src/qpid/cluster/ExpiryPolicy.cpp)33
-rw-r--r--cpp/src/qpid/broker/QueueCursor.h (renamed from cpp/src/qpid/cluster/SecureConnectionFactory.h)67
-rw-r--r--cpp/src/qpid/broker/QueueDepth.cpp127
-rw-r--r--cpp/src/qpid/broker/QueueDepth.h74
-rw-r--r--cpp/src/qpid/broker/QueueEvents.cpp151
-rw-r--r--cpp/src/qpid/broker/QueueEvents.h85
-rw-r--r--cpp/src/qpid/broker/QueueFactory.cpp114
-rw-r--r--cpp/src/qpid/broker/QueueFactory.h73
-rw-r--r--cpp/src/qpid/broker/QueueFlowLimit.cpp103
-rw-r--r--cpp/src/qpid/broker/QueueFlowLimit.h22
-rw-r--r--cpp/src/qpid/broker/QueueObserver.h10
-rw-r--r--cpp/src/qpid/broker/QueuePolicy.cpp364
-rw-r--r--cpp/src/qpid/broker/QueuePolicy.h126
-rw-r--r--cpp/src/qpid/broker/QueueRegistry.cpp65
-rw-r--r--cpp/src/qpid/broker/QueueRegistry.h31
-rw-r--r--cpp/src/qpid/broker/QueueSettings.cpp228
-rw-r--r--cpp/src/qpid/broker/QueueSettings.h92
-rw-r--r--cpp/src/qpid/broker/QueuedMessage.h21
-rw-r--r--cpp/src/qpid/broker/RecoveredDequeue.cpp7
-rw-r--r--cpp/src/qpid/broker/RecoveredDequeue.h9
-rw-r--r--cpp/src/qpid/broker/RecoveredEnqueue.cpp5
-rw-r--r--cpp/src/qpid/broker/RecoveredEnqueue.h10
-rw-r--r--cpp/src/qpid/broker/RecoveryManagerImpl.cpp28
-rw-r--r--cpp/src/qpid/broker/SemanticState.cpp130
-rw-r--r--cpp/src/qpid/broker/SemanticState.h50
-rw-r--r--cpp/src/qpid/broker/SessionAdapter.cpp15
-rw-r--r--cpp/src/qpid/broker/SessionHandler.cpp6
-rw-r--r--cpp/src/qpid/broker/SessionHandler.h2
-rw-r--r--cpp/src/qpid/broker/SessionState.cpp41
-rw-r--r--cpp/src/qpid/broker/SessionState.h43
-rw-r--r--cpp/src/qpid/broker/SimpleMessage.cpp29
-rw-r--r--cpp/src/qpid/broker/SimpleMessage.h44
-rw-r--r--cpp/src/qpid/broker/SimpleQueue.cpp8
-rw-r--r--cpp/src/qpid/broker/SimpleQueuedMessage.cpp2
-rw-r--r--cpp/src/qpid/broker/ThresholdAlerts.cpp87
-rw-r--r--cpp/src/qpid/broker/ThresholdAlerts.h16
-rw-r--r--cpp/src/qpid/broker/TxAccept.h1
-rw-r--r--cpp/src/qpid/broker/TxBuffer.cpp6
-rw-r--r--cpp/src/qpid/broker/TxBuffer.h3
-rw-r--r--cpp/src/qpid/broker/TxOp.h3
-rw-r--r--cpp/src/qpid/broker/TxOpVisitor.h97
-rw-r--r--cpp/src/qpid/broker/TxPublish.cpp111
-rw-r--r--cpp/src/qpid/broker/TxPublish.h92
-rw-r--r--cpp/src/qpid/broker/amqp_0_10/MessageTransfer.cpp373
-rw-r--r--cpp/src/qpid/broker/amqp_0_10/MessageTransfer.h133
-rw-r--r--cpp/src/qpid/broker/windows/SslProtocolFactory.cpp2
-rw-r--r--cpp/src/qpid/client/SslConnector.cpp224
-rw-r--r--cpp/src/qpid/client/SubscriptionManagerImpl.cpp10
-rw-r--r--cpp/src/qpid/client/TCPConnector.cpp23
-rw-r--r--cpp/src/qpid/client/TCPConnector.h1
-rw-r--r--cpp/src/qpid/cluster/Cluster.cpp1294
-rw-r--r--cpp/src/qpid/cluster/Cluster.h332
-rw-r--r--cpp/src/qpid/cluster/ClusterMap.cpp178
-rw-r--r--cpp/src/qpid/cluster/ClusterMap.h106
-rw-r--r--cpp/src/qpid/cluster/ClusterPlugin.cpp124
-rw-r--r--cpp/src/qpid/cluster/ClusterSettings.h51
-rw-r--r--cpp/src/qpid/cluster/ClusterTimer.cpp144
-rw-r--r--cpp/src/qpid/cluster/ClusterTimer.h64
-rw-r--r--cpp/src/qpid/cluster/Connection.cpp878
-rw-r--r--cpp/src/qpid/cluster/Connection.h302
-rw-r--r--cpp/src/qpid/cluster/ConnectionCodec.cpp86
-rw-r--r--cpp/src/qpid/cluster/ConnectionCodec.h82
-rw-r--r--cpp/src/qpid/cluster/Cpg.cpp280
-rw-r--r--cpp/src/qpid/cluster/Cpg.h236
-rw-r--r--cpp/src/qpid/cluster/CredentialsExchange.cpp95
-rw-r--r--cpp/src/qpid/cluster/CredentialsExchange.h72
-rw-r--r--cpp/src/qpid/cluster/Decoder.cpp65
-rw-r--r--cpp/src/qpid/cluster/Decoder.h59
-rw-r--r--cpp/src/qpid/cluster/Dispatchable.h52
-rw-r--r--cpp/src/qpid/cluster/ErrorCheck.cpp155
-rw-r--r--cpp/src/qpid/cluster/ErrorCheck.h90
-rw-r--r--cpp/src/qpid/cluster/Event.cpp134
-rw-r--r--cpp/src/qpid/cluster/Event.h116
-rw-r--r--cpp/src/qpid/cluster/EventFrame.cpp41
-rw-r--r--cpp/src/qpid/cluster/EventFrame.h60
-rw-r--r--cpp/src/qpid/cluster/FailoverExchange.cpp109
-rw-r--r--cpp/src/qpid/cluster/FailoverExchange.h73
-rw-r--r--cpp/src/qpid/cluster/InitialStatusMap.cpp238
-rw-r--r--cpp/src/qpid/cluster/InitialStatusMap.h95
-rw-r--r--cpp/src/qpid/cluster/LockedConnectionMap.h65
-rw-r--r--cpp/src/qpid/cluster/McastFrameHandler.h46
-rw-r--r--cpp/src/qpid/cluster/MemberSet.cpp60
-rw-r--r--cpp/src/qpid/cluster/MemberSet.h45
-rw-r--r--cpp/src/qpid/cluster/Multicaster.cpp105
-rw-r--r--cpp/src/qpid/cluster/Multicaster.h92
-rw-r--r--cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h47
-rw-r--r--cpp/src/qpid/cluster/Numbering.h68
-rw-r--r--cpp/src/qpid/cluster/OutputInterceptor.cpp125
-rw-r--r--cpp/src/qpid/cluster/OutputInterceptor.h79
-rw-r--r--cpp/src/qpid/cluster/PollableQueue.h89
-rw-r--r--cpp/src/qpid/cluster/PollerDispatch.cpp69
-rw-r--r--cpp/src/qpid/cluster/PollerDispatch.h60
-rw-r--r--cpp/src/qpid/cluster/ProxyInputHandler.h56
-rw-r--r--cpp/src/qpid/cluster/Quorum.h32
-rw-r--r--cpp/src/qpid/cluster/Quorum_cman.cpp105
-rw-r--r--cpp/src/qpid/cluster/Quorum_cman.h65
-rw-r--r--cpp/src/qpid/cluster/RetractClient.cpp62
-rw-r--r--cpp/src/qpid/cluster/RetractClient.h50
-rw-r--r--cpp/src/qpid/cluster/SecureConnectionFactory.cpp73
-rw-r--r--cpp/src/qpid/cluster/StoreStatus.cpp170
-rw-r--r--cpp/src/qpid/cluster/StoreStatus.h68
-rw-r--r--cpp/src/qpid/cluster/UpdateClient.cpp736
-rw-r--r--cpp/src/qpid/cluster/UpdateClient.h142
-rw-r--r--cpp/src/qpid/cluster/UpdateDataExchange.cpp77
-rw-r--r--cpp/src/qpid/cluster/UpdateDataExchange.h83
-rw-r--r--cpp/src/qpid/cluster/UpdateExchange.cpp68
-rw-r--r--cpp/src/qpid/cluster/UpdateExchange.h45
-rw-r--r--cpp/src/qpid/cluster/UpdateReceiver.h59
-rw-r--r--cpp/src/qpid/cluster/WatchDogPlugin.cpp139
-rw-r--r--cpp/src/qpid/cluster/management-schema.xml61
-rw-r--r--cpp/src/qpid/cluster/qpidd_watchdog.cpp63
-rw-r--r--cpp/src/qpid/cluster/types.h107
-rw-r--r--cpp/src/qpid/ha/Backup.cpp33
-rw-r--r--cpp/src/qpid/ha/Backup.h2
-rw-r--r--cpp/src/qpid/ha/BackupConnectionExcluder.h2
-rw-r--r--cpp/src/qpid/ha/BrokerReplicator.cpp84
-rw-r--r--cpp/src/qpid/ha/ConnectionObserver.cpp22
-rw-r--r--cpp/src/qpid/ha/ConnectionObserver.h4
-rw-r--r--cpp/src/qpid/ha/HaBroker.cpp14
-rw-r--r--cpp/src/qpid/ha/HaBroker.h2
-rw-r--r--cpp/src/qpid/ha/Membership.cpp2
-rw-r--r--cpp/src/qpid/ha/Membership.h2
-rw-r--r--cpp/src/qpid/ha/Primary.cpp16
-rw-r--r--cpp/src/qpid/ha/QueueGuard.cpp85
-rw-r--r--cpp/src/qpid/ha/QueueGuard.h11
-rw-r--r--cpp/src/qpid/ha/QueueReplicator.cpp11
-rw-r--r--cpp/src/qpid/ha/RemoteBackup.cpp3
-rw-r--r--cpp/src/qpid/ha/ReplicatingSubscription.cpp124
-rw-r--r--cpp/src/qpid/ha/ReplicatingSubscription.h8
-rw-r--r--cpp/src/qpid/ha/ReplicationTest.cpp2
-rw-r--r--cpp/src/qpid/management/ManagementAgent.cpp68
-rw-r--r--cpp/src/qpid/management/ManagementDirectExchange.cpp4
-rw-r--r--cpp/src/qpid/management/ManagementTopicExchange.cpp4
-rw-r--r--cpp/src/qpid/replication/ReplicatingEventListener.cpp200
-rw-r--r--cpp/src/qpid/replication/ReplicatingEventListener.h78
-rw-r--r--cpp/src/qpid/replication/ReplicationExchange.cpp240
-rw-r--r--cpp/src/qpid/replication/ReplicationExchange.h72
-rw-r--r--cpp/src/qpid/replication/constants.h34
-rw-r--r--cpp/src/qpid/store/MessageStorePlugin.cpp2
-rw-r--r--cpp/src/qpid/sys/AsynchIO.h16
-rw-r--r--cpp/src/qpid/sys/AsynchIOHandler.cpp44
-rw-r--r--cpp/src/qpid/sys/AsynchIOHandler.h2
-rw-r--r--cpp/src/qpid/sys/SslPlugin.cpp4
-rw-r--r--cpp/src/qpid/sys/TCPIOPlugin.cpp2
-rw-r--r--cpp/src/qpid/sys/epoll/EpollPoller.cpp8
-rw-r--r--cpp/src/qpid/sys/posix/AsynchIO.cpp25
-rwxr-xr-xcpp/src/qpid/sys/posix/SystemInfo.cpp2
-rw-r--r--cpp/src/qpid/sys/ssl/SslHandler.cpp27
-rw-r--r--cpp/src/qpid/sys/ssl/SslHandler.h2
-rw-r--r--cpp/src/qpid/sys/ssl/SslIo.cpp21
-rw-r--r--cpp/src/qpid/sys/ssl/SslIo.h26
-rw-r--r--cpp/src/qpid/sys/windows/AsynchIO.cpp25
-rw-r--r--cpp/src/qpid/sys/windows/SslAsynchIO.cpp14
-rw-r--r--cpp/src/qpid/sys/windows/SslAsynchIO.h1
-rw-r--r--cpp/src/qpid/sys/windows/Time.cpp74
-rw-r--r--cpp/src/qpid/xml/XmlExchange.cpp77
-rw-r--r--cpp/src/qpid/xml/XmlExchange.h2
-rw-r--r--cpp/src/replication.mk52
-rw-r--r--cpp/src/tests/CMakeLists.txt9
-rw-r--r--cpp/src/tests/ClientSessionTest.cpp2
-rw-r--r--cpp/src/tests/DeliveryRecordTest.cpp2
-rw-r--r--cpp/src/tests/ExchangeTest.cpp80
-rw-r--r--cpp/src/tests/Makefile.am15
-rw-r--r--cpp/src/tests/MessageBuilderTest.cpp190
-rw-r--r--cpp/src/tests/MessageTest.cpp59
-rw-r--r--cpp/src/tests/MessageUtils.h61
-rw-r--r--cpp/src/tests/QueueDepth.cpp105
-rw-r--r--cpp/src/tests/QueueEvents.cpp238
-rw-r--r--cpp/src/tests/QueueFlowLimitTest.cpp38
-rw-r--r--cpp/src/tests/QueuePolicyTest.cpp135
-rw-r--r--cpp/src/tests/QueueRegistryTest.cpp23
-rw-r--r--cpp/src/tests/QueueTest.cpp1267
-rw-r--r--cpp/src/tests/ReplicationTest.cpp144
-rw-r--r--cpp/src/tests/TxMocks.h2
-rw-r--r--cpp/src/tests/TxPublishTest.cpp98
-rwxr-xr-xcpp/src/tests/acl.py541
-rw-r--r--cpp/src/tests/cluster.cmake90
-rw-r--r--cpp/src/tests/cluster.mk102
-rwxr-xr-xcpp/src/tests/ha_tests.py18
-rw-r--r--cpp/src/tests/sasl.mk27
-rw-r--r--cpp/src/tests/storePerftools/asyncPerf/MessageProducer.cpp6
-rw-r--r--cpp/src/tests/test_store.cpp3
-rw-r--r--doc/book/src/cpp-broker/.gitignore19
-rw-r--r--doc/book/src/java-broker/HA-Guide.xml34
-rw-r--r--doc/book/src/java-broker/images/HA-2N-Key.svg20
-rw-r--r--doc/book/src/java-broker/images/HA-2N-MasterFail.svg20
-rw-r--r--doc/book/src/java-broker/images/HA-2N-NetworkPartition.svg20
-rw-r--r--doc/book/src/java-broker/images/HA-2N-Normal.svg20
-rw-r--r--doc/book/src/java-broker/images/HA-2N-ReplicaFail.svg20
-rw-r--r--doc/book/src/java-broker/images/HA-2N-SplitBrain.svg20
-rw-r--r--doc/book/src/programming/Programming-In-Apache-Qpid-Book.xml4
-rw-r--r--extras/qmf/src/py/qmf/console.py2
-rw-r--r--java/.gitignore18
-rw-r--r--java/amqp-1-0-client-jms/README.txt12
-rw-r--r--java/amqp-1-0-client-jms/build.xml11
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverter.java132
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java143
-rw-r--r--java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java2
-rw-r--r--java/broker-plugins/management-http/src/main/java/resources/showBroker.html20
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java20
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java20
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverterTest.java141
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java20
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java20
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java20
-rw-r--r--java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java20
-rw-r--r--java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java131
-rw-r--r--java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogActorTest.java170
-rw-r--r--java/broker/etc/broker_example.acl25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java50
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/model/Model.java62
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java72
-rw-r--r--java/build.deps2
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java11
-rw-r--r--java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java6
-rw-r--r--java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java24
-rw-r--r--java/client/test/bin/IBM-JNDI-Setup.bat69
-rwxr-xr-xjava/client/test/bin/IBM-JNDI-Setup.sh27
-rw-r--r--java/client/test/bin/IBM-Publisher.bat62
-rwxr-xr-xjava/client/test/bin/IBM-Publisher.sh22
-rw-r--r--java/client/test/bin/IBM-PutGet.bat62
-rwxr-xr-xjava/client/test/bin/IBM-PutGet.sh21
-rw-r--r--java/client/test/bin/IBM-README.txt19
-rw-r--r--java/client/test/bin/IBM-Receiver.bat62
-rwxr-xr-xjava/client/test/bin/IBM-Receiver.sh22
-rw-r--r--java/client/test/bin/IBM-Sender.bat62
-rwxr-xr-xjava/client/test/bin/IBM-Sender.sh22
-rw-r--r--java/client/test/bin/IBM-Subscriber.bat62
-rwxr-xr-xjava/client/test/bin/IBM-Subscriber.sh22
-rwxr-xr-xjava/client/test/bin/headersListener.sh22
-rwxr-xr-xjava/client/test/bin/headersListenerGroup.sh25
-rwxr-xr-xjava/client/test/bin/headersPublisher.sh22
-rwxr-xr-xjava/client/test/bin/run_many.sh30
-rwxr-xr-xjava/client/test/bin/serviceProvidingClient.sh24
-rwxr-xr-xjava/client/test/bin/serviceRequestingClient.sh27
-rwxr-xr-xjava/client/test/bin/testService.sh22
-rwxr-xr-xjava/client/test/bin/topicListener.sh23
-rwxr-xr-xjava/client/test/bin/topicPublisher.sh22
-rw-r--r--java/client/test/etc/ApacheDS.properties24
-rw-r--r--java/client/test/example_build.xml104
-rw-r--r--java/common.xml3
-rw-r--r--java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/configuration/CommonProperties.java (renamed from java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java)20
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Connection.java26
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java22
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java7
-rw-r--r--java/ivy.retrieve.xml2
-rw-r--r--java/ivysettings.retrieve.xml1
-rw-r--r--java/lib/poms/je-5.0.58.xml (renamed from java/lib/poms/je-5.0.55.xml)2
-rw-r--r--java/perftests/etc/chartdefs/1021-AcknowledgementModes-Persistent.chartdef (renamed from java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transacted.chartdef)11
-rw-r--r--java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transient.chartdef (renamed from java/perftests/etc/chartdefs/1021-AcknowledgementModes-AutoAck.chartdef)9
-rw-r--r--java/perftests/etc/testdefs/Topic-AckModes.js21
-rw-r--r--java/perftests/etc/testdefs/Topic-NumberOfConsumers.js21
-rw-r--r--java/perftests/etc/testdefs/Topic-NumberOfTopics.js21
-rw-r--r--java/perftests/etc/testdefs/Topic-Persistence.js20
-rw-r--r--java/perftests/example/perftests.js21
-rw-r--r--java/perftests/src/main/java/test-utils.js20
-rw-r--r--java/perftests/visualisation-jfc/src/main/java/org/apache/qpid/disttest/charting/writer/ChartWriter.java9
-rwxr-xr-x[-rw-r--r--]java/perftests/visualisation-jfc/src/test/java/org/apache/qpid/disttest/charting/writer/expected-chart-summary.html6
-rw-r--r--java/systests/etc/log.properties19
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java277
-rw-r--r--java/test-profiles/python_tests/Java010PythonExcludes1
-rw-r--r--python/qpid/util.py2
-rw-r--r--tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py4
-rw-r--r--tests/src/py/qpid_tests/broker_0_10/management.py4
-rw-r--r--tests/src/py/qpid_tests/broker_0_10/msg_groups.py2
-rw-r--r--tests/src/py/qpid_tests/broker_0_10/new_api.py4
-rw-r--r--tests/src/py/qpid_tests/broker_0_10/priority.py35
-rw-r--r--tests/src/py/qpid_tests/broker_0_10/threshold.py2
342 files changed, 6926 insertions, 18616 deletions
diff --git a/bin/release.sh b/bin/release.sh
index a2a187b4bc..ecd00f4f18 100755
--- a/bin/release.sh
+++ b/bin/release.sh
@@ -218,8 +218,12 @@ if [ "JAVA" == "$JAVA" ] ; then
cp qpid-${VER}/java/broker/release/*.tar.gz artifacts/qpid-java-broker-${VER}.tar.gz
cp qpid-${VER}/java/client/release/*.tar.gz artifacts/qpid-java-client-${VER}.tar.gz
+ cp qpid-${VER}/java/amqp-1-0-client-jms/release/*.tar.gz artifacts/qpid-java-amqp-1-0-client-jms-${VER}.tar.gz
# copy the Maven artifacts
+ cp -a qpid-${VER}/java/amqp-1-0-client/release/maven artifacts/
+ cp -a qpid-${VER}/java/amqp-1-0-client-jms/release/maven artifacts/
+ cp -a qpid-${VER}/java/amqp-1-0-common/release/maven artifacts/
cp -a qpid-${VER}/java/client/release/maven artifacts/
cp -a qpid-${VER}/java/common/release/maven artifacts/
cp -a qpid-${VER}/java/broker/release/maven artifacts/
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 4c83540909..ada8f165ee 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -60,7 +60,6 @@ set (QPIDD_CONF_FILE ${QPID_INSTALL_CONFDIR}/qpidd.conf CACHE STRING
"Name of the Qpid broker configuration file")
install(FILES LICENSE NOTICE DESTINATION ${CMAKE_INSTALL_PREFIX})
-install(FILES xml/cluster.xml DESTINATION ${QPID_INSTALL_DATADIR})
if (WIN32)
set (CMAKE_DEBUG_POSTFIX "d")
diff --git a/cpp/configure.ac b/cpp/configure.ac
index c68fed932e..c4e55f90de 100644
--- a/cpp/configure.ac
+++ b/cpp/configure.ac
@@ -256,54 +256,6 @@ AC_SUBST(DOWNLOAD_URL)
AC_CHECK_HEADERS([boost/shared_ptr.hpp uuid/uuid.h],,
AC_MSG_ERROR([Missing required header files.]))
-# Check for optional cluster requirements.
-tmp_LIBS=$LIBS
-tmp_LDFLAGS=$LDFLAGS
-LDFLAGS="$LDFLAGS -L/usr/lib/openais -L/usr/lib64/openais -L/usr/lib/corosync -L/usr/lib64/corosync"
-AC_CHECK_LIB([cpg],[cpg_local_get],[have_libcpg=yes],)
-AC_CHECK_HEADERS([openais/cpg.h corosync/cpg.h],[have_cpg_h=yes],)
-AC_ARG_WITH([cpg],
- [AS_HELP_STRING([--with-cpg], [Build with CPG support for clustering.])],
- [case "${withval}" in
- yes) # yes - require dependencies
- test x$have_libcpg = xyes || AC_MSG_ERROR([libcpg not found, install openais-devel or corosync-devel])
- test x$have_cpg_h = xyes || AC_MSG_ERROR([cpg.h not found, install openais-devel or corosync-devel])
- with_cpg=yes
- ;;
- no) with_cpg=no ;;
- *) AC_MSG_ERROR([Bad value ${withval} for --with-cpg option]) ;;
- esac],
- [ # not specified - use if present
- test x$have_libcpg = xyes -a x$have_cpg_h = xyes && with_cpg=yes
- ]
-)
-AM_CONDITIONAL([HAVE_LIBCPG], [test x$with_cpg = xyes])
-AC_SUBST(USE_CPG, [$with_cpg])
-
-# Clean up unnceccassary flags if we don't use clustering
-AS_IF([test ! x$with_cpg = xyes], [LDFLAGS=$tmp_LDFLAGS])
-
-AC_CHECK_LIB([cman],[cman_is_quorate],have_libcman=yes,)
-AC_CHECK_HEADERS([libcman.h],have_libcman_h=yes,)
-AC_ARG_WITH([libcman],
- [AS_HELP_STRING([--with-libcman], [Integration with libcman quorum service.])],
- [case "${withval}" in
- yes) # yes - require dependencies
- test x$have_libcman = xyes || AC_MSG_ERROR([libcman not found, install cman-devel or cmanlib-devel])
- test x$have_libcman_h = xyes || AC_MSG_ERROR([libcman.h not found, install cman-devel or cmanlib-devel])
- with_libcman=yes
- ;;
- no) with_libcman=no ;;
- *) AC_MSG_ERROR([Bad value ${withval} for --with-libcman option]) ;;
- esac],
- [ # not specified - use if present and we're using with_cpg
- test x$have_libcman = xyes -a x$have_libcman_h = xyes -a x$with_cpg = xyes && with_libcman=yes
- ]
-)
-AM_CONDITIONAL([HAVE_LIBCMAN], [test x$with_libcman = xyes])
-
-LIBS=$tmp_LIBS
-
# Setup --with-sasl/--without-sasl as arguments to configure
AC_ARG_WITH([sasl],
[AS_HELP_STRING([--with-sasl], [Build with SASL authentication support])],
diff --git a/cpp/include/qpid/client/SubscriptionManager.h b/cpp/include/qpid/client/SubscriptionManager.h
index b69819a8ff..404a9c6eb9 100644
--- a/cpp/include/qpid/client/SubscriptionManager.h
+++ b/cpp/include/qpid/client/SubscriptionManager.h
@@ -280,8 +280,8 @@ class QPID_CLIENT_CLASS_EXTERN SubscriptionManager : public sys::Runnable, publi
/** AutoCancel cancels a subscription in its destructor */
class AutoCancel {
public:
- AutoCancel(SubscriptionManager& sm_, const std::string& tag_) : sm(sm_), tag(tag_) {}
- ~AutoCancel() { sm.cancel(tag); }
+ AutoCancel(SubscriptionManager&, const std::string& tag);
+ ~AutoCancel();
private:
SubscriptionManager& sm;
std::string tag;
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt
index 526f191f84..ee9291a41b 100644
--- a/cpp/src/CMakeLists.txt
+++ b/cpp/src/CMakeLists.txt
@@ -167,7 +167,7 @@ inherit_value ("winver_LEGAL_COPYRIGHT" "")
# check if we generate source as part of the build
-# - rubygen generates the amqp spec and clustering
+# - rubygen generates the amqp spec
# - managementgen generates the broker management code
#
# rubygen subdir is excluded from stable distributions
@@ -186,7 +186,7 @@ if (EXISTS ${AMQP_SPEC})
message(FATAL_ERROR "Can't locate python, needed to generate source files.")
endif (NOT PYTHON_EXECUTABLE)
- set(specs ${AMQP_SPEC} ${qpid-cpp_SOURCE_DIR}/xml/cluster.xml)
+ set(specs ${AMQP_SPEC})
set(regen_amqp OFF)
set(rgen_dir ${qpid-cpp_SOURCE_DIR}/rubygen)
file(GLOB_RECURSE rgen_progs ${rgen_dir}/*.rb)
@@ -207,7 +207,6 @@ execute_process(COMMAND ${RUBY_EXECUTABLE} -I ${rgen_dir} ${rgen_dir}/generate $
set(mgmt_specs ${AMQP_SPEC_DIR}/management-schema.xml
${CMAKE_CURRENT_SOURCE_DIR}/qpid/acl/management-schema.xml
- ${CMAKE_CURRENT_SOURCE_DIR}/qpid/cluster/management-schema.xml
${CMAKE_CURRENT_SOURCE_DIR}/qpid/ha/management-schema.xml
)
set(mgen_dir ${qpid-cpp_SOURCE_DIR}/managementgen)
@@ -672,9 +671,6 @@ if (BUILD_HA)
COMPONENT ${QPID_COMPONENT_BROKER})
endif (BUILD_HA)
-# Check for optional cluster support requirements
-include (cluster.cmake)
-
# Check for optional RDMA support requirements
include (rdma.cmake)
@@ -1117,7 +1113,6 @@ set (qpidbroker_SOURCES
qpid/broker/Exchange.cpp
qpid/broker/ExpiryPolicy.cpp
qpid/broker/Fairshare.cpp
- qpid/broker/LegacyLVQ.cpp
qpid/broker/MessageDeque.cpp
qpid/broker/MessageMap.cpp
qpid/broker/PriorityQueue.cpp
@@ -1144,17 +1139,22 @@ set (qpidbroker_SOURCES
qpid/broker/HeadersExchange.cpp
qpid/broker/Link.cpp
qpid/broker/LinkRegistry.cpp
+ qpid/broker/LossyQueue.cpp
+ qpid/broker/Lvq.cpp
qpid/broker/Message.cpp
qpid/broker/MessageAdapter.cpp
qpid/broker/MessageBuilder.cpp
+ qpid/broker/MessageHandle.cpp
qpid/broker/MessageStoreModule.cpp
qpid/broker/NameGenerator.cpp
qpid/broker/NullMessageStore.cpp
qpid/broker/QueueBindings.cpp
qpid/broker/QueuedMessage.cpp
- qpid/broker/QueueEvents.cpp
- qpid/broker/QueuePolicy.cpp
+ qpid/broker/QueueCursor.cpp
+ qpid/broker/QueueDepth.cpp
+ qpid/broker/QueueFactory.cpp
qpid/broker/QueueRegistry.cpp
+ qpid/broker/QueueSettings.cpp
qpid/broker/QueueFlowLimit.cpp
qpid/broker/RecoveryManagerImpl.cpp
qpid/broker/RecoveredEnqueue.cpp
@@ -1177,8 +1177,8 @@ set (qpidbroker_SOURCES
qpid/broker/TopicExchange.cpp
qpid/broker/TxAccept.cpp
qpid/broker/TxBuffer.cpp
- qpid/broker/TxPublish.cpp
qpid/broker/Vhost.cpp
+ qpid/broker/amqp_0_10/MessageTransfer.cpp
qpid/management/ManagementAgent.cpp
qpid/management/ManagementDirectExchange.cpp
qpid/management/ManagementTopicExchange.cpp
@@ -1433,45 +1433,6 @@ install (FILES ${qmfconsole_HEADERS}
COMPONENT ${QPID_COMPONENT_QMF})
install_pdb (qmfconsole ${QPID_COMPONENT_QMF})
-# A queue event listener plugin that creates messages on a replication
-# queue corresponding to enqueue and dequeue events:
-set (replicating_listener_SOURCES
- qpid/replication/constants.h
- qpid/replication/ReplicatingEventListener.cpp
- qpid/replication/ReplicatingEventListener.h
- )
-add_msvc_version (replicating_listener library dll)
-add_library (replicating_listener MODULE ${replicating_listener_SOURCES})
-target_link_libraries (replicating_listener qpidbroker ${Boost_PROGRAM_OPTIONS_LIBRARY})
-set_target_properties (replicating_listener PROPERTIES PREFIX "")
-if (CMAKE_COMPILER_IS_GNUCXX)
- set_target_properties(replicating_listener PROPERTIES
- LINK_FLAGS "${GCC_CATCH_UNDEFINED}")
-endif (CMAKE_COMPILER_IS_GNUCXX)
-install (TARGETS replicating_listener
- DESTINATION ${QPIDD_MODULE_DIR}
- COMPONENT ${QPID_COMPONENT_BROKER})
-
-# A custom exchange plugin that allows an exchange to be created that
-# can process the messages from a replication queue (populated on the
-# source system by the replicating listener plugin above) and take the
-# corresponding action on the local queues
-set (replication_exchange_SOURCES
- qpid/replication/constants.h
- qpid/replication/ReplicationExchange.cpp
- qpid/replication/ReplicationExchange.h
- )
-add_msvc_version (replication_exchange library dll)
-add_library (replication_exchange MODULE ${replication_exchange_SOURCES})
-target_link_libraries (replication_exchange qpidbroker)
-set_target_properties (replication_exchange PROPERTIES PREFIX "")
-if (CMAKE_COMPILER_IS_GNUCXX)
- set_target_properties(replication_exchange PROPERTIES
- LINK_FLAGS "${GCC_CATCH_UNDEFINED}")
-endif (CMAKE_COMPILER_IS_GNUCXX)
-install (TARGETS replication_exchange
- DESTINATION ${QPIDD_MODULE_DIR}
- COMPONENT ${QPID_COMPONENT_BROKER})
# This is only really needed until all the trunk builds (Linux, UNIX, Windows)
# are all on cmake only. This is because cmake builds always have a config.h
diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am
index 8a8e4b1928..a65230b091 100644
--- a/cpp/src/Makefile.am
+++ b/cpp/src/Makefile.am
@@ -85,7 +85,7 @@ if GENERATE
# AMQP_FINAL_XML is defined in ../configure.ac
amqp_0_10_xml=@AMQP_FINAL_XML@
-specs=$(amqp_0_10_xml) $(top_srcdir)/xml/cluster.xml
+specs=$(amqp_0_10_xml)
# Ruby generator.
rgen_dir=$(top_srcdir)/rubygen
@@ -104,7 +104,6 @@ $(srcdir)/rubygen.cmake: $(rgen_generator) $(specs)
mgen_dir=$(top_srcdir)/managementgen
mgen_xml=$(top_srcdir)/../specs/management-schema.xml \
$(srcdir)/qpid/acl/management-schema.xml \
- $(srcdir)/qpid/cluster/management-schema.xml \
$(srcdir)/qpid/ha/management-schema.xml
mgen_cmd=$(mgen_dir)/qmf-gen -m $(srcdir)/managementgen.mk \
-c $(srcdir)/managementgen.cmake -q -b -l -o qmf \
@@ -217,7 +216,6 @@ cmoduleexecdir=$(libdir)/qpid/client
dmoduleexec_LTLIBRARIES =
cmoduleexec_LTLIBRARIES =
-include cluster.mk
include ha.mk
include acl.mk
include qmf.mk
@@ -225,7 +223,6 @@ include qmfc.mk
if HAVE_XML
include xml.mk
endif
-include replication.mk
if RDMA
@@ -292,7 +289,6 @@ endif
EXTRA_DIST +=\
CMakeLists.txt \
- cluster.cmake \
config.h.cmake \
rdma.cmake \
ssl.cmake \
@@ -337,6 +333,7 @@ libqpidcommon_la_LIBADD = \
-lboost_program_options \
-lboost_filesystem \
-luuid \
+ -lpthread \
$(LIB_DLOPEN) \
$(LIB_CLOCK_GETTIME)
@@ -559,7 +556,6 @@ libqpidbroker_la_SOURCES = \
qpid/broker/Deliverable.h \
qpid/broker/DeliverableMessage.cpp \
qpid/broker/DeliverableMessage.h \
- qpid/broker/DeliveryAdapter.h \
qpid/broker/DeliveryId.h \
qpid/broker/DeliveryRecord.cpp \
qpid/broker/DeliveryRecord.h \
@@ -590,12 +586,14 @@ libqpidbroker_la_SOURCES = \
qpid/broker/HeadersExchange.cpp \
qpid/broker/HeadersExchange.h \
qpid/broker/AsyncCompletion.h \
- qpid/broker/LegacyLVQ.h \
- qpid/broker/LegacyLVQ.cpp \
+ qpid/broker/IndexedDeque.h \
qpid/broker/Link.cpp \
qpid/broker/Link.h \
qpid/broker/LinkRegistry.cpp \
qpid/broker/LinkRegistry.h \
+ qpid/broker/Lvq.h \
+ qpid/broker/Lvq.cpp \
+ qpid/broker/MapHandler.h \
qpid/broker/Message.cpp \
qpid/broker/Message.h \
qpid/broker/MessageAdapter.cpp \
@@ -630,19 +628,25 @@ libqpidbroker_la_SOURCES = \
qpid/broker/QueueBindings.h \
qpid/broker/QueueCleaner.cpp \
qpid/broker/QueueCleaner.h \
- qpid/broker/QueueEvents.cpp \
- qpid/broker/QueueEvents.h \
+ qpid/broker/QueueCursor.h \
+ qpid/broker/QueueCursor.cpp \
+ qpid/broker/QueueDepth.h \
+ qpid/broker/QueueDepth.cpp \
+ qpid/broker/QueueFactory.h \
+ qpid/broker/QueueFactory.cpp \
+ qpid/broker/QueueSettings.h \
+ qpid/broker/QueueSettings.cpp \
qpid/broker/QueueListeners.cpp \
qpid/broker/QueueListeners.h \
qpid/broker/QueueObserver.h \
- qpid/broker/QueuePolicy.cpp \
- qpid/broker/QueuePolicy.h \
qpid/broker/QueueRegistry.cpp \
qpid/broker/QueueRegistry.h \
qpid/broker/QueuedMessage.cpp \
qpid/broker/QueuedMessage.h \
qpid/broker/QueueFlowLimit.h \
qpid/broker/QueueFlowLimit.cpp \
+ qpid/broker/LossyQueue.h \
+ qpid/broker/LossyQueue.cpp \
qpid/broker/RecoverableConfig.h \
qpid/broker/RecoverableExchange.h \
qpid/broker/RecoverableMessage.h \
@@ -693,9 +697,6 @@ libqpidbroker_la_SOURCES = \
qpid/broker/TxBuffer.cpp \
qpid/broker/TxBuffer.h \
qpid/broker/TxOp.h \
- qpid/broker/TxOpVisitor.h \
- qpid/broker/TxPublish.cpp \
- qpid/broker/TxPublish.h \
qpid/broker/Vhost.cpp \
qpid/broker/Vhost.h \
qpid/broker/MessageDistributor.h \
@@ -703,6 +704,8 @@ libqpidbroker_la_SOURCES = \
qpid/broker/FifoDistributor.cpp \
qpid/broker/MessageGroupManager.cpp \
qpid/broker/MessageGroupManager.h \
+ qpid/broker/amqp_0_10/MessageTransfer.h \
+ qpid/broker/amqp_0_10/MessageTransfer.cpp \
qpid/management/ManagementAgent.cpp \
qpid/management/ManagementAgent.h \
qpid/management/ManagementDirectExchange.cpp \
diff --git a/cpp/src/asyncstore.cmake b/cpp/src/asyncstore.cmake
index 6171ed5505..e6230483ea 100644
--- a/cpp/src/asyncstore.cmake
+++ b/cpp/src/asyncstore.cmake
@@ -51,6 +51,7 @@ set (asyncStore_SOURCES
qpid/asyncStore/EventHandleImpl.cpp
qpid/asyncStore/MessageHandleImpl.cpp
qpid/asyncStore/OperationQueue.cpp
+ qpid/asyncStore/PersistableMessageContext.cpp
qpid/asyncStore/Plugin.cpp
qpid/asyncStore/QueueHandleImpl.cpp
qpid/asyncStore/RunState.cpp
diff --git a/cpp/src/cluster.cmake b/cpp/src/cluster.cmake
deleted file mode 100644
index 815cdffdec..0000000000
--- a/cpp/src/cluster.cmake
+++ /dev/null
@@ -1,175 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-#
-# Cluster library CMake fragment, to be included in CMakeLists.txt
-#
-
-# Optional cluster support. Requires CPG; if building it, can optionally
-# include CMAN support as well.
-
-include(CheckIncludeFiles)
-include(CheckLibraryExists)
-
-set(LIBCPG_PATH /usr/lib/openais /usr/lib64/openais /usr/lib/corosync /usr/lib64/corosync CACHE STRING "Default locations for libcpg (cluster library)" )
-find_library(LIBCPG cpg ${LIBCPG_PATH})
-if (LIBCPG)
- CHECK_LIBRARY_EXISTS (${LIBCPG} cpg_local_get "" HAVE_LIBCPG)
- CHECK_INCLUDE_FILES (openais/cpg.h HAVE_OPENAIS_CPG_H)
- CHECK_INCLUDE_FILES (corosync/cpg.h HAVE_COROSYNC_CPG_H)
-endif (LIBCPG)
-
-set (cluster_default ${cluster_force})
-if (CMAKE_SYSTEM_NAME STREQUAL Windows)
-else (CMAKE_SYSTEM_NAME STREQUAL Windows)
- if (HAVE_LIBCPG)
- if (HAVE_OPENAIS_CPG_H OR HAVE_COROSYNC_CPG_H)
- set (cluster_default ON)
- endif (HAVE_OPENAIS_CPG_H OR HAVE_COROSYNC_CPG_H)
- endif (HAVE_LIBCPG)
-endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
-
-option(BUILD_CLUSTER "Build with CPG support for clustering" ${cluster_default})
-if (BUILD_CLUSTER)
-
- if (NOT HAVE_LIBCPG)
- message(FATAL_ERROR "libcpg not found, install openais-devel or corosync-devel")
- endif (NOT HAVE_LIBCPG)
- if (NOT HAVE_OPENAIS_CPG_H AND NOT HAVE_COROSYNC_CPG_H)
- message(FATAL_ERROR "cpg.h not found, install openais-devel or corosync-devel")
- endif (NOT HAVE_OPENAIS_CPG_H AND NOT HAVE_COROSYNC_CPG_H)
-
- CHECK_LIBRARY_EXISTS (cman cman_is_quorate "" HAVE_LIBCMAN)
- CHECK_INCLUDE_FILES (libcman.h HAVE_LIBCMAN_H)
-
- set(cluster_quorum_default ${cluster_quorum_force})
- if (HAVE_LIBCMAN AND HAVE_LIBCMAN_H)
- set(cluster_quorum_default ON)
- endif (HAVE_LIBCMAN AND HAVE_LIBCMAN_H)
-
- option(BUILD_CLUSTER_QUORUM "Include libcman quorum service integration" ${cluster_quorum_default})
- if (BUILD_CLUSTER_QUORUM)
- if (NOT HAVE_LIBCMAN)
- message(FATAL_ERROR "libcman not found, install cman-devel or cmanlib-devel")
- endif (NOT HAVE_LIBCMAN)
- if (NOT HAVE_LIBCMAN_H)
- message(FATAL_ERROR "libcman.h not found, install cman-devel or cmanlib-devel")
- endif (NOT HAVE_LIBCMAN_H)
-
- set (CMAN_SOURCES qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp)
- set (CMAN_LIB cman)
- else (BUILD_CLUSTER_QUORUM)
- set (CMAN_SOURCES qpid/cluster/Quorum_null.h)
- endif (BUILD_CLUSTER_QUORUM)
-
- set (cluster_SOURCES
- ${CMAN_SOURCES}
- qpid/cluster/Cluster.cpp
- qpid/cluster/Cluster.h
- qpid/cluster/ClusterTimer.cpp
- qpid/cluster/ClusterTimer.h
- qpid/cluster/Decoder.cpp
- qpid/cluster/Decoder.h
- qpid/cluster/PollableQueue.h
- qpid/cluster/ClusterMap.cpp
- qpid/cluster/ClusterMap.h
- qpid/cluster/ClusterPlugin.cpp
- qpid/cluster/ClusterSettings.h
- qpid/cluster/Connection.cpp
- qpid/cluster/Connection.h
- qpid/cluster/ConnectionCodec.cpp
- qpid/cluster/ConnectionCodec.h
- qpid/cluster/Cpg.cpp
- qpid/cluster/Cpg.h
- qpid/cluster/CredentialsExchange.cpp
- qpid/cluster/CredentialsExchange.h
- qpid/cluster/Dispatchable.h
- qpid/cluster/UpdateClient.cpp
- qpid/cluster/UpdateClient.h
- qpid/cluster/RetractClient.cpp
- qpid/cluster/RetractClient.h
- qpid/cluster/ErrorCheck.cpp
- qpid/cluster/ErrorCheck.h
- qpid/cluster/Event.cpp
- qpid/cluster/Event.h
- qpid/cluster/EventFrame.h
- qpid/cluster/EventFrame.cpp
- qpid/cluster/ExpiryPolicy.h
- qpid/cluster/ExpiryPolicy.cpp
- qpid/cluster/FailoverExchange.cpp
- qpid/cluster/FailoverExchange.h
- qpid/cluster/UpdateExchange.cpp
- qpid/cluster/UpdateExchange.h
- qpid/cluster/UpdateReceiver.h
- qpid/cluster/LockedConnectionMap.h
- qpid/cluster/Multicaster.cpp
- qpid/cluster/Multicaster.h
- qpid/cluster/McastFrameHandler.h
- qpid/cluster/NoOpConnectionOutputHandler.h
- qpid/cluster/Numbering.h
- qpid/cluster/OutputInterceptor.cpp
- qpid/cluster/OutputInterceptor.h
- qpid/cluster/PollerDispatch.cpp
- qpid/cluster/PollerDispatch.h
- qpid/cluster/ProxyInputHandler.h
- qpid/cluster/Quorum.h
- qpid/cluster/InitialStatusMap.h
- qpid/cluster/InitialStatusMap.cpp
- qpid/cluster/MemberSet.h
- qpid/cluster/MemberSet.cpp
- qpid/cluster/types.h
- qpid/cluster/SecureConnectionFactory.h
- qpid/cluster/SecureConnectionFactory.cpp
- qpid/cluster/StoreStatus.h
- qpid/cluster/StoreStatus.cpp
- qpid/cluster/UpdateDataExchange.h
- qpid/cluster/UpdateDataExchange.cpp
- )
-
- add_library (cluster MODULE ${cluster_SOURCES})
- target_link_libraries (cluster ${LIBCPG} ${CMAN_LIB} qpidbroker qpidclient ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY})
- set_target_properties (cluster PROPERTIES PREFIX "")
-
- # Create a second shared library for linking with test executables,
- # cmake will not allow a module to be linked with an executable.
- add_library (cluster_shared SHARED ${cluster_SOURCES})
- target_link_libraries (cluster_shared ${LIBCPG} ${CMAN_LIB} qpidbroker qpidclient ${Boost_FILESYSTEM_LIBRARY})
-
- if (CMAKE_COMPILER_IS_GNUCXX)
- # Turn off optimisation based on strict-aliasing because we get warnings about violations
- set_target_properties(cluster cluster_shared PROPERTIES
- COMPILE_FLAGS "-fno-strict-aliasing"
- LINK_FLAGS "${GCC_CATCH_UNDEFINED} -pthread")
- endif (CMAKE_COMPILER_IS_GNUCXX)
-
- add_library (watchdog MODULE qpid/cluster/WatchDogPlugin.cpp)
- set_target_properties (watchdog PROPERTIES PREFIX "")
-
- add_executable(qpidd_watchdog qpid/cluster/qpidd_watchdog.cpp)
-
- install (TARGETS cluster watchdog
- DESTINATION ${QPIDD_MODULE_DIR}
- COMPONENT ${QPID_COMPONENT_BROKER})
- install (TARGETS qpidd_watchdog
- DESTINATION ${QPID_LIBEXEC_DIR}
- COMPONENT ${QPID_COMPONENT_BROKER})
-
-endif (BUILD_CLUSTER)
-
-# Distribute all sources.
-#EXTRA_DIST += qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp qpid/cluster/Quorum_null.h
diff --git a/cpp/src/cluster.mk b/cpp/src/cluster.mk
deleted file mode 100644
index 632522e84f..0000000000
--- a/cpp/src/cluster.mk
+++ /dev/null
@@ -1,115 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-#
-# Cluster library makefile fragment, to be included in Makefile.am
-#
-
-# Optional CMAN support
-
-# Distribute all sources.
-EXTRA_DIST += qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp qpid/cluster/Quorum_null.h
-
-if HAVE_LIBCMAN
-CMAN_SOURCES = qpid/cluster/Quorum_cman.h qpid/cluster/Quorum_cman.cpp
-libcman = -lcman
-else
-CMAN_SOURCES = qpid/cluster/Quorum_null.h
-endif
-
-if HAVE_LIBCPG
-
-dmoduleexec_LTLIBRARIES += cluster.la
-
-cluster_la_SOURCES = \
- $(CMAN_SOURCES) \
- qpid/cluster/Cluster.cpp \
- qpid/cluster/Cluster.h \
- qpid/cluster/ClusterTimer.cpp \
- qpid/cluster/ClusterTimer.h \
- qpid/cluster/Decoder.cpp \
- qpid/cluster/Decoder.h \
- qpid/cluster/PollableQueue.h \
- qpid/cluster/ClusterMap.cpp \
- qpid/cluster/ClusterMap.h \
- qpid/cluster/ClusterPlugin.cpp \
- qpid/cluster/ClusterSettings.h \
- qpid/cluster/Connection.cpp \
- qpid/cluster/Connection.h \
- qpid/cluster/ConnectionCodec.cpp \
- qpid/cluster/ConnectionCodec.h \
- qpid/cluster/Cpg.cpp \
- qpid/cluster/Cpg.h \
- qpid/cluster/CredentialsExchange.cpp \
- qpid/cluster/CredentialsExchange.h \
- qpid/cluster/Dispatchable.h \
- qpid/cluster/UpdateClient.cpp \
- qpid/cluster/UpdateClient.h \
- qpid/cluster/RetractClient.cpp \
- qpid/cluster/RetractClient.h \
- qpid/cluster/ErrorCheck.cpp \
- qpid/cluster/ErrorCheck.h \
- qpid/cluster/Event.cpp \
- qpid/cluster/Event.h \
- qpid/cluster/EventFrame.h \
- qpid/cluster/EventFrame.cpp \
- qpid/cluster/ExpiryPolicy.h \
- qpid/cluster/ExpiryPolicy.cpp \
- qpid/cluster/FailoverExchange.cpp \
- qpid/cluster/FailoverExchange.h \
- qpid/cluster/UpdateExchange.h \
- qpid/cluster/UpdateExchange.cpp \
- qpid/cluster/UpdateReceiver.h \
- qpid/cluster/LockedConnectionMap.h \
- qpid/cluster/Multicaster.cpp \
- qpid/cluster/Multicaster.h \
- qpid/cluster/McastFrameHandler.h \
- qpid/cluster/NoOpConnectionOutputHandler.h \
- qpid/cluster/Numbering.h \
- qpid/cluster/OutputInterceptor.cpp \
- qpid/cluster/OutputInterceptor.h \
- qpid/cluster/PollerDispatch.cpp \
- qpid/cluster/PollerDispatch.h \
- qpid/cluster/ProxyInputHandler.h \
- qpid/cluster/Quorum.h \
- qpid/cluster/InitialStatusMap.h \
- qpid/cluster/InitialStatusMap.cpp \
- qpid/cluster/MemberSet.h \
- qpid/cluster/MemberSet.cpp \
- qpid/cluster/types.h \
- qpid/cluster/SecureConnectionFactory.h \
- qpid/cluster/SecureConnectionFactory.cpp \
- qpid/cluster/StoreStatus.h \
- qpid/cluster/StoreStatus.cpp \
- qpid/cluster/UpdateDataExchange.h \
- qpid/cluster/UpdateDataExchange.cpp
-
-cluster_la_LIBADD= -lcpg $(libcman) libqpidbroker.la libqpidclient.la
-cluster_la_CXXFLAGS = $(AM_CXXFLAGS) -fno-strict-aliasing
-cluster_la_LDFLAGS = $(PLUGINLDFLAGS)
-
-# The watchdog plugin and helper executable
-dmoduleexec_LTLIBRARIES += watchdog.la
-watchdog_la_SOURCES = qpid/cluster/WatchDogPlugin.cpp
-watchdog_la_LIBADD = libqpidbroker.la
-watchdog_la_LDFLAGS = $(PLUGINLDFLAGS)
-
-qpidexec_PROGRAMS += qpidd_watchdog
-qpidd_watchdog_SOURCES = qpid/cluster/qpidd_watchdog.cpp
-
-endif # HAVE_LIBCPG
diff --git a/cpp/src/qpid/acl/Acl.cpp b/cpp/src/qpid/acl/Acl.cpp
index d941577f6a..89c4b3402a 100644
--- a/cpp/src/qpid/acl/Acl.cpp
+++ b/cpp/src/qpid/acl/Acl.cpp
@@ -129,6 +129,13 @@ bool Acl::approveConnection(const qpid::broker::Connection& conn)
return connectionCounter->approveConnection(conn);
}
+
+void Acl::setUserId(const qpid::broker::Connection& connection, const std::string& username)
+{
+ connectionCounter->setUserId(connection, username);
+}
+
+
bool Acl::result(
const AclResult& aclreslt,
const std::string& id,
diff --git a/cpp/src/qpid/acl/Acl.h b/cpp/src/qpid/acl/Acl.h
index 4893f71ef2..4787934275 100644
--- a/cpp/src/qpid/acl/Acl.h
+++ b/cpp/src/qpid/acl/Acl.h
@@ -94,6 +94,8 @@ public:
virtual bool approveConnection(const broker::Connection& connection);
+ virtual void setUserId(const broker::Connection& connection, const std::string& username);
+
virtual ~Acl();
private:
bool result(
diff --git a/cpp/src/qpid/acl/AclConnectionCounter.cpp b/cpp/src/qpid/acl/AclConnectionCounter.cpp
index 052fa3c222..8c6e3eef6e 100644
--- a/cpp/src/qpid/acl/AclConnectionCounter.cpp
+++ b/cpp/src/qpid/acl/AclConnectionCounter.cpp
@@ -296,6 +296,47 @@ bool ConnectionCounter::approveConnection(const broker::Connection& connection)
}
}
+
+//
+// setUserId
+// On cluster shadow connections, track a new user id for this connection.
+//
+void ConnectionCounter::setUserId(const broker::Connection& connection,
+ const std::string& username)
+{
+ Mutex::ScopedLock locker(dataLock);
+
+ connectCountsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
+ if (eRef != connectProgressMap.end()) {
+ if ((*eRef).second == C_OPENED){
+ // Connection has been opened so that current user has been counted
+ if (connection.isShadow()) {
+ // This is a shadow connection and therefore receives userId changes
+ QPID_LOG(debug, "Changing User ID for cluster connection: "
+ << connection.getMgmtId() << ", old user:'" << connection.getUserId()
+ << "', new user:'" << username << "'");
+
+ // Decrement user in-use count for old userId
+ releaseLH(connectByNameMap,
+ connection.getUserId(),
+ nameLimit);
+ // Increment user in-use count for new userId
+ (void) countConnectionLH(connectByNameMap, username, nameLimit, false);
+ } else {
+ QPID_LOG(warning, "Changing User ID for non-cluster connections is not supported: "
+ << connection.getMgmtId() << ", old user " << connection.getUserId()
+ << ", new user " << username);
+ }
+ } else {
+ // connection exists but has not been opened.
+ // setUserId is called in normal course. The user gets counted when connection is opened.
+ }
+ } else {
+ // Connection does not exist.
+ }
+}
+
+
//
// getClientIp - given a connection's mgmtId return the client host part.
//
diff --git a/cpp/src/qpid/acl/AclConnectionCounter.h b/cpp/src/qpid/acl/AclConnectionCounter.h
index eec8e90256..54fa6933ff 100644
--- a/cpp/src/qpid/acl/AclConnectionCounter.h
+++ b/cpp/src/qpid/acl/AclConnectionCounter.h
@@ -94,6 +94,7 @@ public:
// Connection counting
bool approveConnection(const broker::Connection& conn);
+ void setUserId(const broker::Connection& connection, const std::string& username);
};
}} // namespace qpid::ha
diff --git a/cpp/src/qpid/acl/AclData.cpp b/cpp/src/qpid/acl/AclData.cpp
index a07176dc76..7c14d0985d 100644
--- a/cpp/src/qpid/acl/AclData.cpp
+++ b/cpp/src/qpid/acl/AclData.cpp
@@ -25,6 +25,13 @@ namespace qpid {
namespace acl {
//
+ // Instantiate the substitution keyword string
+ //
+ const std::string AclData::USER_SUBSTITUTION_KEYWORD = "${user}";
+ const std::string AclData::DOMAIN_SUBSTITUTION_KEYWORD = "${domain}";
+ const std::string AclData::USERDOMAIN_SUBSTITUTION_KEYWORD = "${userdomain}";
+
+ //
// constructor
//
AclData::AclData():
@@ -147,7 +154,17 @@ namespace acl {
// the calling args and not in the param map.
if (rulePropMapItr->first == acl::SPECPROP_NAME)
{
- if (matchProp(rulePropMapItr->second, name))
+ // substitute user name into object name
+ bool result;
+ if (rsItr->ruleHasUserSub[PROP_NAME]) {
+ std::string sName(rulePropMapItr->second);
+ substituteUserId(sName, id);
+ result = matchProp(sName, name);
+ } else {
+ result = matchProp(rulePropMapItr->second, name);
+ }
+
+ if (result)
{
QPID_LOG(debug, "ACL: lookup name '" << name
<< "' matched with rule name '"
@@ -222,7 +239,20 @@ namespace acl {
break;
default:
- if (matchProp(rulePropMapItr->second, lookupParamItr->second))
+ bool result;
+ if ((SPECPROP_ALTERNATE == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_ALTERNATE]) ||
+ (SPECPROP_ROUTINGKEY == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_ROUTINGKEY]) ||
+ (SPECPROP_QUEUENAME == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_QUEUENAME]))
+ {
+ // These properties are allowed to have username substitution
+ std::string sName(rulePropMapItr->second);
+ substituteUserId(sName, id);
+ result = matchProp(sName, lookupParamItr->second);
+ } else {
+ result = matchProp(rulePropMapItr->second, lookupParamItr->second);
+ }
+
+ if (result)
{
QPID_LOG(debug, "ACL: the pair("
<< AclHelper::getPropertyStr(lookupParamItr->first)
@@ -346,7 +376,18 @@ namespace acl {
bool match =true;
if (rsItr->pubExchNameInRule)
{
- if (matchProp(rsItr->pubExchName, name))
+ // substitute user name into object name
+ bool result;
+
+ if (rsItr->ruleHasUserSub[PROP_NAME]) {
+ std::string sName(rsItr->pubExchName);
+ substituteUserId(sName, id);
+ result = matchProp(sName, name);
+ } else {
+ result = matchProp(rsItr->pubExchName, name);
+ }
+
+ if (result)
{
QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup exchange name '"
<< name << "' matched with rule name '"
@@ -364,18 +405,40 @@ namespace acl {
if (match && rsItr->pubRoutingKeyInRule)
{
- if (rsItr->matchRoutingKey(routingKey))
+ if ((routingKey.find(USER_SUBSTITUTION_KEYWORD, 0) != std::string::npos) ||
+ (routingKey.find(DOMAIN_SUBSTITUTION_KEYWORD, 0) != std::string::npos) ||
+ (routingKey.find(USERDOMAIN_SUBSTITUTION_KEYWORD, 0) != std::string::npos))
{
- QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
- << routingKey << "' matched with rule routing key '"
- << rsItr->pubRoutingKey << "'");
+ // The user is not allowed to present a routing key with the substitution key in it
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum <<
+ " User-specified routing key has substitution wildcard:" << routingKey
+ << ". Rule match prohibited.");
+ match = false;
}
else
{
- QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
- << routingKey << "' did not match with rule routing key '"
- << rsItr->pubRoutingKey << "'");
- match = false;
+ bool result;
+ if (rsItr->ruleHasUserSub[PROP_ROUTINGKEY]) {
+ std::string sKey(routingKey);
+ substituteKeywords(sKey, id);
+ result = rsItr->matchRoutingKey(sKey);
+ } else {
+ result = rsItr->matchRoutingKey(routingKey);
+ }
+
+ if (result)
+ {
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
+ << routingKey << "' matched with rule routing key '"
+ << rsItr->pubRoutingKey << "'");
+ }
+ else
+ {
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
+ << routingKey << "' did not match with rule routing key '"
+ << rsItr->pubRoutingKey << "'");
+ match = false;
+ }
}
}
@@ -501,4 +564,102 @@ namespace acl {
return true;
}
+ const std::string DOMAIN_SEPARATOR("@");
+ const std::string PERIOD(".");
+ const std::string UNDERSCORE("_");
+ //
+ // substituteString
+ // Given a name string from an Acl rule, substitute the replacement into it
+ // wherever the placeholder directs.
+ //
+ void AclData::substituteString(std::string& targetString,
+ const std::string& placeholder,
+ const std::string& replacement)
+ {
+ assert (!placeholder.empty());
+ if (placeholder.empty())
+ return;
+ size_t start_pos(0);
+ while((start_pos = targetString.find(placeholder, start_pos)) != std::string::npos)
+ {
+ targetString.replace(start_pos, placeholder.length(), replacement);
+ start_pos += replacement.length();
+ }
+ }
+
+
+ //
+ // normalizeUserId
+ // Given a name string return it in a form usable as topic keys:
+ // change "@" and "." to "_".
+ //
+ std::string AclData::normalizeUserId(const std::string& userId)
+ {
+ std::string normalId(userId);
+ substituteString(normalId, DOMAIN_SEPARATOR, UNDERSCORE);
+ substituteString(normalId, PERIOD, UNDERSCORE);
+ return normalId;
+ }
+
+
+ //
+ // substituteUserId
+ // Given an Acl rule and an authenticated userId
+ // do the keyword substitutions on the rule.
+ //
+ void AclData::AclData::substituteUserId(std::string& ruleString,
+ const std::string& userId)
+ {
+ size_t locDomSeparator(0);
+ std::string user("");
+ std::string domain("");
+ std::string userdomain = normalizeUserId(userId);
+
+ locDomSeparator = userId.find(DOMAIN_SEPARATOR);
+ if (std::string::npos == locDomSeparator) {
+ // "@" not found. There's just a user name
+ user = normalizeUserId(userId);
+ } else {
+ // "@" found, split the names. Domain may be blank.
+ user = normalizeUserId(userId.substr(0,locDomSeparator));
+ domain = normalizeUserId(userId.substr(locDomSeparator+1));
+ }
+
+ substituteString(ruleString, USER_SUBSTITUTION_KEYWORD, user);
+ substituteString(ruleString, DOMAIN_SUBSTITUTION_KEYWORD, domain);
+ substituteString(ruleString, USERDOMAIN_SUBSTITUTION_KEYWORD, userdomain);
+ }
+
+
+ //
+ // substituteKeywords
+ // Given an Acl rule and an authenticated userId
+ // do reverse keyword substitutions on the rule.
+ // That is, replace the normalized name in the rule string with
+ // the keyword that represents it. This stragegy is used for
+ // topic key lookups where the keyword string proper is in the
+ // topic key search tree.
+ //
+ void AclData::AclData::substituteKeywords(std::string& ruleString,
+ const std::string& userId)
+ {
+ size_t locDomSeparator(0);
+ std::string user("");
+ std::string domain("");
+ std::string userdomain = normalizeUserId(userId);
+
+ locDomSeparator = userId.find(DOMAIN_SEPARATOR);
+ if (std::string::npos == locDomSeparator) {
+ // "@" not found. There's just a user name
+ user = normalizeUserId(userId);
+ } else {
+ // "@" found, split the names
+ user = normalizeUserId(userId.substr(0,locDomSeparator));
+ domain = normalizeUserId(userId.substr(locDomSeparator+1));
+ }
+ std::string oRule(ruleString);
+ substituteString(ruleString, userdomain, USERDOMAIN_SUBSTITUTION_KEYWORD);
+ substituteString(ruleString, user, USER_SUBSTITUTION_KEYWORD);
+ substituteString(ruleString, domain, DOMAIN_SUBSTITUTION_KEYWORD);
+ }
}}
diff --git a/cpp/src/qpid/acl/AclData.h b/cpp/src/qpid/acl/AclData.h
index ca0a676a1c..b4b13c44b6 100644
--- a/cpp/src/qpid/acl/AclData.h
+++ b/cpp/src/qpid/acl/AclData.h
@@ -62,6 +62,7 @@ public:
boost::shared_ptr<topicTester> pTTest;
bool pubExchNameInRule;
std::string pubExchName;
+ std::vector<bool> ruleHasUserSub;
Rule (int ruleNum, qpid::acl::AclResult res, specPropertyMap& p) :
rawRuleNum(ruleNum),
@@ -71,7 +72,8 @@ public:
pubRoutingKey(),
pTTest(boost::shared_ptr<topicTester>(new topicTester())),
pubExchNameInRule(false),
- pubExchName()
+ pubExchName(),
+ ruleHasUserSub(PROPERTYSIZE, false)
{}
@@ -132,6 +134,17 @@ public:
bool matchProp(const std::string & src, const std::string& src1);
void clear ();
+ static const std::string USER_SUBSTITUTION_KEYWORD;
+ static const std::string DOMAIN_SUBSTITUTION_KEYWORD;
+ static const std::string USERDOMAIN_SUBSTITUTION_KEYWORD;
+ void substituteString(std::string& targetString,
+ const std::string& placeholder,
+ const std::string& replacement);
+ std::string normalizeUserId(const std::string& userId);
+ void substituteUserId(std::string& ruleString,
+ const std::string& userId);
+ void substituteKeywords(std::string& ruleString,
+ const std::string& userId);
AclData();
virtual ~AclData();
diff --git a/cpp/src/qpid/acl/AclReader.cpp b/cpp/src/qpid/acl/AclReader.cpp
index f9be49b88d..fae67d0325 100644
--- a/cpp/src/qpid/acl/AclReader.cpp
+++ b/cpp/src/qpid/acl/AclReader.cpp
@@ -103,6 +103,15 @@ namespace acl {
} else {
AclData::Rule rule(cnt, (*i)->res, (*i)->props);
+ // Record which properties have the user substitution string
+ for (pmCitr pItr=rule.props.begin(); pItr!=rule.props.end(); pItr++) {
+ if ((pItr->second.find(AclData::USER_SUBSTITUTION_KEYWORD, 0) != std::string::npos) ||
+ (pItr->second.find(AclData::DOMAIN_SUBSTITUTION_KEYWORD, 0) != std::string::npos) ||
+ (pItr->second.find(AclData::USERDOMAIN_SUBSTITUTION_KEYWORD, 0) != std::string::npos)) {
+ rule.ruleHasUserSub[pItr->first] = true;
+ }
+ }
+
// Action -> Object -> map<user -> set<Rule> >
std::ostringstream actionstr;
for (int acnt = ((*i)->actionAll ? 0 : (*i)->action);
diff --git a/cpp/src/qpid/asyncStore/PersistableMessageContext.cpp b/cpp/src/qpid/asyncStore/PersistableMessageContext.cpp
new file mode 100644
index 0000000000..fd449e1b9c
--- /dev/null
+++ b/cpp/src/qpid/asyncStore/PersistableMessageContext.cpp
@@ -0,0 +1,39 @@
+#include "PersistableMessageContext.h"
+
+namespace qpid {
+namespace asyncStore {
+
+PersistableMessageContext::PersistableMessageContext(qpid::broker::AsyncStore* store) : m_store(store) {}
+
+PersistableMessageContext::~PersistableMessageContext() {}
+
+void
+PersistableMessageContext::encode(qpid::framing::Buffer& /*buffer*/) const {}
+
+uint32_t
+PersistableMessageContext::encodedSize() const {
+ return 0;
+}
+
+bool
+PersistableMessageContext::isPersistent() const {
+ return false;
+}
+
+void
+PersistableMessageContext::decodeHeader(framing::Buffer& /*buffer*/) {}
+
+void
+PersistableMessageContext::decodeContent(framing::Buffer& /*buffer*/) {}
+
+uint32_t
+PersistableMessageContext::encodedHeaderSize() const {
+ return 0;
+}
+
+boost::intrusive_ptr<qpid::broker::PersistableMessage> PersistableMessageContext::merge(const std::map<std::string, qpid::types::Variant>& /*annotations*/) const {
+ boost::intrusive_ptr<qpid::broker::PersistableMessage> pmc;
+ return pmc;
+}
+
+}} // namespace qpid::asyncStore
diff --git a/cpp/src/qpid/asyncStore/PersistableMessageContext.h b/cpp/src/qpid/asyncStore/PersistableMessageContext.h
new file mode 100644
index 0000000000..ec9eb377c2
--- /dev/null
+++ b/cpp/src/qpid/asyncStore/PersistableMessageContext.h
@@ -0,0 +1,32 @@
+#ifndef qpid_asyncStore_PersistableMessageContext_h_
+#define qpid_asyncStore_PersistableMessageContext_h_
+
+#include "qpid/broker/MessageHandle.h"
+#include "qpid/broker/PersistableMessage.h"
+
+namespace qpid {
+namespace asyncStore {
+
+class PersistableMessageContext: public qpid::broker::PersistableMessage {
+private:
+ qpid::broker::MessageHandle m_msgHandle;
+ qpid::broker::AsyncStore* m_store;
+public:
+ PersistableMessageContext(qpid::broker::AsyncStore* store);
+ virtual ~PersistableMessageContext();
+
+ // --- Interface Persistable ---
+ void encode(qpid::framing::Buffer& buffer) const;
+ uint32_t encodedSize() const;
+
+ // --- Class PersistableMessage ---
+ bool isPersistent() const;
+ void decodeHeader(framing::Buffer& buffer);
+ void decodeContent(framing::Buffer& buffer);
+ uint32_t encodedHeaderSize() const;
+ boost::intrusive_ptr<PersistableMessage> merge(const std::map<std::string, qpid::types::Variant>& annotations) const;
+};
+
+}} // namespace qpid::asyncStore
+
+#endif // qpid_asyncStore_PersistableMessageContext_h_
diff --git a/cpp/src/qpid/broker/AclModule.h b/cpp/src/qpid/broker/AclModule.h
index 7c180439cf..4caf8ed3ce 100644
--- a/cpp/src/qpid/broker/AclModule.h
+++ b/cpp/src/qpid/broker/AclModule.h
@@ -78,7 +78,9 @@ namespace acl {
PROP_SCHEMACLASS,
PROP_POLICYTYPE,
PROP_MAXQUEUESIZE,
- PROP_MAXQUEUECOUNT };
+ PROP_MAXQUEUECOUNT,
+ PROPERTYSIZE // PROPERTYSIZE must be last in list
+ };
// Property used in ACL spec file
// Note for properties common to file processing/rule storage and to
@@ -145,6 +147,10 @@ namespace broker {
*/
virtual bool approveConnection (const Connection& connection)=0;
+ /** Change connection's counted userId
+ */
+ virtual void setUserId(const Connection& connection, const std::string& username)=0;
+
virtual ~AclModule() {};
};
} // namespace broker
diff --git a/cpp/src/qpid/broker/AsyncCompletion.h b/cpp/src/qpid/broker/AsyncCompletion.h
index fef994438f..0cf2856584 100644
--- a/cpp/src/qpid/broker/AsyncCompletion.h
+++ b/cpp/src/qpid/broker/AsyncCompletion.h
@@ -22,6 +22,7 @@
*
*/
+#include "qpid/RefCounted.h"
#include <boost/intrusive_ptr.hpp>
#include "qpid/broker/BrokerImportExport.h"
@@ -77,7 +78,7 @@ namespace broker {
* assuming no need for synchronization with Completer threads.
*/
-class AsyncCompletion
+class AsyncCompletion : public virtual RefCounted
{
public:
diff --git a/cpp/src/qpid/broker/Broker.cpp b/cpp/src/qpid/broker/Broker.cpp
index b763dd4119..2411e0520c 100644
--- a/cpp/src/qpid/broker/Broker.cpp
+++ b/cpp/src/qpid/broker/Broker.cpp
@@ -33,6 +33,7 @@
#include "qpid/broker/Link.h"
#include "qpid/broker/ExpiryPolicy.h"
#include "qpid/broker/QueueFlowLimit.h"
+#include "qpid/broker/QueueSettings.h"
#include "qpid/broker/MessageGroupManager.h"
#include "qmf/org/apache/qpid/broker/Package.h"
@@ -120,7 +121,6 @@ Broker::Options::Options(const std::string& name) :
queueLimit(100*1048576/*100M default limit*/),
tcpNoDelay(false),
requireEncrypted(false),
- asyncQueueEvents(false), // Must be false in a cluster.
qmf2Support(true),
qmf1Support(true),
queueFlowStopRatio(80),
@@ -164,7 +164,6 @@ Broker::Options::Options(const std::string& name) :
("require-encryption", optValue(requireEncrypted), "Only accept connections that are encrypted")
("known-hosts-url", optValue(knownHosts, "URL or 'none'"), "URL to send as 'known-hosts' to clients ('none' implies empty list)")
("sasl-config", optValue(saslConfigPath, "DIR"), "gets sasl config info from nonstandard location")
- ("async-queue-events", optValue(asyncQueueEvents, "yes|no"), "Set Queue Events async, used for services like replication")
("default-flow-stop-threshold", optValue(queueFlowStopRatio, "PERCENT"), "Percent of queue's maximum capacity at which flow control is activated.")
("default-flow-resume-threshold", optValue(queueFlowResumeRatio, "PERCENT"), "Percent of queue's maximum capacity at which flow control is de-activated.")
("default-event-threshold-ratio", optValue(queueThresholdEventRatio, "%age of limit"), "The ratio of any specified queue limit at which an event will be raised")
@@ -206,7 +205,6 @@ Broker::Broker(const Broker::Options& conf) :
*this),
mgmtObject(0),
queueCleaner(queues, &timer),
- queueEvents(poller,!conf.asyncQueueEvents),
recovery(true),
inCluster(false),
clusterUpdatee(false),
@@ -265,8 +263,6 @@ Broker::Broker(const Broker::Options& conf) :
federationTag = conf.fedTag;
}
- QueuePolicy::setDefaultMaxSize(conf.queueLimit);
-
// Early-Initialize plugins
Plugin::earlyInitAll(*this);
@@ -430,7 +426,6 @@ void Broker::shutdown() {
Broker::~Broker() {
shutdown();
- queueEvents.shutdown();
finalize(); // Finalize any plugins.
if (config.auth)
SaslAuthenticator::fini();
@@ -694,11 +689,15 @@ void Broker::createObject(const std::string& type, const std::string& name,
//treat everything else as extension properties
else extensions[i->first] = i->second;
}
- framing::FieldTable arguments;
- amqp_0_10::translate(extensions, arguments);
+ QueueSettings settings(durable, autodelete);
+ Variant::Map unused;
+ settings.populate(extensions, unused);
+ qpid::amqp_0_10::translate(unused, settings.storeSettings);
+ //TODO: unused doesn't take store settings into account... so can't yet implement strict
+ QPID_LOG(debug, "Broker did not use the following settings (store module may): " << unused);
std::pair<boost::shared_ptr<Queue>, bool> result =
- createQueue(name, durable, autodelete, 0, alternateExchange, arguments, userId, connectionId);
+ createQueue(name, settings, 0, alternateExchange, userId, connectionId);
if (!result.second) {
throw ObjectAlreadyExists(name);
}
@@ -1046,8 +1045,7 @@ Broker::getKnownBrokersImpl()
return knownBrokers;
}
-bool Broker::deferDeliveryImpl(const std::string& ,
- const boost::intrusive_ptr<Message>& )
+bool Broker::deferDeliveryImpl(const std::string&, const Message&)
{ return false; }
void Broker::setClusterTimer(std::auto_ptr<sys::Timer> t) {
@@ -1061,23 +1059,21 @@ const std::string Broker::TCP_TRANSPORT("tcp");
std::pair<boost::shared_ptr<Queue>, bool> Broker::createQueue(
const std::string& name,
- bool durable,
- bool autodelete,
+ const QueueSettings& settings,
const OwnershipToken* owner,
const std::string& alternateExchange,
- const qpid::framing::FieldTable& arguments,
const std::string& userId,
const std::string& connectionId)
{
if (acl) {
std::map<acl::Property, std::string> params;
params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
- params.insert(make_pair(acl::PROP_DURABLE, durable ? _TRUE : _FALSE));
+ params.insert(make_pair(acl::PROP_DURABLE, settings.durable ? _TRUE : _FALSE));
params.insert(make_pair(acl::PROP_EXCLUSIVE, owner ? _TRUE : _FALSE));
- params.insert(make_pair(acl::PROP_AUTODELETE, autodelete ? _TRUE : _FALSE));
- params.insert(make_pair(acl::PROP_POLICYTYPE, arguments.getAsString("qpid.policy_type")));
- params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.max_count"))));
- params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.max_size"))));
+ params.insert(make_pair(acl::PROP_AUTODELETE, settings.autodelete ? _TRUE : _FALSE));
+ params.insert(make_pair(acl::PROP_POLICYTYPE, settings.dropMessagesAtLimit ? "ring" : "reject"));
+ params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(settings.maxDepth.getCount())));
+ params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(settings.maxDepth.getSize())));
if (!acl->authorise(userId,acl::ACT_CREATE,acl::OBJ_QUEUE,name,&params) )
throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied queue create request from " << userId));
@@ -1089,7 +1085,7 @@ std::pair<boost::shared_ptr<Queue>, bool> Broker::createQueue(
if (!alternate) throw framing::NotFoundException(QPID_MSG("Alternate exchange does not exist: " << alternateExchange));
}
- std::pair<Queue::shared_ptr, bool> result = queues.declare(name, durable, autodelete, owner, alternate, arguments);
+ std::pair<Queue::shared_ptr, bool> result = queues.declare(name, settings, alternate);
if (result.second) {
//add default binding:
result.first->bind(exchanges.getDefault(), name);
@@ -1100,16 +1096,16 @@ std::pair<boost::shared_ptr<Queue>, bool> Broker::createQueue(
//event instead?
managementAgent->raiseEvent(
_qmf::EventQueueDeclare(connectionId, userId, name,
- durable, owner, autodelete, alternateExchange,
- ManagementAgent::toMap(arguments),
+ settings.durable, owner, settings.autodelete, alternateExchange,
+ settings.asMap(),
"created"));
}
QPID_LOG_CAT(debug, model, "Create queue. name:" << name
<< " user:" << userId
<< " rhost:" << connectionId
- << " durable:" << (durable ? "T" : "F")
+ << " durable:" << (settings.durable ? "T" : "F")
<< " owner:" << owner
- << " autodelete:" << (autodelete ? "T" : "F")
+ << " autodelete:" << (settings.autodelete ? "T" : "F")
<< " alternateExchange:" << alternateExchange );
}
return result;
diff --git a/cpp/src/qpid/broker/Broker.h b/cpp/src/qpid/broker/Broker.h
index 922d0558e5..d1be0f58da 100644
--- a/cpp/src/qpid/broker/Broker.h
+++ b/cpp/src/qpid/broker/Broker.h
@@ -34,7 +34,6 @@
#include "qpid/broker/LinkRegistry.h"
#include "qpid/broker/SessionManager.h"
#include "qpid/broker/QueueCleaner.h"
-#include "qpid/broker/QueueEvents.h"
#include "qpid/broker/Vhost.h"
#include "qpid/broker/System.h"
#include "qpid/broker/ExpiryPolicy.h"
@@ -76,7 +75,7 @@ namespace broker {
class ConnectionState;
class ExpiryPolicy;
class Message;
-
+struct QueueSettings;
static const uint16_t DEFAULT_PORT=5672;
struct NoSuchTransportException : qpid::Exception
@@ -118,7 +117,6 @@ class Broker : public sys::Runnable, public Plugin::Target,
bool requireEncrypted;
std::string knownHosts;
std::string saslConfigPath;
- bool asyncQueueEvents;
bool qmf2Support;
bool qmf1Support;
uint queueFlowStopRatio; // producer flow control: on
@@ -178,11 +176,10 @@ class Broker : public sys::Runnable, public Plugin::Target,
Vhost::shared_ptr vhostObject;
System::shared_ptr systemObject;
QueueCleaner queueCleaner;
- QueueEvents queueEvents;
std::vector<Url> knownBrokers;
std::vector<Url> getKnownBrokersImpl();
bool deferDeliveryImpl(const std::string& queue,
- const boost::intrusive_ptr<Message>& msg);
+ const Message& msg);
std::string federationTag;
bool recovery;
bool inCluster, clusterUpdatee;
@@ -227,7 +224,6 @@ class Broker : public sys::Runnable, public Plugin::Target,
DtxManager& getDtxManager() { return dtxManager; }
DataDir& getDataDir() { return dataDir; }
Options& getOptions() { return config; }
- QueueEvents& getQueueEvents() { return queueEvents; }
void setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e) { expiryPolicy = e; }
boost::intrusive_ptr<ExpiryPolicy> getExpiryPolicy() { return expiryPolicy; }
@@ -309,7 +305,8 @@ class Broker : public sys::Runnable, public Plugin::Target,
* context.
*@return true if delivery of a message should be deferred.
*/
- boost::function<bool (const std::string& queue, const boost::intrusive_ptr<Message>& msg)> deferDelivery;
+ boost::function<bool (const std::string& queue,
+ const Message& msg)> deferDelivery;
bool isAuthenticating ( ) { return config.auth; }
bool isTimestamping() { return config.timestampRcvMsgs; }
@@ -318,11 +315,9 @@ class Broker : public sys::Runnable, public Plugin::Target,
QPID_BROKER_EXTERN std::pair<boost::shared_ptr<Queue>, bool> createQueue(
const std::string& name,
- bool durable,
- bool autodelete,
+ const QueueSettings& settings,
const OwnershipToken* owner,
const std::string& alternateExchange,
- const qpid::framing::FieldTable& arguments,
const std::string& userId,
const std::string& connectionId);
diff --git a/cpp/src/qpid/broker/Connection.cpp b/cpp/src/qpid/broker/Connection.cpp
index 8d250a32e5..e68c906cc2 100644
--- a/cpp/src/qpid/broker/Connection.cpp
+++ b/cpp/src/qpid/broker/Connection.cpp
@@ -25,6 +25,7 @@
#include "qpid/broker/Bridge.h"
#include "qpid/broker/Broker.h"
#include "qpid/broker/Queue.h"
+#include "qpid/broker/AclModule.h"
#include "qpid/sys/SecuritySettings.h"
#include "qpid/sys/ClusterSafe.h"
@@ -278,6 +279,13 @@ void Connection::notifyConnectionForced(const string& text)
void Connection::setUserId(const string& userId)
{
+ // Account for changing userId
+ AclModule* acl = broker.getAcl();
+ if (acl)
+ {
+ acl->setUserId(*this, userId);
+ }
+
ConnectionState::setUserId(userId);
// In a cluster, the cluster code will raise the connect event
// when the connection is replicated to the cluster.
diff --git a/cpp/src/qpid/broker/Consumer.h b/cpp/src/qpid/broker/Consumer.h
index 64073621be..64fc4288af 100644
--- a/cpp/src/qpid/broker/Consumer.h
+++ b/cpp/src/qpid/broker/Consumer.h
@@ -21,21 +21,23 @@
#ifndef _Consumer_
#define _Consumer_
-#include "qpid/broker/Message.h"
-#include "qpid/broker/QueuedMessage.h"
+#include "qpid/broker/QueueCursor.h"
#include "qpid/broker/OwnershipToken.h"
+#include <boost/shared_ptr.hpp>
+#include <string>
namespace qpid {
namespace broker {
+class DeliveryRecord;
+class Message;
class Queue;
class QueueListeners;
/**
* Base class for consumers which represent a subscription to a queue.
*/
-class Consumer
-{
+class Consumer : public QueueCursor {
const bool acquires;
// inListeners allows QueueListeners to efficiently track if this
// instance is registered for notifications without having to
@@ -47,22 +49,17 @@ class Consumer
public:
typedef boost::shared_ptr<Consumer> shared_ptr;
- Consumer(const std::string& _name, bool preAcquires = true)
- : acquires(preAcquires), inListeners(false), name(_name), position(0) {}
+ Consumer(const std::string& _name, SubscriptionType type)
+ : QueueCursor(type), acquires(type == CONSUMER), inListeners(false), name(_name) {}
virtual ~Consumer(){}
bool preAcquires() const { return acquires; }
const std::string& getName() const { return name; }
- /**@return the position of the last message seen by this consumer */
- virtual framing::SequenceNumber getPosition() const { return position; }
-
- virtual void setPosition(framing::SequenceNumber pos) { position = pos; }
-
- virtual bool deliver(QueuedMessage& msg) = 0;
+ virtual bool deliver(const QueueCursor& cursor, const Message& msg) = 0;
virtual void notify() = 0;
- virtual bool filter(boost::intrusive_ptr<Message>) { return true; }
- virtual bool accept(boost::intrusive_ptr<Message>) { return true; }
+ virtual bool filter(const Message&) { return true; }
+ virtual bool accept(const Message&) { return true; }
virtual OwnershipToken* getSession() = 0;
virtual void cancel() = 0;
@@ -75,7 +72,7 @@ class Consumer
* Not to be confused with accept() above, which is asking if
* this consumer will consume/browse the message.
*/
- virtual void acknowledged(const QueuedMessage&) = 0;
+ virtual void acknowledged(const DeliveryRecord&) = 0;
/** Called if queue has been deleted, if true suppress the error message.
* Used by HA ReplicatingSubscriptions where such errors are normal.
@@ -83,7 +80,7 @@ class Consumer
virtual bool hideDeletedError() { return false; }
protected:
- framing::SequenceNumber position;
+ //framing::SequenceNumber position;
private:
friend class QueueListeners;
diff --git a/cpp/src/qpid/broker/Deliverable.h b/cpp/src/qpid/broker/Deliverable.h
index ffb5a77bca..e08d0e1b20 100644
--- a/cpp/src/qpid/broker/Deliverable.h
+++ b/cpp/src/qpid/broker/Deliverable.h
@@ -21,17 +21,22 @@
#ifndef _Deliverable_
#define _Deliverable_
-#include "qpid/broker/Message.h"
+#include "qpid/broker/AsyncCompletion.h"
+#include "qpid/sys/IntegerTypes.h"
+#include <boost/shared_ptr.hpp>
namespace qpid {
namespace broker {
- class Deliverable{
+ class Message;
+ class Queue;
+
+ class Deliverable : public AsyncCompletion {
public:
bool delivered;
Deliverable() : delivered(false) {}
virtual Message& getMessage() = 0;
-
+
virtual void deliverTo(const boost::shared_ptr<Queue>& queue) = 0;
virtual uint64_t contentSize() { return 0; }
virtual ~Deliverable(){}
diff --git a/cpp/src/qpid/broker/DeliverableMessage.cpp b/cpp/src/qpid/broker/DeliverableMessage.cpp
index 3ebb12461c..be4b7f0796 100644
--- a/cpp/src/qpid/broker/DeliverableMessage.cpp
+++ b/cpp/src/qpid/broker/DeliverableMessage.cpp
@@ -24,22 +24,20 @@
using namespace qpid::broker;
-DeliverableMessage::DeliverableMessage(const boost::intrusive_ptr<Message>& _msg) : msg(_msg)
-{
-}
+DeliverableMessage::DeliverableMessage(const Message& _msg, TxBuffer* _txn) : msg(_msg), txn(_txn) {}
void DeliverableMessage::deliverTo(const boost::shared_ptr<Queue>& queue)
{
- queue->deliver(msg);
+ queue->deliver(msg, txn);
delivered = true;
}
Message& DeliverableMessage::getMessage()
{
- return *msg;
+ return msg;
}
-uint64_t DeliverableMessage::contentSize ()
+uint64_t DeliverableMessage::contentSize()
{
- return msg->contentSize ();
+ return msg.getContentSize();
}
diff --git a/cpp/src/qpid/broker/DeliverableMessage.h b/cpp/src/qpid/broker/DeliverableMessage.h
index c8d21001eb..d6d6bf5265 100644
--- a/cpp/src/qpid/broker/DeliverableMessage.h
+++ b/cpp/src/qpid/broker/DeliverableMessage.h
@@ -25,14 +25,15 @@
#include "qpid/broker/Deliverable.h"
#include "qpid/broker/Message.h"
-#include <boost/intrusive_ptr.hpp>
-
namespace qpid {
namespace broker {
- class QPID_BROKER_CLASS_EXTERN DeliverableMessage : public Deliverable{
- boost::intrusive_ptr<Message> msg;
+ class TxBuffer;
+ class QPID_BROKER_CLASS_EXTERN DeliverableMessage : public Deliverable
+ {
+ Message msg;
+ TxBuffer* txn;
public:
- QPID_BROKER_EXTERN DeliverableMessage(const boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN DeliverableMessage(const Message& msg, TxBuffer* txn);
QPID_BROKER_EXTERN virtual void deliverTo(const boost::shared_ptr<Queue>& queue);
QPID_BROKER_EXTERN Message& getMessage();
QPID_BROKER_EXTERN uint64_t contentSize();
diff --git a/cpp/src/qpid/broker/DeliveryAdapter.h b/cpp/src/qpid/broker/DeliveryAdapter.h
index b0bec60890..e69de29bb2 100644
--- a/cpp/src/qpid/broker/DeliveryAdapter.h
+++ b/cpp/src/qpid/broker/DeliveryAdapter.h
@@ -1,53 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _DeliveryAdapter_
-#define _DeliveryAdapter_
-
-#include "qpid/broker/DeliveryId.h"
-#include "qpid/broker/Message.h"
-#include "qpid/framing/amqp_types.h"
-
-namespace qpid {
-namespace broker {
-
-class DeliveryRecord;
-
-/**
- * The intention behind this interface is to separate the generic
- * handling of some form of message delivery to clients that is
- * contained in the version independent Channel class from the
- * details required for a particular situation or
- * version. i.e. where the existing adapters allow (through
- * supporting the generated interface for a version of the
- * protocol) inputs of a channel to be adapted to the version
- * independent part, this does the same for the outputs.
- */
-class DeliveryAdapter
-{
- public:
- virtual void deliver(DeliveryRecord&, bool sync) = 0;
- virtual ~DeliveryAdapter(){}
-};
-
-}}
-
-
-#endif
diff --git a/cpp/src/qpid/broker/DeliveryRecord.cpp b/cpp/src/qpid/broker/DeliveryRecord.cpp
index 5d6aee9045..f547ee54c9 100644
--- a/cpp/src/qpid/broker/DeliveryRecord.cpp
+++ b/cpp/src/qpid/broker/DeliveryRecord.cpp
@@ -24,6 +24,7 @@
#include "qpid/broker/Consumer.h"
#include "qpid/broker/Exchange.h"
#include "qpid/broker/Queue.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/log/Statement.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/MessageTransferBody.h"
@@ -32,77 +33,46 @@ using namespace qpid;
using namespace qpid::broker;
using std::string;
-DeliveryRecord::DeliveryRecord(const QueuedMessage& _msg,
+DeliveryRecord::DeliveryRecord(const QueueCursor& _msg,
+ framing::SequenceNumber _msgId,
const Queue::shared_ptr& _queue,
const std::string& _tag,
const boost::shared_ptr<Consumer>& _consumer,
bool _acquired,
bool accepted,
bool _windowing,
- uint32_t _credit):
- msg(_msg),
- queue(_queue),
- tag(_tag),
- consumer(_consumer),
- acquired(_acquired),
- acceptExpected(!accepted),
- cancelled(false),
- completed(false),
- ended(accepted && acquired),
- windowing(_windowing),
- credit(msg.payload ? msg.payload->getRequiredCredit() : _credit)
+ uint32_t _credit) : msg(_msg),
+ queue(_queue),
+ tag(_tag),
+ consumer(_consumer),
+ acquired(_acquired),
+ acceptExpected(!accepted),
+ cancelled(false),
+ completed(false),
+ ended(accepted && acquired),
+ windowing(_windowing),
+ credit(_credit),
+ msgId(_msgId)
{}
bool DeliveryRecord::setEnded()
{
ended = true;
- //reset msg pointer, don't need to hold on to it anymore
- msg.payload = boost::intrusive_ptr<Message>();
QPID_LOG(debug, "DeliveryRecord::setEnded() id=" << id);
return isRedundant();
}
-void DeliveryRecord::redeliver(SemanticState* const session) {
- if (!ended) {
- if(cancelled){
- //if subscription was cancelled, requeue it (waiting for
- //final confirmation for AMQP WG on this case)
- requeue();
- }else{
- msg.payload->redeliver();//mark as redelivered
- session->deliver(*this, false);
- }
- }
-}
-
-void DeliveryRecord::deliver(framing::FrameHandler& h, DeliveryId deliveryId, uint16_t framesize)
-{
- id = deliveryId;
- if (msg.payload->getRedelivered()){
- msg.payload->setRedelivered();
- }
- msg.payload->adjustTtl();
-
- framing::AMQFrame method((framing::MessageTransferBody(framing::ProtocolVersion(), tag, acceptExpected ? 0 : 1, acquired ? 0 : 1)));
- method.setEof(false);
- h.handle(method);
- msg.payload->sendHeader(h, framesize);
- msg.payload->sendContent(*queue, h, framesize);
-}
-
-void DeliveryRecord::requeue() const
+void DeliveryRecord::requeue()
{
if (acquired && !ended) {
- msg.payload->redeliver();
- queue->requeue(msg);
+ queue->release(msg);
}
}
void DeliveryRecord::release(bool setRedelivered)
{
if (acquired && !ended) {
- if (setRedelivered) msg.payload->redeliver();
- queue->requeue(msg);
+ queue->release(msg, setRedelivered);
acquired = false;
setEnded();
} else {
@@ -110,13 +80,14 @@ void DeliveryRecord::release(bool setRedelivered)
}
}
-void DeliveryRecord::complete() {
+void DeliveryRecord::complete()
+{
completed = true;
}
bool DeliveryRecord::accept(TransactionContext* ctxt) {
if (!ended) {
- if (consumer) consumer->acknowledged(getMessage());
+ if (consumer) consumer->acknowledged(*this);
if (acquired) queue->dequeue(ctxt, msg);
setEnded();
QPID_LOG(debug, "Accepted " << id);
@@ -124,31 +95,22 @@ bool DeliveryRecord::accept(TransactionContext* ctxt) {
return isRedundant();
}
-void DeliveryRecord::dequeue(TransactionContext* ctxt) const{
+void DeliveryRecord::dequeue(TransactionContext* ctxt) const
+{
if (acquired && !ended) {
queue->dequeue(ctxt, msg);
}
}
-void DeliveryRecord::committed() const{
+void DeliveryRecord::committed() const
+{
queue->dequeueCommitted(msg);
}
void DeliveryRecord::reject()
{
if (acquired && !ended) {
- Exchange::shared_ptr alternate = queue->getAlternateExchange();
- if (alternate) {
- DeliverableMessage delivery(msg.payload);
- alternate->routeWithAlternate(delivery);
- QPID_LOG(info, "Routed rejected message from " << queue->getName() << " to "
- << alternate->getName());
- } else {
- //just drop it
- QPID_LOG(info, "Dropping rejected message from " << queue->getName());
- }
- queue->countRejected();
- dequeue();
+ queue->reject(msg);
setEnded();
}
}
diff --git a/cpp/src/qpid/broker/DeliveryRecord.h b/cpp/src/qpid/broker/DeliveryRecord.h
index 21074d4274..10436f3fa0 100644
--- a/cpp/src/qpid/broker/DeliveryRecord.h
+++ b/cpp/src/qpid/broker/DeliveryRecord.h
@@ -26,15 +26,17 @@
#include <deque>
#include <vector>
#include <ostream>
+#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/SequenceSet.h"
#include "qpid/broker/BrokerImportExport.h"
-#include "qpid/broker/QueuedMessage.h"
+#include "qpid/broker/QueueCursor.h"
#include "qpid/broker/DeliveryId.h"
#include "qpid/broker/Message.h"
namespace qpid {
namespace broker {
+class Queue;
class TransactionContext;
class SemanticState;
struct AckRange;
@@ -45,7 +47,7 @@ class Consumer;
*/
class DeliveryRecord
{
- QueuedMessage msg;
+ QueueCursor msg;
mutable boost::shared_ptr<Queue> queue;
std::string tag; // name of consumer
boost::shared_ptr<Consumer> consumer;
@@ -65,9 +67,10 @@ class DeliveryRecord
* after that).
*/
uint32_t credit;
+ framing::SequenceNumber msgId;
public:
- QPID_BROKER_EXTERN DeliveryRecord(const QueuedMessage& msg,
+ QPID_BROKER_EXTERN DeliveryRecord(const QueueCursor& msgCursor, framing::SequenceNumber msgId,
const boost::shared_ptr<Queue>& queue,
const std::string& tag,
const boost::shared_ptr<Consumer>& consumer,
@@ -80,11 +83,10 @@ class DeliveryRecord
bool coveredBy(const framing::SequenceSet* const range) const { return range->contains(id); }
void dequeue(TransactionContext* ctxt = 0) const;
- void requeue() const;
+ void requeue();
void release(bool setRedelivered);
void reject();
void cancel(const std::string& tag);
- void redeliver(SemanticState* const);
void acquire(DeliveryIds& results);
void complete();
bool accept(TransactionContext* ctxt); // Returns isRedundant()
@@ -102,13 +104,13 @@ class DeliveryRecord
uint32_t getCredit() const;
const std::string& getTag() const { return tag; }
- void deliver(framing::FrameHandler& h, DeliveryId deliveryId, uint16_t framesize);
void setId(DeliveryId _id) { id = _id; }
typedef std::deque<DeliveryRecord> DeliveryRecords;
static AckRange findRange(DeliveryRecords& records, DeliveryId first, DeliveryId last);
- const QueuedMessage& getMessage() const { return msg; }
+ const QueueCursor& getMessage() const { return msg; }
framing::SequenceNumber getId() const { return id; }
+ framing::SequenceNumber getMessageId() const { return msgId; }
boost::shared_ptr<Queue> getQueue() const { return queue; }
friend std::ostream& operator<<(std::ostream&, const DeliveryRecord&);
diff --git a/cpp/src/qpid/broker/DtxAck.h b/cpp/src/qpid/broker/DtxAck.h
index 16c3ff8ba0..10d63f5b0c 100644
--- a/cpp/src/qpid/broker/DtxAck.h
+++ b/cpp/src/qpid/broker/DtxAck.h
@@ -40,7 +40,6 @@ class DtxAck : public TxOp{
virtual void commit() throw();
virtual void rollback() throw();
virtual ~DtxAck(){}
- virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
const DeliveryRecords& getPending() const { return pending; }
};
diff --git a/cpp/src/qpid/broker/Exchange.cpp b/cpp/src/qpid/broker/Exchange.cpp
index 82d4b4df15..bb5dc2b807 100644
--- a/cpp/src/qpid/broker/Exchange.cpp
+++ b/cpp/src/qpid/broker/Exchange.cpp
@@ -25,6 +25,7 @@
#include "qpid/broker/ExchangeRegistry.h"
#include "qpid/broker/FedOps.h"
#include "qpid/broker/Queue.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/framing/MessageProperties.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/log/Statement.h"
@@ -62,10 +63,10 @@ Exchange::PreRoute::PreRoute(Deliverable& msg, Exchange* _p):parent(_p) {
if (parent->sequence){
parent->sequenceNo++;
- msg.getMessage().insertCustomProperty(qpidMsgSequence,parent->sequenceNo);
+ msg.getMessage().addAnnotation(qpidMsgSequence,parent->sequenceNo);
}
if (parent->ive) {
- parent->lastMsg = &( msg.getMessage());
+ parent->lastMsg = msg.getMessage();
}
}
}
@@ -111,12 +112,6 @@ void Exchange::doRoute(Deliverable& msg, ConstBindingList b)
int count = 0;
if (b.get()) {
- // Block the content release if the message is transient AND there is more than one binding
- if (!msg.getMessage().isPersistent() && b->size() > 1) {
- msg.getMessage().blockContentRelease();
- }
-
-
ExInfo error(getName()); // Save exception to throw at the end.
for(std::vector<Binding::shared_ptr>::const_iterator i = b->begin(); i != b->end(); i++, count++) {
try {
@@ -161,8 +156,8 @@ void Exchange::doRoute(Deliverable& msg, ConstBindingList b)
}
void Exchange::routeIVE(){
- if (ive && lastMsg.get()){
- DeliverableMessage dmsg(lastMsg);
+ if (ive && lastMsg){
+ DeliverableMessage dmsg(lastMsg, 0);
route(dmsg);
}
}
@@ -400,9 +395,9 @@ bool Exchange::MatchQueue::operator()(Exchange::Binding::shared_ptr b)
return b->queue == queue;
}
-void Exchange::setProperties(const boost::intrusive_ptr<Message>& msg) {
- msg->setExchange(getName());
-}
+//void Exchange::setProperties(Message& msg) {
+// qpid::broker::amqp_0_10::MessageTransfer::setExchange(msg, getName());
+//}
bool Exchange::routeWithAlternate(Deliverable& msg)
{
diff --git a/cpp/src/qpid/broker/Exchange.h b/cpp/src/qpid/broker/Exchange.h
index fba752210f..2b2f7db934 100644
--- a/cpp/src/qpid/broker/Exchange.h
+++ b/cpp/src/qpid/broker/Exchange.h
@@ -25,6 +25,7 @@
#include <boost/shared_ptr.hpp>
#include "qpid/broker/BrokerImportExport.h"
#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/Message.h"
#include "qpid/broker/MessageStore.h"
#include "qpid/broker/PersistableExchange.h"
#include "qpid/framing/FieldTable.h"
@@ -74,7 +75,7 @@ protected:
mutable qpid::sys::Mutex sequenceLock;
int64_t sequenceNo;
bool ive;
- boost::intrusive_ptr<Message> lastMsg;
+ Message lastMsg;
class PreRoute{
public:
@@ -196,7 +197,7 @@ public:
virtual bool bind(boost::shared_ptr<Queue> queue, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
virtual bool unbind(boost::shared_ptr<Queue> queue, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
virtual bool isBound(boost::shared_ptr<Queue> queue, const std::string* const routingKey, const qpid::framing::FieldTable* const args) = 0;
- QPID_BROKER_EXTERN virtual void setProperties(const boost::intrusive_ptr<Message>&);
+ //QPID_BROKER_EXTERN virtual void setProperties(Message&);
virtual void route(Deliverable& msg) = 0;
//PersistableExchange:
diff --git a/cpp/src/qpid/broker/ExpiryPolicy.cpp b/cpp/src/qpid/broker/ExpiryPolicy.cpp
index 62cb3fc116..687eac7817 100644
--- a/cpp/src/qpid/broker/ExpiryPolicy.cpp
+++ b/cpp/src/qpid/broker/ExpiryPolicy.cpp
@@ -27,7 +27,7 @@ namespace broker {
ExpiryPolicy::~ExpiryPolicy() {}
-bool ExpiryPolicy::hasExpired(Message& m) {
+bool ExpiryPolicy::hasExpired(const Message& m) {
return m.getExpiration() < sys::AbsTime::now();
}
diff --git a/cpp/src/qpid/broker/ExpiryPolicy.h b/cpp/src/qpid/broker/ExpiryPolicy.h
index 2caf00ce00..1fb41ccd29 100644
--- a/cpp/src/qpid/broker/ExpiryPolicy.h
+++ b/cpp/src/qpid/broker/ExpiryPolicy.h
@@ -42,7 +42,7 @@ class QPID_BROKER_CLASS_EXTERN ExpiryPolicy : public RefCounted
{
public:
QPID_BROKER_EXTERN virtual ~ExpiryPolicy();
- QPID_BROKER_EXTERN virtual bool hasExpired(Message&);
+ QPID_BROKER_EXTERN virtual bool hasExpired(const Message&);
QPID_BROKER_EXTERN virtual qpid::sys::AbsTime getCurrentTime();
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Fairshare.cpp b/cpp/src/qpid/broker/Fairshare.cpp
index 7cdad1a44f..ec8ae9a037 100644
--- a/cpp/src/qpid/broker/Fairshare.cpp
+++ b/cpp/src/qpid/broker/Fairshare.cpp
@@ -19,7 +19,8 @@
*
*/
#include "qpid/broker/Fairshare.h"
-#include "qpid/broker/QueuedMessage.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/QueueSettings.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/framing/FieldValue.h"
#include "qpid/log/Statement.h"
@@ -83,17 +84,6 @@ bool Fairshare::setState(uint p, uint c)
return true;
}
-bool Fairshare::findFrontLevel(uint& p, PriorityLevels& messages)
-{
- const uint start = p = currentLevel();
- do {
- if (!messages[p].empty()) return true;
- } while ((p = nextLevel()) != start);
- return false;
-}
-
-
-
bool Fairshare::getState(const Messages& m, uint& priority, uint& count)
{
const Fairshare* fairshare = dynamic_cast<const Fairshare*>(&m);
@@ -106,82 +96,30 @@ bool Fairshare::setState(Messages& m, uint priority, uint count)
return fairshare && fairshare->setState(priority, count);
}
-int getIntegerSetting(const qpid::framing::FieldTable& settings, const std::vector<std::string>& keys)
-{
- qpid::framing::FieldTable::ValuePtr v;
- std::vector<std::string>::const_iterator i = keys.begin();
- while (!v && i != keys.end()) {
- v = settings.get(*i++);
- }
-
- if (!v) {
- return 0;
- } else if (v->convertsTo<int>()) {
- return v->get<int>();
- } else if (v->convertsTo<std::string>()){
- std::string s = v->get<std::string>();
- try {
- return boost::lexical_cast<int>(s);
- } catch(const boost::bad_lexical_cast&) {
- QPID_LOG(warning, "Ignoring invalid integer value for " << *i << ": " << s);
- return 0;
- }
- } else {
- QPID_LOG(warning, "Ignoring invalid integer value for " << *i << ": " << *v);
- return 0;
- }
-}
-
-int getIntegerSettingForKey(const qpid::framing::FieldTable& settings, const std::string& key)
-{
- return getIntegerSetting(settings, boost::assign::list_of<std::string>(key));
-}
-
-int getSetting(const qpid::framing::FieldTable& settings, const std::vector<std::string>& keys, int minvalue, int maxvalue)
+PriorityQueue::Priority Fairshare::firstLevel()
{
- return std::max(minvalue,std::min(getIntegerSetting(settings, keys), maxvalue));
+ return Priority(currentLevel());
}
-std::auto_ptr<Fairshare> getFairshareForKey(const qpid::framing::FieldTable& settings, uint levels, const std::string& key)
+bool Fairshare::nextLevel(Priority& p)
{
- uint defaultLimit = getIntegerSettingForKey(settings, key);
- std::auto_ptr<Fairshare> fairshare(new Fairshare(levels, defaultLimit));
- for (uint i = 0; i < levels; i++) {
- std::string levelKey = (boost::format("%1%-%2%") % key % i).str();
- if(settings.isSet(levelKey)) {
- fairshare->setLimit(i, getIntegerSettingForKey(settings, levelKey));
- }
- }
- if (!fairshare->isNull()) {
- return fairshare;
+ int next = nextLevel();
+ if (next == p.start) {
+ return false;
} else {
- return std::auto_ptr<Fairshare>();
- }
-}
-
-std::auto_ptr<Fairshare> getFairshare(const qpid::framing::FieldTable& settings,
- uint levels,
- const std::vector<std::string>& keys)
-{
- std::auto_ptr<Fairshare> fairshare;
- for (std::vector<std::string>::const_iterator i = keys.begin(); i != keys.end() && !fairshare.get(); ++i) {
- fairshare = getFairshareForKey(settings, levels, *i);
+ p.current = next;
+ return true;
}
- return fairshare;
}
-std::auto_ptr<Messages> Fairshare::create(const qpid::framing::FieldTable& settings)
+std::auto_ptr<Messages> Fairshare::create(const QueueSettings& settings)
{
- using boost::assign::list_of;
- std::auto_ptr<Messages> result;
- size_t levels = getSetting(settings, list_of<std::string>("qpid.priorities")("x-qpid-priorities"), 0, 100);
- if (levels) {
- std::auto_ptr<Fairshare> fairshare =
- getFairshare(settings, levels, list_of<std::string>("qpid.fairshare")("x-qpid-fairshare"));
- if (fairshare.get()) result = fairshare;
- else result = std::auto_ptr<Messages>(new PriorityQueue(levels));
+ std::auto_ptr<Fairshare> fairshare(new Fairshare(settings.priorities, settings.defaultFairshare));
+ for (uint i = 0; i < settings.priorities; i++) {
+ std::map<uint32_t,uint32_t>::const_iterator l = settings.fairshare.find(i);
+ if (l != settings.fairshare.end()) fairshare->setLimit(i, l->second);
}
- return result;
+ return std::auto_ptr<Messages>(fairshare.release());
}
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Fairshare.h b/cpp/src/qpid/broker/Fairshare.h
index 1b25721e0c..e7c8b04ecf 100644
--- a/cpp/src/qpid/broker/Fairshare.h
+++ b/cpp/src/qpid/broker/Fairshare.h
@@ -24,13 +24,11 @@
#include "qpid/broker/PriorityQueue.h"
namespace qpid {
-namespace framing {
-class FieldTable;
-}
namespace broker {
+struct QueueSettings;
/**
- * Modifies a basic prioirty queue by limiting the number of messages
+ * Modifies a basic priority queue by limiting the number of messages
* from each priority level that are dispatched before allowing
* dispatch from the next level.
*/
@@ -42,7 +40,7 @@ class Fairshare : public PriorityQueue
bool setState(uint priority, uint count);
void setLimit(size_t level, uint limit);
bool isNull();
- static std::auto_ptr<Messages> create(const qpid::framing::FieldTable& settings);
+ static std::auto_ptr<Messages> create(const QueueSettings& settings);
static bool getState(const Messages&, uint& priority, uint& count);
static bool setState(Messages&, uint priority, uint count);
private:
@@ -54,7 +52,8 @@ class Fairshare : public PriorityQueue
uint currentLevel();
uint nextLevel();
bool limitReached();
- bool findFrontLevel(uint& p, PriorityLevels&);
+ Priority firstLevel();
+ bool nextLevel(Priority& );
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/FifoDistributor.cpp b/cpp/src/qpid/broker/FifoDistributor.cpp
index c9ba894297..e1c0d268ce 100644
--- a/cpp/src/qpid/broker/FifoDistributor.cpp
+++ b/cpp/src/qpid/broker/FifoDistributor.cpp
@@ -28,21 +28,14 @@ using namespace qpid::broker;
FifoDistributor::FifoDistributor(Messages& container)
: messages(container) {}
-bool FifoDistributor::nextConsumableMessage( Consumer::shared_ptr&, QueuedMessage& next )
+bool FifoDistributor::acquire(const std::string&, Message& msg)
{
- return messages.consume(next);
-}
-
-bool FifoDistributor::allocate(const std::string&, const QueuedMessage& )
-{
- // by default, all messages present on the queue may be allocated as they have yet to
- // be acquired.
- return true;
-}
-
-bool FifoDistributor::nextBrowsableMessage( Consumer::shared_ptr& c, QueuedMessage& next )
-{
- return messages.browse(c->getPosition(), next, !c->browseAcquired());
+ if (msg.getState() == AVAILABLE) {
+ msg.setState(ACQUIRED);
+ return true;
+ } else {
+ return false;
+ }
}
void FifoDistributor::query(qpid::types::Variant::Map&) const
diff --git a/cpp/src/qpid/broker/FifoDistributor.h b/cpp/src/qpid/broker/FifoDistributor.h
index 245537ed12..aa5ebe28c5 100644
--- a/cpp/src/qpid/broker/FifoDistributor.h
+++ b/cpp/src/qpid/broker/FifoDistributor.h
@@ -38,15 +38,7 @@ class FifoDistributor : public MessageDistributor
public:
FifoDistributor(Messages& container);
- /** Locking Note: all methods assume the caller is holding the Queue::messageLock
- * during the method call.
- */
-
- /** MessageDistributor interface */
-
- bool nextConsumableMessage( Consumer::shared_ptr& consumer, QueuedMessage& next );
- bool allocate(const std::string& consumer, const QueuedMessage& target);
- bool nextBrowsableMessage( Consumer::shared_ptr& consumer, QueuedMessage& next );
+ bool acquire(const std::string& consumer, Message& target);
void query(qpid::types::Variant::Map&) const;
private:
diff --git a/cpp/src/qpid/broker/HeadersExchange.cpp b/cpp/src/qpid/broker/HeadersExchange.cpp
index 9975d26c72..02c05852ff 100644
--- a/cpp/src/qpid/broker/HeadersExchange.cpp
+++ b/cpp/src/qpid/broker/HeadersExchange.cpp
@@ -19,6 +19,7 @@
*
*/
#include "qpid/broker/HeadersExchange.h"
+#include "qpid/broker/MapHandler.h"
#include "qpid/framing/FieldValue.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/log/Statement.h"
@@ -55,6 +56,100 @@ namespace {
const std::string fedOpUnbind("U");
const std::string fedOpReorigin("R");
const std::string fedOpHello("H");
+
+std::string getMatch(const FieldTable* args)
+{
+ if (!args) {
+ throw InternalErrorException(QPID_MSG("No arguments given."));
+ }
+ FieldTable::ValuePtr what = args->get(x_match);
+ if (!what) {
+ return empty;
+ }
+ if (!what->convertsTo<std::string>()) {
+ throw InternalErrorException(QPID_MSG("Invalid x-match binding format to headers exchange. Must be a string [\"all\" or \"any\"]"));
+ }
+ return what->get<std::string>();
+}
+class Matcher : public MapHandler
+{
+ public:
+ Matcher(const FieldTable& b) : binding(b), matched(0) {}
+ void handleUint8(const MapHandler::CharSequence& key, uint8_t value) { processUint(std::string(key.data, key.size), value); }
+ void handleUint16(const MapHandler::CharSequence& key, uint16_t value) { processUint(std::string(key.data, key.size), value); }
+ void handleUint32(const MapHandler::CharSequence& key, uint32_t value) { processUint(std::string(key.data, key.size), value); }
+ void handleUint64(const MapHandler::CharSequence& key, uint64_t value) { processUint(std::string(key.data, key.size), value); }
+ void handleInt8(const MapHandler::CharSequence& key, int8_t value) { processInt(std::string(key.data, key.size), value); }
+ void handleInt16(const MapHandler::CharSequence& key, int16_t value) { processInt(std::string(key.data, key.size), value); }
+ void handleInt32(const MapHandler::CharSequence& key, int32_t value) { processInt(std::string(key.data, key.size), value); }
+ void handleInt64(const MapHandler::CharSequence& key, int64_t value) { processInt(std::string(key.data, key.size), value); }
+ void handleFloat(const MapHandler::CharSequence& key, float value) { processFloat(std::string(key.data, key.size), value); }
+ void handleDouble(const MapHandler::CharSequence& key, double value) { processFloat(std::string(key.data, key.size), value); }
+ void handleString(const MapHandler::CharSequence& key, const MapHandler::CharSequence& value, const MapHandler::CharSequence& /*encoding*/)
+ {
+ processString(std::string(key.data, key.size), std::string(value.data, value.size));
+ }
+ void handleVoid(const MapHandler::CharSequence& key)
+ {
+ valueCheckRequired(std::string(key.data, key.size));
+ }
+ bool matches()
+ {
+ std::string what = getMatch(&binding);
+ if (what == all) {
+ //must match all entries in the binding, except the match mode indicator
+ return matched == binding.size() - 1;
+ } else if (what == any) {
+ //match any of the entries in the binding
+ return matched > 0;
+ } else {
+ return false;
+ }
+ }
+ private:
+ bool valueCheckRequired(const std::string& key)
+ {
+ FieldTable::ValuePtr v = binding.get(key);
+ if (v) {
+ if (v->getType() == 0xf0/*VOID*/) {
+ ++matched;
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ void processString(const std::string& key, const std::string& actual)
+ {
+ if (valueCheckRequired(key) && binding.getAsString(key) == actual) {
+ ++matched;
+ }
+ }
+ void processFloat(const std::string& key, double actual)
+ {
+ double bound;
+ if (valueCheckRequired(key) && binding.getDouble(key, bound) && bound == actual) {
+ ++matched;
+ }
+ }
+ void processInt(const std::string& key, int64_t actual)
+ {
+ if (valueCheckRequired(key) && binding.getAsInt64(key) == actual) {
+ ++matched;
+ }
+ }
+ void processUint(const std::string& key, uint64_t actual)
+ {
+ if (valueCheckRequired(key) && binding.getAsUInt64(key) == actual) {
+ ++matched;
+ }
+ }
+ const FieldTable& binding;
+ size_t matched;
+};
}
HeadersExchange::HeadersExchange(const string& _name, Manageable* _parent, Broker* b) :
@@ -72,21 +167,6 @@ HeadersExchange::HeadersExchange(const std::string& _name, bool _durable,
mgmtExchange->set_type (typeName);
}
-std::string HeadersExchange::getMatch(const FieldTable* args)
-{
- if (!args) {
- throw InternalErrorException(QPID_MSG("No arguments given."));
- }
- FieldTable::ValuePtr what = args->get(x_match);
- if (!what) {
- return empty;
- }
- if (!what->convertsTo<std::string>()) {
- throw InternalErrorException(QPID_MSG("Invalid x-match binding format to headers exchange. Must be a string [\"all\" or \"any\"]"));
- }
- return what->get<std::string>();
-}
-
bool HeadersExchange::bind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable* args)
{
string fedOp(fedOpBind);
@@ -196,28 +276,16 @@ bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey,
void HeadersExchange::route(Deliverable& msg)
{
- const FieldTable* args = msg.getMessage().getApplicationHeaders();
- if (!args) {
- //can't match if there were no headers passed in
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgReceives();
- mgmtExchange->inc_byteReceives(msg.contentSize());
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- if (brokerMgmtObject)
- brokerMgmtObject->inc_discardsNoRoute();
- }
- return;
- }
-
PreRoute pr(msg, this);
BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >);
Bindings::ConstPtr p = bindings.snapshot();
if (p.get()) {
for (std::vector<BoundKey>::const_iterator i = p->begin(); i != p->end(); ++i) {
- if (match((*i).binding->args, *args)) {
- b->push_back((*i).binding);
+ Matcher matcher(i->binding->args);
+ msg.getMessage().processProperties(matcher);
+ if (matcher.matches()) {
+ b->push_back(i->binding);
}
}
}
diff --git a/cpp/src/qpid/broker/HeadersExchange.h b/cpp/src/qpid/broker/HeadersExchange.h
index d10892b9cc..2e4669a018 100644
--- a/cpp/src/qpid/broker/HeadersExchange.h
+++ b/cpp/src/qpid/broker/HeadersExchange.h
@@ -73,9 +73,6 @@ class HeadersExchange : public virtual Exchange {
Bindings bindings;
qpid::sys::Mutex lock;
-
- static std::string getMatch(const framing::FieldTable* args);
-
protected:
void getNonFedArgs(const framing::FieldTable* args,
framing::FieldTable& nonFedArgs);
diff --git a/cpp/src/qpid/broker/IndexedDeque.h b/cpp/src/qpid/broker/IndexedDeque.h
new file mode 100644
index 0000000000..229b4e3009
--- /dev/null
+++ b/cpp/src/qpid/broker/IndexedDeque.h
@@ -0,0 +1,226 @@
+#ifndef QPID_BROKER_INDEXEDDEQUE_H
+#define QPID_BROKER_INDEXEDDEQUE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Messages.h"
+#include "qpid/broker/QueueCursor.h"
+#include "qpid/log/Statement.h"
+#include <deque>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Template for a deque whose contents can be refered to by
+ * QueueCursor
+ */
+template <typename T> class IndexedDeque
+{
+ public:
+ typedef boost::function1<T, qpid::framing::SequenceNumber> Padding;
+ IndexedDeque(Padding p) : head(0), version(0), padding(p) {}
+
+ bool index(const QueueCursor& cursor, size_t& result)
+ {
+ return cursor.valid && index(qpid::framing::SequenceNumber(cursor.position + 1), result);
+ }
+
+ /**
+ * Finds the index for the message with the specified sequence number.
+ *
+ * @returns true if a message was found with the specified sequence,
+ * in which case the second parameter will be set to the index of that
+ * message; false if no message with that sequence exists, in which
+ * case the second parameter will be 0 if the sequence is less than
+ * that of the first message and non-zero if it is greater than that
+ * of the last message
+ */
+ bool index(const qpid::framing::SequenceNumber& position, size_t& i)
+ {
+ //assuming a monotonic sequence, with no messages removed except
+ //from the ends of the deque, we can use the position to determine
+ //an index into the deque
+ if (messages.size()) {
+ qpid::framing::SequenceNumber front(messages.front().getSequence());
+ if (position < front) {
+ i = 0;
+ } else {
+ i = position - front;
+ return i < messages.size();
+ }
+ }
+ return false;
+ }
+
+ bool deleted(const QueueCursor& cursor)
+ {
+ size_t i;
+ if (cursor.valid && index(cursor.position, i)) {
+ messages[i].setState(DELETED);
+ clean();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ T& publish(const T& added)
+ {
+ // QPID-4046: let producer help clean the backlog of deleted messages
+ clean();
+ //for ha replication, the queue can sometimes be reset by
+ //removing some of the more recent messages, in this case we
+ //need to ensure the DELETED records at the tail do not interfere with indexing
+ while (messages.size() && added.getSequence() <= messages.back().getSequence() && messages.back().getState() == DELETED)
+ messages.pop_back();
+ if (messages.size() && added.getSequence() <= messages.back().getSequence()) throw qpid::Exception(QPID_MSG("Index out of sequence!"));
+
+ //add padding to prevent gaps in sequence, which break the index
+ //calculation (needed for queue replication)
+ while (messages.size() && (added.getSequence() - messages.back().getSequence()) > 1)
+ messages.push_back(padding(messages.back().getSequence() + 1));
+
+ messages.push_back(added);
+ T& m = messages.back();
+ m.setState(AVAILABLE);
+ if (head >= messages.size()) head = messages.size() - 1;
+ QPID_LOG(debug, "Message " << &m << " published, state is " << m.getState() << " (head is now " << head << ")");
+ return m;
+ }
+
+ T* release(const QueueCursor& cursor)
+ {
+ size_t i;
+ if (cursor.valid && index(cursor.position, i)) {
+ messages[i].setState(AVAILABLE);
+ ++version;
+ QPID_LOG(debug, "Released message at position " << cursor.position << ", index " << i);
+ return &messages[i];
+ } else {
+ if (!cursor.valid) { QPID_LOG(debug, "Could not release message; cursor was invalid");}
+ else { QPID_LOG(debug, "Could not release message at position " << cursor.position); }
+ return 0;
+ }
+ }
+
+ bool reset(const QueueCursor& cursor)
+ {
+ return !cursor.valid || (cursor.type == CONSUMER && cursor.version != version);
+ }
+
+ T* next(QueueCursor& cursor)
+ {
+ size_t i = 0;
+ if (reset(cursor)) i = head; //start from head
+ else index(cursor, i); //get first message that is greater than position
+
+ if (cursor.valid) {
+ QPID_LOG(debug, "next() called for cursor at " << cursor.position << ", index set to " << i << " (of " << messages.size() << ")");
+ } else {
+ QPID_LOG(debug, "next() called for invalid cursor, index started at " << i << " (of " << messages.size() << ")");
+ }
+ while (i < messages.size()) {
+ T& m = messages[i++];
+ if (m.getState() == DELETED) continue;
+ cursor.setPosition(m.getSequence(), version);
+ QPID_LOG(debug, "in next(), cursor set to " << cursor.position);
+
+ if (cursor.check(m)) {
+ QPID_LOG(debug, "in next(), returning message at " << cursor.position);
+ return &m;
+ }
+ }
+ QPID_LOG(debug, "no message to return from next");
+ return 0;
+ }
+
+ size_t size()
+ {
+ size_t count(0);
+ for (size_t i = head; i < messages.size(); ++i) {
+ if (messages[i].getState() == AVAILABLE) ++count;
+ }
+ return count;
+ }
+
+ T* find(const qpid::framing::SequenceNumber& position, QueueCursor* cursor)
+ {
+ size_t i = 0;
+ if (index(position, i)){
+ T& m = messages[i];
+ if (cursor) cursor->setPosition(position, version);
+ if (m.getState() == AVAILABLE || m.getState() == ACQUIRED) {
+ return &m;
+ }
+ } else if (cursor) {
+ if (i >= messages.size()) cursor->setPosition(position, version);//haven't yet got a message with that seq no
+ else if (i == 0) cursor->valid = false;//reset
+ }
+ return 0;
+ }
+
+ T* find(const QueueCursor& cursor)
+ {
+ if (cursor.valid) return find(cursor.position, 0);
+ else return 0;
+ }
+
+ void clean()
+ {
+ // QPID-4046: If a queue has multiple consumers, then it is possible for a large
+ // collection of deleted messages to build up. Limit the number of messages cleaned
+ // up on each call to clean().
+ size_t count = 0;
+ while (messages.size() && messages.front().getState() == DELETED && count < 10) {
+ messages.pop_front();
+ count += 1;
+ }
+ head = (head > count) ? head - count : 0;
+ QPID_LOG(debug, "clean(): " << messages.size() << " messages remain; head is now " << head);
+ }
+
+ void foreach(Messages::Functor f)
+ {
+ for (typename Deque::iterator i = messages.begin(); i != messages.end(); ++i) {
+ if (i->getState() == AVAILABLE) {
+ f(*i);
+ }
+ }
+ clean();
+ }
+
+ void resetCursors()
+ {
+ ++version;
+ }
+
+ typedef std::deque<T> Deque;
+ Deque messages;
+ size_t head;
+ int32_t version;
+ Padding padding;
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_INDEXEDDEQUE_H*/
diff --git a/cpp/src/qpid/broker/LegacyLVQ.cpp b/cpp/src/qpid/broker/LegacyLVQ.cpp
index f1deddf4c8..e69de29bb2 100644
--- a/cpp/src/qpid/broker/LegacyLVQ.cpp
+++ b/cpp/src/qpid/broker/LegacyLVQ.cpp
@@ -1,127 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/broker/LegacyLVQ.h"
-#include "qpid/broker/Broker.h"
-#include "qpid/broker/QueuedMessage.h"
-
-namespace qpid {
-namespace broker {
-
-LegacyLVQ::LegacyLVQ(const std::string& k, bool b, Broker* br) : MessageMap(k), noBrowse(b), broker(br) {}
-
-void LegacyLVQ::setNoBrowse(bool b)
-{
- noBrowse = b;
-}
-bool LegacyLVQ::deleted(const QueuedMessage& message)
-{
- Ordering::iterator i = messages.find(message.position);
- if (i != messages.end() && i->second.payload == message.payload) {
- erase(i);
- return true;
- } else {
- return false;
- }
-}
-
-bool LegacyLVQ::acquire(const framing::SequenceNumber& position, QueuedMessage& message)
-{
- Ordering::iterator i = messages.find(position);
- if (i != messages.end() && i->second.payload == message.payload && i->second.status == QueuedMessage::AVAILABLE) {
- i->second.status = QueuedMessage::ACQUIRED;
- message = i->second;
- return true;
- } else {
- return false;
- }
-}
-
-bool LegacyLVQ::browse(const framing::SequenceNumber& position, QueuedMessage& message, bool unacquired)
-{
- if (MessageMap::browse(position, message, unacquired)) {
- if (!noBrowse) index.erase(getKey(message));
- return true;
- } else {
- return false;
- }
-}
-
-bool LegacyLVQ::push(const QueuedMessage& added, QueuedMessage& removed)
-{
- //Hack to disable LVQ behaviour on cluster update:
- if (broker && broker->isClusterUpdatee()) {
- messages[added.position] = added;
- return false;
- } else {
- return MessageMap::push(added, removed);
- }
-}
-
-const QueuedMessage& LegacyLVQ::replace(const QueuedMessage& original, const QueuedMessage& update)
-{
- //add the new message into the original position of the replaced message
- Ordering::iterator i = messages.find(original.position);
- if (i != messages.end()) {
- i->second = update;
- i->second.position = original.position;
- return i->second;
- } else {
- QPID_LOG(error, "Failed to replace message at " << original.position);
- return update;
- }
-}
-
-void LegacyLVQ::removeIf(Predicate p)
-{
- //Note: This method is currently called periodically on the timer
- //thread to expire messages. In a clustered broker this means that
- //the purging does not occur on the cluster event dispatch thread
- //and consequently that is not totally ordered w.r.t other events
- //(including publication of messages). The cluster does ensure
- //that the actual expiration of messages (as distinct from the
- //removing of those expired messages from the queue) *is*
- //consistently ordered w.r.t. cluster events. This means that
- //delivery of messages is in general consistent across the cluster
- //inspite of any non-determinism in the triggering of a
- //purge. However at present purging a last value queue (of the
- //legacy sort) could potentially cause inconsistencies in the
- //cluster (as the order w.r.t publications can affect the order in
- //which messages appear in the queue). Consequently periodic
- //purging of an LVQ is not enabled if the broker is clustered
- //(expired messages will be removed on delivery and consolidated
- //by key as part of normal LVQ operation).
- if (!broker || !broker->isInCluster())
- MessageMap::removeIf(p);
-}
-
-std::auto_ptr<Messages> LegacyLVQ::updateOrReplace(std::auto_ptr<Messages> current,
- const std::string& key, bool noBrowse, Broker* broker)
-{
- LegacyLVQ* lvq = dynamic_cast<LegacyLVQ*>(current.get());
- if (lvq) {
- lvq->setNoBrowse(noBrowse);
- return current;
- } else {
- return std::auto_ptr<Messages>(new LegacyLVQ(key, noBrowse, broker));
- }
-}
-
-}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/LegacyLVQ.h b/cpp/src/qpid/broker/LegacyLVQ.h
index 9355069f37..e69de29bb2 100644
--- a/cpp/src/qpid/broker/LegacyLVQ.h
+++ b/cpp/src/qpid/broker/LegacyLVQ.h
@@ -1,60 +0,0 @@
-#ifndef QPID_BROKER_LEGACYLVQ_H
-#define QPID_BROKER_LEGACYLVQ_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/broker/MessageMap.h"
-#include <memory>
-
-namespace qpid {
-namespace broker {
-class Broker;
-
-/**
- * This class encapsulates the behaviour of the old style LVQ where a
- * message replacing another messages for the given key will use the
- * position in the queue of the previous message. This however causes
- * problems for browsing. Either browsers stop the coalescing of
- * messages by key (default) or they may mis updates (if the no-browse
- * option is specified).
- */
-class LegacyLVQ : public MessageMap
-{
- public:
- LegacyLVQ(const std::string& key, bool noBrowse = false, Broker* broker = 0);
- bool deleted(const QueuedMessage&);
- bool acquire(const framing::SequenceNumber&, QueuedMessage&);
- bool browse(const framing::SequenceNumber&, QueuedMessage&, bool);
- bool push(const QueuedMessage& added, QueuedMessage& removed);
- void removeIf(Predicate);
- void setNoBrowse(bool);
- static std::auto_ptr<Messages> updateOrReplace(std::auto_ptr<Messages> current,
- const std::string& key, bool noBrowse,
- Broker* broker);
- protected:
- bool noBrowse;
- Broker* broker;
-
- const QueuedMessage& replace(const QueuedMessage&, const QueuedMessage&);
-};
-}} // namespace qpid::broker
-
-#endif /*!QPID_BROKER_LEGACYLVQ_H*/
diff --git a/cpp/src/qpid/broker/Link.cpp b/cpp/src/qpid/broker/Link.cpp
index 84dd163ac3..6479e47799 100644
--- a/cpp/src/qpid/broker/Link.cpp
+++ b/cpp/src/qpid/broker/Link.cpp
@@ -92,10 +92,10 @@ public:
// Process messages sent from the remote's amq.failover exchange by extracting the failover URLs
// and saving them should the Link need to reconnect.
- void route(broker::Deliverable& msg)
+ void route(broker::Deliverable& /*msg*/)
{
if (!link) return;
- const framing::FieldTable* headers = msg.getMessage().getApplicationHeaders();
+ const framing::FieldTable* headers = 0;//TODO: msg.getMessage().getApplicationHeaders();
framing::Array addresses;
if (headers && headers->getArray(FAILOVER_HEADER_KEY, addresses)) {
// convert the Array of addresses to a single Url container for used with setUrl():
diff --git a/cpp/src/qpid/broker/LinkRegistry.cpp b/cpp/src/qpid/broker/LinkRegistry.cpp
index 0507fe6521..6f813554fa 100644
--- a/cpp/src/qpid/broker/LinkRegistry.cpp
+++ b/cpp/src/qpid/broker/LinkRegistry.cpp
@@ -119,6 +119,7 @@ pair<Link::shared_ptr, bool> LinkRegistry::declare(const string& name,
parent, failover));
if (durable && store) store->create(*link);
links[name] = link;
+ pendingLinks[name] = link;
QPID_LOG(debug, "Creating new link; name=" << name );
return std::pair<Link::shared_ptr, bool>(link, true);
}
@@ -229,6 +230,7 @@ void LinkRegistry::linkDestroyed(Link *link)
QPID_LOG(debug, "LinkRegistry::destroy(); link= " << link->getName());
Mutex::ScopedLock locker(lock);
+ pendingLinks.erase(link->getName());
LinkMap::iterator i = links.find(link->getName());
if (i != links.end())
{
@@ -322,10 +324,12 @@ void LinkRegistry::notifyConnection(const std::string& key, Connection* c)
Link::shared_ptr link;
{
Mutex::ScopedLock locker(lock);
- for (LinkMap::iterator l = links.begin(); l != links.end(); ++l) {
+ for (LinkMap::iterator l = pendingLinks.begin(); l != pendingLinks.end(); ++l) {
if (l->second->pendingConnection(host, port)) {
link = l->second;
+ pendingLinks.erase(l);
connections[key] = link->getName();
+ QPID_LOG(debug, "LinkRegistry:: found pending =" << link->getName());
break;
}
}
@@ -347,6 +351,10 @@ void LinkRegistry::notifyClosed(const std::string& key)
{
Link::shared_ptr link = findLink(key);
if (link) {
+ {
+ Mutex::ScopedLock locker(lock);
+ pendingLinks[link->getName()] = link;
+ }
link->closed(0, "Closed by peer");
}
}
@@ -355,6 +363,10 @@ void LinkRegistry::notifyConnectionForced(const std::string& key, const std::str
{
Link::shared_ptr link = findLink(key);
if (link) {
+ {
+ Mutex::ScopedLock locker(lock);
+ pendingLinks[link->getName()] = link;
+ }
link->notifyConnectionForced(text);
}
}
diff --git a/cpp/src/qpid/broker/LinkRegistry.h b/cpp/src/qpid/broker/LinkRegistry.h
index 5a39b62bd1..076ab831c9 100644
--- a/cpp/src/qpid/broker/LinkRegistry.h
+++ b/cpp/src/qpid/broker/LinkRegistry.h
@@ -47,6 +47,7 @@ namespace broker {
LinkMap links; /** indexed by name of Link */
BridgeMap bridges; /** indexed by name of Bridge */
ConnectionMap connections; /** indexed by connection identifier, gives link name */
+ LinkMap pendingLinks; /** pending connection, indexed by name of Link */
qpid::sys::Mutex lock;
Broker* broker;
diff --git a/cpp/src/qpid/broker/LossyQueue.cpp b/cpp/src/qpid/broker/LossyQueue.cpp
new file mode 100644
index 0000000000..ee2c3ca794
--- /dev/null
+++ b/cpp/src/qpid/broker/LossyQueue.cpp
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "LossyQueue.h"
+#include "QueueDepth.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
+
+namespace qpid {
+namespace broker {
+
+namespace {
+bool isLowerPriorityThan(uint8_t priority, const Message& m)
+{
+ return m.getPriority() <= priority;
+}
+}
+
+LossyQueue::LossyQueue(const std::string& n, const QueueSettings& s, MessageStore* const ms, management::Manageable* p, Broker* b)
+ : Queue(n, s, ms, p, b) {}
+
+bool LossyQueue::checkDepth(const QueueDepth& increment, const Message& message)
+{
+ if (increment.getSize() > settings.maxDepth.getSize()) {
+ if (mgmtObject) {
+ mgmtObject->inc_discardsOverflow();
+ if (brokerMgmtObject)
+ brokerMgmtObject->inc_discardsOverflow();
+ }
+ throw qpid::framing::ResourceLimitExceededException(QPID_MSG("Message larger than configured maximum depth on "
+ << name << ": size=" << increment.getSize() << ", max-size=" << settings.maxDepth.getSize()));
+ }
+
+ while (settings.maxDepth && (current + increment > settings.maxDepth)) {
+ QPID_LOG(debug, "purging " << name << ": current depth is [" << current << "], max depth is [" << settings.maxDepth << "], new message has size " << increment.getSize());
+ qpid::sys::Mutex::ScopedUnlock u(messageLock);
+ //TODO: arguably we should try and purge expired messages first but that is potentially expensive
+ if (remove(1, settings.priorities ? boost::bind(&isLowerPriorityThan, message.getPriority(), _1) : MessagePredicate(), MessageFunctor(), PURGE)) {
+ if (mgmtObject) {
+ mgmtObject->inc_discardsRing(1);
+ if (brokerMgmtObject)
+ brokerMgmtObject->inc_discardsRing(1);
+ }
+ } else {
+ //should only be the case for a non-empty queue if we are
+ //testing priority and there was no lower (or equal)
+ //priority message available to purge
+ break;
+ }
+ }
+ if (settings.maxDepth && (current + increment > settings.maxDepth)) {
+ //will only be the case where we were unable to purge another
+ //message, which should only be the case if we are purging
+ //based on priority and there was no message with a lower (or
+ //equal) priority than this one, meaning that we drop this
+ //current message
+ if (mgmtObject) {
+ mgmtObject->inc_discardsRing(1);
+ if (brokerMgmtObject)
+ brokerMgmtObject->inc_discardsRing(1);
+ }
+ return false;
+ } else {
+ //have sufficient space for this message
+ current += increment;
+ return true;
+ }
+}
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/cluster/Quorum_null.h b/cpp/src/qpid/broker/LossyQueue.h
index dc27f0a43b..3e62151d6f 100644
--- a/cpp/src/qpid/cluster/Quorum_null.h
+++ b/cpp/src/qpid/broker/LossyQueue.h
@@ -1,5 +1,5 @@
-#ifndef QPID_CLUSTER_QUORUM_NULL_H
-#define QPID_CLUSTER_QUORUM_NULL_H
+#ifndef QPID_BROKER_LOSSYQUEUE_H
+#define QPID_BROKER_LOSSYQUEUE_H
/*
*
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,22 +21,21 @@
* under the License.
*
*/
-
-#include <boost/shared_ptr.hpp>
-#include <boost/function.hpp>
+#include "qpid/broker/Queue.h"
namespace qpid {
-namespace cluster {
-class Cluster;
+namespace broker {
-/** Null implementation of quorum. */
-
-class Quorum {
+/**
+ * Drops messages to prevent a breach of any configured maximum depth.
+ */
+class LossyQueue : public Queue
+{
public:
- Quorum(boost::function<void ()>) {}
- void start(boost::shared_ptr<sys::Poller>) {}
+ LossyQueue(const std::string&, const QueueSettings&, MessageStore* const, management::Manageable*, Broker*);
+ bool checkDepth(const QueueDepth& increment, const Message&);
+ private:
};
+}} // namespace qpid::broker
-#endif /*!QPID_CLUSTER_QUORUM_NULL_H*/
-
-}} // namespace qpid::cluster
+#endif /*!QPID_BROKER_LOSSYQUEUE_H*/
diff --git a/cpp/src/qpid/broker/Lvq.cpp b/cpp/src/qpid/broker/Lvq.cpp
new file mode 100644
index 0000000000..d053616c8a
--- /dev/null
+++ b/cpp/src/qpid/broker/Lvq.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "Lvq.h"
+#include "MessageMap.h"
+#include "qpid/sys/ClusterSafe.h"
+#include "qpid/sys/Monitor.h"
+
+namespace qpid {
+namespace broker {
+Lvq::Lvq(const std::string& n, std::auto_ptr<MessageMap> m, const QueueSettings& s, MessageStore* const ms, management::Manageable* p, Broker* b)
+ : Queue(n, s, ms, p, b), messageMap(*m)
+{
+ messages = m;
+}
+
+void Lvq::push(Message& message, bool isRecovery)
+{
+ qpid::sys::assertClusterSafe();
+ QueueListeners::NotificationSet copy;
+ Message old;
+ bool removed;
+ {
+ qpid::sys::Mutex::ScopedLock locker(messageLock);
+ message.setSequence(++sequence);
+ removed = messageMap.update(message, old);
+ listeners.populate(copy);
+ observeEnqueue(message, locker);
+ if (removed) {
+ if (mgmtObject) {
+ mgmtObject->inc_acquires();
+ mgmtObject->inc_discardsLvq();
+ if (brokerMgmtObject) {
+ brokerMgmtObject->inc_acquires();
+ brokerMgmtObject->inc_discardsLvq();
+ }
+ }
+ observeDequeue(old, locker);
+ }
+ }
+ copy.notify();
+ if (removed) {
+ if (isRecovery) pendingDequeues.push_back(old);
+ else dequeueFromStore(old.getPersistentContext());//do outside of lock
+ }
+}
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/cluster/ExpiryPolicy.h b/cpp/src/qpid/broker/Lvq.h
index d8ddbca8b3..335270a073 100644
--- a/cpp/src/qpid/cluster/ExpiryPolicy.h
+++ b/cpp/src/qpid/broker/Lvq.h
@@ -1,5 +1,5 @@
-#ifndef QPID_CLUSTER_EXPIRYPOLICY_H
-#define QPID_CLUSTER_EXPIRYPOLICY_H
+#ifndef QPID_BROKER_LVQ_H
+#define QPID_BROKER_LVQ_H
/*
*
@@ -10,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -21,39 +21,25 @@
* under the License.
*
*/
-
-#include "qpid/cluster/types.h"
-#include "qpid/broker/ExpiryPolicy.h"
-#include "qpid/sys/Mutex.h"
-#include <boost/function.hpp>
-#include <boost/intrusive_ptr.hpp>
-#include <boost/optional.hpp>
-#include <map>
+#include "qpid/broker/Queue.h"
namespace qpid {
-
namespace broker {
-class Message;
-}
-
-namespace cluster {
-class Cluster;
+class MessageMap;
/**
- * Cluster expiry policy
+ * Subclass of queue that handles last-value-queue semantics in
+ * conjunction with the MessageMap class. This requires an existing
+ * message to be 'replaced' by a newer message with the same key.
*/
-class ExpiryPolicy : public broker::ExpiryPolicy
+class Lvq : public Queue
{
public:
- ExpiryPolicy(Cluster& cluster);
-
- bool hasExpired(broker::Message&);
- qpid::sys::AbsTime getCurrentTime();
-
+ Lvq(const std::string&, std::auto_ptr<MessageMap>, const QueueSettings&, MessageStore* const, management::Manageable*, Broker*);
+ void push(Message& msg, bool isRecovery=false);
private:
- Cluster& cluster;
+ MessageMap& messageMap;
};
+}} // namespace qpid::broker
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_EXPIRYPOLICY_H*/
+#endif /*!QPID_BROKER_LVQ_H*/
diff --git a/cpp/src/qpid/broker/MapHandler.h b/cpp/src/qpid/broker/MapHandler.h
new file mode 100644
index 0000000000..200eba4f7a
--- /dev/null
+++ b/cpp/src/qpid/broker/MapHandler.h
@@ -0,0 +1,57 @@
+#ifndef QPID_BROKER_MAPHANDLER_H
+#define QPID_BROKER_MAPHANDLER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/sys/IntegerTypes.h"
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Interface for processing entries in some map-like object
+ */
+class MapHandler
+{
+ public:
+ typedef struct {
+ const char* data;
+ size_t size;
+ } CharSequence;
+
+ virtual ~MapHandler() {}
+ virtual void handleVoid(const CharSequence& key) = 0;
+ virtual void handleUint8(const CharSequence& key, uint8_t value) = 0;
+ virtual void handleUint16(const CharSequence& key, uint16_t value) = 0;
+ virtual void handleUint32(const CharSequence& key, uint32_t value) = 0;
+ virtual void handleUint64(const CharSequence& key, uint64_t value) = 0;
+ virtual void handleInt8(const CharSequence& key, int8_t value) = 0;
+ virtual void handleInt16(const CharSequence& key, int16_t value) = 0;
+ virtual void handleInt32(const CharSequence& key, int32_t value) = 0;
+ virtual void handleInt64(const CharSequence& key, int64_t value) = 0;
+ virtual void handleFloat(const CharSequence& key, float value) = 0;
+ virtual void handleDouble(const CharSequence& key, double value) = 0;
+ virtual void handleString(const CharSequence& key, const CharSequence& value, const CharSequence& encoding) = 0;
+ private:
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_MAPHANDLER_H*/
diff --git a/cpp/src/qpid/broker/Message.cpp b/cpp/src/qpid/broker/Message.cpp
index 4dd8a349dd..c48e9bcfa4 100644
--- a/cpp/src/qpid/broker/Message.cpp
+++ b/cpp/src/qpid/broker/Message.cpp
@@ -20,19 +20,12 @@
*/
#include "qpid/broker/Message.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/ExchangeRegistry.h"
-#include "qpid/broker/ExpiryPolicy.h"
+#include "qpid/broker/MapHandler.h"
#include "qpid/StringUtils.h"
-#include "qpid/framing/frame_functors.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/framing/SendContent.h"
-#include "qpid/framing/SequenceNumber.h"
-#include "qpid/framing/TypeFilter.h"
-#include "qpid/framing/reply_exceptions.h"
#include "qpid/log/Statement.h"
+#include <algorithm>
+#include <string.h>
#include <time.h>
using boost::intrusive_ptr;
@@ -41,492 +34,261 @@ using qpid::sys::Duration;
using qpid::sys::TIME_MSEC;
using qpid::sys::FAR_FUTURE;
using std::string;
-using namespace qpid::framing;
namespace qpid {
namespace broker {
-TransferAdapter Message::TRANSFER;
-
-Message::Message(const framing::SequenceNumber& id) :
- frames(id), persistenceId(0), redelivered(false), loaded(false),
- staged(false), forcePersistentPolicy(false), publisher(0), adapter(0),
- expiration(FAR_FUTURE), dequeueCallback(0),
- inCallback(false), requiredCredit(0), isManagementMessage(false), copyHeaderOnWrite(false)
-{}
-
-Message::~Message() {}
-
-void Message::forcePersistent()
+Message::Message() : deliveryCount(0), publisher(0), expiration(FAR_FUTURE), timestamp(0), isManagementMessage(false) {}
+Message::Message(boost::intrusive_ptr<Encoding> e, boost::intrusive_ptr<PersistableMessage> p)
+ : encoding(e), persistentContext(p), deliveryCount(0), publisher(0), expiration(FAR_FUTURE), timestamp(0), isManagementMessage(false)
{
- sys::Mutex::ScopedLock l(lock);
- // only set forced bit if we actually need to force.
- if (! getAdapter().isPersistent(frames) ){
- forcePersistentPolicy = true;
- }
+ if (persistentContext) persistentContext->setIngressCompletion(e);
}
+Message::~Message() {}
-bool Message::isForcedPersistent()
-{
- return forcePersistentPolicy;
-}
std::string Message::getRoutingKey() const
{
- return getAdapter().getRoutingKey(frames);
-}
-
-std::string Message::getExchangeName() const
-{
- return getAdapter().getExchange(frames);
-}
-
-const boost::shared_ptr<Exchange> Message::getExchange(ExchangeRegistry& registry) const
-{
- if (!exchange) {
- exchange = registry.get(getExchangeName());
- }
- return exchange;
-}
-
-bool Message::isImmediate() const
-{
- return getAdapter().isImmediate(frames);
-}
-
-const FieldTable* Message::getApplicationHeaders() const
-{
- sys::Mutex::ScopedLock l(lock);
- return getAdapter().getApplicationHeaders(frames);
-}
-
-std::string Message::getAppId() const
-{
- sys::Mutex::ScopedLock l(lock);
- return getAdapter().getAppId(frames);
+ return getEncoding().getRoutingKey();
}
bool Message::isPersistent() const
{
- sys::Mutex::ScopedLock l(lock);
- return (getAdapter().isPersistent(frames) || forcePersistentPolicy);
+ return getEncoding().isPersistent();
}
-bool Message::requiresAccept()
+uint64_t Message::getContentSize() const
{
- return getAdapter().requiresAccept(frames);
+ return getEncoding().getContentSize();
}
-uint32_t Message::getRequiredCredit()
+boost::intrusive_ptr<AsyncCompletion> Message::getIngressCompletion() const
{
- sys::Mutex::ScopedLock l(lock);
- if (!requiredCredit) {
- //add up payload for all header and content frames in the frameset
- SumBodySize sum;
- frames.map_if(sum, TypeFilter2<HEADER_BODY, CONTENT_BODY>());
- requiredCredit = sum.getSize();
- }
- return requiredCredit;
+ return encoding;
}
-void Message::encode(framing::Buffer& buffer) const
-{
- sys::Mutex::ScopedLock l(lock);
- //encode method and header frames
- EncodeFrame f1(buffer);
- frames.map_if(f1, TypeFilter2<METHOD_BODY, HEADER_BODY>());
-
- //then encode the payload of each content frame
- framing::EncodeBody f2(buffer);
- frames.map_if(f2, TypeFilter<CONTENT_BODY>());
-}
-
-void Message::encodeContent(framing::Buffer& buffer) const
-{
- sys::Mutex::ScopedLock l(lock);
- //encode the payload of each content frame
- EncodeBody f2(buffer);
- frames.map_if(f2, TypeFilter<CONTENT_BODY>());
-}
-
-uint32_t Message::encodedSize() const
-{
- return encodedHeaderSize() + encodedContentSize();
-}
-
-uint32_t Message::encodedContentSize() const
-{
- sys::Mutex::ScopedLock l(lock);
- return frames.getContentSize();
-}
-
-uint32_t Message::encodedHeaderSize() const
-{
- sys::Mutex::ScopedLock l(lock); // prevent modifications while computing size
- //add up the size for all method and header frames in the frameset
- SumFrameSize sum;
- frames.map_if(sum, TypeFilter2<METHOD_BODY, HEADER_BODY>());
- return sum.getSize();
-}
-
-void Message::decodeHeader(framing::Buffer& buffer)
+namespace
{
- AMQFrame method;
- method.decode(buffer);
- frames.append(method);
-
- AMQFrame header;
- header.decode(buffer);
- frames.append(header);
+const std::string X_QPID_TRACE("x-qpid.trace");
}
-void Message::decodeContent(framing::Buffer& buffer)
+bool Message::isExcluded(const std::vector<std::string>& excludes) const
{
- if (buffer.available()) {
- //get the data as a string and set that as the content
- //body on a frame then add that frame to the frameset
- AMQFrame frame((AMQContentBody()));
- frame.castBody<AMQContentBody>()->decode(buffer, buffer.available());
- frame.setFirstSegment(false);
- frames.append(frame);
- } else {
- //adjust header flags
- MarkLastSegment f;
- frames.map_if(f, TypeFilter<HEADER_BODY>());
+ std::string traceStr = getEncoding().getAnnotationAsString(X_QPID_TRACE);
+ if (traceStr.size()) {
+ std::vector<std::string> trace = split(traceStr, ", ");
+ for (std::vector<std::string>::const_iterator i = excludes.begin(); i != excludes.end(); i++) {
+ for (std::vector<std::string>::const_iterator j = trace.begin(); j != trace.end(); j++) {
+ if (*i == *j) {
+ return true;
+ }
+ }
+ }
}
- //mark content loaded
- loaded = true;
+ return false;
}
-// Used for testing only
-void Message::tryReleaseContent()
+void Message::addTraceId(const std::string& id)
{
- if (checkContentReleasable()) {
- releaseContent();
+ std::string trace = getEncoding().getAnnotationAsString(X_QPID_TRACE);
+ if (trace.empty()) {
+ annotations[X_QPID_TRACE] = id;
+ } else if (trace.find(id) == std::string::npos) {
+ trace += ",";
+ trace += id;
+ annotations[X_QPID_TRACE] = trace;
}
+ annotationsChanged();
}
-void Message::releaseContent(MessageStore* s)
+void Message::clearTrace()
{
- //deprecated, use setStore(store); releaseContent(); instead
- if (!store) setStore(s);
- releaseContent();
+ annotations[X_QPID_TRACE] = std::string();
+ annotationsChanged();
}
-void Message::releaseContent()
+void Message::setTimestamp()
{
- sys::Mutex::ScopedLock l(lock);
- if (store) {
- if (!getPersistenceId()) {
- intrusive_ptr<PersistableMessage> pmsg(this);
- store->stage(pmsg);
- staged = true;
- }
- //ensure required credit and size is cached before content frames are released
- getRequiredCredit();
- contentSize();
- //remove any content frames from the frameset
- frames.remove(TypeFilter<CONTENT_BODY>());
- setContentReleased();
- }
+ timestamp = ::time(0); // AMQP-0.10: posix time_t - secs since Epoch
}
-void Message::destroy()
+uint64_t Message::getTimestamp() const
{
- if (staged) {
- if (store) {
- store->destroy(*this);
- } else {
- QPID_LOG(error, "Message content was staged but no store is set so it can't be destroyed");
- }
- }
+ return timestamp;
}
-bool Message::getContentFrame(const Queue& queue, AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const
+uint64_t Message::getTtl() const
{
- intrusive_ptr<const PersistableMessage> pmsg(this);
-
- bool done = false;
- string& data = frame.castBody<AMQContentBody>()->getData();
- store->loadContent(queue, pmsg, data, offset, maxContentSize);
- done = data.size() < maxContentSize;
- frame.setBof(false);
- frame.setEof(true);
- QPID_LOG(debug, "loaded frame" << frame);
- if (offset > 0) {
- frame.setBos(false);
- }
- if (!done) {
- frame.setEos(false);
- } else return false;
- return true;
-}
-
-void Message::sendContent(const Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const
-{
- sys::Mutex::ScopedLock l(lock);
- if (isContentReleased() && !frames.isComplete()) {
- sys::Mutex::ScopedUnlock u(lock);
- uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead();
- bool morecontent = true;
- for (uint64_t offset = 0; morecontent; offset += maxContentSize)
- {
- AMQFrame frame((AMQContentBody()));
- morecontent = getContentFrame(queue, frame, maxContentSize, offset);
- out.handle(frame);
- }
- queue.countLoadedFromDisk(contentSize());
+ uint64_t ttl;
+ if (encoding->getTtl(ttl) && expiration < FAR_FUTURE) {
+ sys::AbsTime current(
+ expiryPolicy ? expiryPolicy->getCurrentTime() : sys::AbsTime::now());
+ sys::Duration ttl(current, getExpiration());
+ // convert from ns to ms; set to 1 if expired
+ return (int64_t(ttl) >= 1000000 ? int64_t(ttl)/1000000 : 1);
} else {
- Count c;
- frames.map_if(c, TypeFilter<CONTENT_BODY>());
-
- SendContent f(out, maxFrameSize, c.getCount());
- frames.map_if(f, TypeFilter<CONTENT_BODY>());
+ return 0;
}
}
-void Message::sendHeader(framing::FrameHandler& out, uint16_t /*maxFrameSize*/) const
-{
- sys::Mutex::ScopedLock l(lock);
- Relay f(out);
- frames.map_if(f, TypeFilter<HEADER_BODY>());
- //as frame (and pointer to body) has now been passed to handler,
- //subsequent modifications should use a copy
- copyHeaderOnWrite = true;
-}
-
-// TODO aconway 2007-11-09: Obsolete, remove. Was used to cover over
-// 0-8/0-9 message differences.
-MessageAdapter& Message::getAdapter() const
+void Message::computeExpiration(const boost::intrusive_ptr<ExpiryPolicy>& e)
{
- if (!adapter) {
- if(frames.isA<MessageTransferBody>()) {
- adapter = &TRANSFER;
- } else {
- const AMQMethodBody* method = frames.getMethod();
- if (!method) throw Exception("Can't adapt message with no method");
- else throw Exception(QPID_MSG("Can't adapt message based on " << *method));
+ //TODO: this is still quite 0-10 specific...
+ uint64_t ttl;
+ if (getEncoding().getTtl(ttl)) {
+ if (e) {
+ // Use higher resolution time for the internal expiry calculation.
+ // Prevent overflow as a signed int64_t
+ Duration duration(std::min(ttl * TIME_MSEC,
+ (uint64_t) std::numeric_limits<int64_t>::max()));
+ expiration = AbsTime(e->getCurrentTime(), duration);
+ setExpiryPolicy(e);
}
}
- return *adapter;
}
-uint64_t Message::contentSize() const
+void Message::addAnnotation(const std::string& key, const qpid::types::Variant& value)
{
- return frames.getContentSize();
+ annotations[key] = value;
+ annotationsChanged();
}
-bool Message::isContentLoaded() const
+void Message::annotationsChanged()
{
- return loaded;
+ if (persistentContext) {
+ persistentContext = persistentContext->merge(annotations);
+ persistentContext->setIngressCompletion(encoding);
+ }
}
-
-namespace
-{
-const std::string X_QPID_TRACE("x-qpid.trace");
+void Message::setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e) {
+ expiryPolicy = e;
}
-bool Message::isExcluded(const std::vector<std::string>& excludes) const
+bool Message::hasExpired() const
{
- sys::Mutex::ScopedLock l(lock);
- const FieldTable* headers = getApplicationHeaders();
- if (headers) {
- std::string traceStr = headers->getAsString(X_QPID_TRACE);
- if (traceStr.size()) {
- std::vector<std::string> trace = split(traceStr, ", ");
-
- for (std::vector<std::string>::const_iterator i = excludes.begin(); i != excludes.end(); i++) {
- for (std::vector<std::string>::const_iterator j = trace.begin(); j != trace.end(); j++) {
- if (*i == *j) {
- return true;
- }
- }
- }
- }
- }
- return false;
+ return expiryPolicy && expiryPolicy->hasExpired(*this);
}
-class CloneHeaderBody
-{
-public:
- void operator()(AMQFrame& f)
- {
- f.cloneBody();
- }
-};
-
-AMQHeaderBody* Message::getHeaderBody()
+uint8_t Message::getPriority() const
{
- // expects lock to be held
- if (copyHeaderOnWrite) {
- CloneHeaderBody f;
- frames.map_if(f, TypeFilter<HEADER_BODY>());
- copyHeaderOnWrite = false;
- }
- return frames.getHeaders();
+ return getEncoding().getPriority();
}
-void Message::addTraceId(const std::string& id)
+bool Message::getIsManagementMessage() const { return isManagementMessage; }
+void Message::setIsManagementMessage(bool b) { isManagementMessage = b; }
+qpid::framing::SequenceNumber Message::getSequence() const
{
- sys::Mutex::ScopedLock l(lock);
- if (isA<MessageTransferBody>()) {
- FieldTable& headers = getModifiableProperties<MessageProperties>()->getApplicationHeaders();
- std::string trace = headers.getAsString(X_QPID_TRACE);
- if (trace.empty()) {
- headers.setString(X_QPID_TRACE, id);
- } else if (trace.find(id) == std::string::npos) {
- trace += ",";
- trace += id;
- headers.setString(X_QPID_TRACE, trace);
- }
- }
+ return sequence;
}
-
-void Message::clearTrace()
+void Message::setSequence(const qpid::framing::SequenceNumber& s)
{
- sys::Mutex::ScopedLock l(lock);
- if (isA<MessageTransferBody>()) {
- FieldTable& headers = getModifiableProperties<MessageProperties>()->getApplicationHeaders();
- std::string trace = headers.getAsString(X_QPID_TRACE);
- if (!trace.empty()) {
- headers.setString(X_QPID_TRACE, "");
- }
- }
+ sequence = s;
}
-void Message::setTimestamp()
+MessageState Message::getState() const
{
- sys::Mutex::ScopedLock l(lock);
- DeliveryProperties* props = getModifiableProperties<DeliveryProperties>();
- time_t now = ::time(0);
- props->setTimestamp(now); // AMQP-0.10: posix time_t - secs since Epoch
+ return state;
}
-
-void Message::computeExpiration(const boost::intrusive_ptr<ExpiryPolicy>& e)
+void Message::setState(MessageState s)
{
- sys::Mutex::ScopedLock l(lock);
- DeliveryProperties* props = getModifiableProperties<DeliveryProperties>();
- if (props->getTtl()) {
- // AMQP requires setting the expiration property to be posix
- // time_t in seconds. TTL is in milliseconds
- if (!props->getExpiration()) {
- //only set expiration in delivery properties if not already set
- time_t now = ::time(0);
- props->setExpiration(now + (props->getTtl()/1000));
- }
- if (e) {
- // Use higher resolution time for the internal expiry calculation.
- // Prevent overflow as a signed int64_t
- Duration ttl(std::min(props->getTtl() * TIME_MSEC,
- (uint64_t) std::numeric_limits<int64_t>::max()));
- expiration = AbsTime(e->getCurrentTime(), ttl);
- setExpiryPolicy(e);
- }
- }
+ state = s;
}
-void Message::adjustTtl()
+const qpid::types::Variant::Map& Message::getAnnotations() const
{
- sys::Mutex::ScopedLock l(lock);
- DeliveryProperties* props = getModifiableProperties<DeliveryProperties>();
- if (props->getTtl()) {
- if (expiration < FAR_FUTURE) {
- sys::AbsTime current(
- expiryPolicy ? expiryPolicy->getCurrentTime() : sys::AbsTime::now());
- sys::Duration ttl(current, getExpiration());
- // convert from ns to ms; set to 1 if expired
- props->setTtl(int64_t(ttl) >= 1000000 ? int64_t(ttl)/1000000 : 1);
- }
- }
+ return annotations;
}
-void Message::setRedelivered()
+qpid::types::Variant Message::getAnnotation(const std::string& key) const
{
- sys::Mutex::ScopedLock l(lock);
- getModifiableProperties<framing::DeliveryProperties>()->setRedelivered(true);
+ qpid::types::Variant::Map::const_iterator i = annotations.find(key);
+ if (i != annotations.end()) return i->second;
+ //FIXME: modify Encoding interface to allow retrieval of
+ //annotations of different types from the message data as received
+ //off the wire
+ return qpid::types::Variant(getEncoding().getAnnotationAsString(key));
}
-void Message::insertCustomProperty(const std::string& key, int64_t value)
+std::string Message::getUserId() const
{
- sys::Mutex::ScopedLock l(lock);
- getModifiableProperties<MessageProperties>()->getApplicationHeaders().setInt64(key,value);
+ return encoding->getUserId();
}
-void Message::insertCustomProperty(const std::string& key, const std::string& value)
+Message::Encoding& Message::getEncoding()
{
- sys::Mutex::ScopedLock l(lock);
- getModifiableProperties<MessageProperties>()->getApplicationHeaders().setString(key,value);
+ return *encoding;
}
-
-void Message::removeCustomProperty(const std::string& key)
+const Message::Encoding& Message::getEncoding() const
{
- sys::Mutex::ScopedLock l(lock);
- getModifiableProperties<MessageProperties>()->getApplicationHeaders().erase(key);
+ return *encoding;
}
-
-void Message::setExchange(const std::string& exchange)
+Message::operator bool() const
{
- sys::Mutex::ScopedLock l(lock);
- getModifiableProperties<DeliveryProperties>()->setExchange(exchange);
+ return encoding;
}
-void Message::clearApplicationHeadersFlag()
+std::string Message::getContent() const
{
- sys::Mutex::ScopedLock l(lock);
- getModifiableProperties<MessageProperties>()->clearApplicationHeadersFlag();
-}
-
-void Message::setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e) {
- expiryPolicy = e;
+ return encoding->getContent();
}
-bool Message::hasExpired()
+std::string Message::getPropertyAsString(const std::string& key) const
{
- return expiryPolicy && expiryPolicy->hasExpired(*this);
+ return encoding->getPropertyAsString(key);
}
-
namespace {
-struct ScopedSet {
- sys::Monitor& lock;
- bool& flag;
- ScopedSet(sys::Monitor& l, bool& f) : lock(l), flag(f) {
- sys::Monitor::ScopedLock sl(lock);
- flag = true;
+class PropertyRetriever : public MapHandler
+{
+ public:
+ PropertyRetriever(const std::string& key) : name(key) {}
+ void handleVoid(const CharSequence&) {}
+ void handleUint8(const CharSequence& key, uint8_t value) { handle(key, value); }
+ void handleUint16(const CharSequence& key, uint16_t value) { handle(key, value); }
+ void handleUint32(const CharSequence& key, uint32_t value) { handle(key, value); }
+ void handleUint64(const CharSequence& key, uint64_t value) { handle(key, value); }
+ void handleInt8(const CharSequence& key, int8_t value) { handle(key, value); }
+ void handleInt16(const CharSequence& key, int16_t value) { handle(key, value); }
+ void handleInt32(const CharSequence& key, int32_t value) { handle(key, value); }
+ void handleInt64(const CharSequence& key, int64_t value) { handle(key, value); }
+ void handleFloat(const CharSequence& key, float value) { handle(key, value); }
+ void handleDouble(const CharSequence& key, double value) { handle(key, value); }
+ void handleString(const CharSequence& key, const CharSequence& value, const CharSequence& /*encoding*/)
+ {
+ if (matches(key)) result = std::string(value.data, value.size);
}
- ~ScopedSet(){
- sys::Monitor::ScopedLock sl(lock);
- flag = false;
- lock.notifyAll();
+ qpid::types::Variant getResult() { return result; }
+
+ private:
+ std::string name;
+ qpid::types::Variant result;
+
+ bool matches(const CharSequence& key)
+ {
+ return ::strncmp(key.data, name.data(), std::min(key.size, name.size())) == 0;
}
-};
-}
-void Message::allDequeuesComplete() {
- ScopedSet ss(callbackLock, inCallback);
- MessageCallback* cb = dequeueCallback;
- if (cb && *cb) (*cb)(intrusive_ptr<Message>(this));
+ template <typename T> void handle(const CharSequence& key, T value)
+ {
+ if (matches(key)) result = value;
+ }
+};
}
-
-void Message::setDequeueCompleteCallback(MessageCallback& cb) {
- sys::Mutex::ScopedLock l(callbackLock);
- while (inCallback) callbackLock.wait();
- dequeueCallback = &cb;
+qpid::types::Variant Message::getProperty(const std::string& key) const
+{
+ PropertyRetriever r(key);
+ encoding->processProperties(r);
+ return r.getResult();
}
-void Message::resetDequeueCompleteCallback() {
- sys::Mutex::ScopedLock l(callbackLock);
- while (inCallback) callbackLock.wait();
- dequeueCallback = 0;
+boost::intrusive_ptr<PersistableMessage> Message::getPersistentContext() const
+{
+ return persistentContext;
}
-uint8_t Message::getPriority() const {
- sys::Mutex::ScopedLock l(lock);
- return getAdapter().getPriority(frames);
+void Message::processProperties(MapHandler& handler) const
+{
+ encoding->processProperties(handler);
}
-bool Message::getIsManagementMessage() const { return isManagementMessage; }
-void Message::setIsManagementMessage(bool b) { isManagementMessage = b; }
-
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Message.h b/cpp/src/qpid/broker/Message.h
index 90e4eec889..599819d7b6 100644
--- a/cpp/src/qpid/broker/Message.h
+++ b/cpp/src/qpid/broker/Message.h
@@ -23,194 +23,131 @@
*/
#include "qpid/broker/BrokerImportExport.h"
-#include "qpid/broker/PersistableMessage.h"
-#include "qpid/broker/MessageAdapter.h"
-#include "qpid/framing/amqp_types.h"
-#include "qpid/sys/Monitor.h"
#include "qpid/sys/Time.h"
-#include <boost/function.hpp>
-#include <boost/intrusive_ptr.hpp>
-#include <boost/shared_ptr.hpp>
-#include <memory>
+#include "qpid/types/Variant.h"
+//TODO: move the following out of framing or replace it
+#include "qpid/framing/SequenceNumber.h"
#include <string>
#include <vector>
-namespace qpid {
-
-namespace framing {
-class AMQBody;
-class AMQHeaderBody;
-class FieldTable;
-class SequenceNumber;
-}
+#include "qpid/RefCounted.h"
+#include <boost/intrusive_ptr.hpp>
+#include "qpid/broker/ExpiryPolicy.h"
+#include "qpid/broker/PersistableMessage.h"
+namespace qpid {
namespace broker {
class ConnectionToken;
-class Exchange;
-class ExchangeRegistry;
-class MessageStore;
-class Queue;
-class ExpiryPolicy;
+class MapHandler;
+
+enum MessageState
+{
+ AVAILABLE=1,
+ ACQUIRED=2,
+ DELETED=4,
+ UNAVAILABLE=8
+};
-class Message : public PersistableMessage {
+class Message {
public:
- typedef boost::function<void (const boost::intrusive_ptr<Message>&)> MessageCallback;
-
- QPID_BROKER_EXTERN Message(const framing::SequenceNumber& id = framing::SequenceNumber());
+ class Encoding : public AsyncCompletion
+ {
+ public:
+ virtual ~Encoding() {}
+ virtual std::string getRoutingKey() const = 0;
+ virtual bool isPersistent() const = 0;
+ virtual uint8_t getPriority() const = 0;
+ virtual uint64_t getContentSize() const = 0;
+ virtual std::string getPropertyAsString(const std::string& key) const = 0;
+ virtual std::string getAnnotationAsString(const std::string& key) const = 0;
+ virtual bool getTtl(uint64_t&) const = 0;
+ virtual bool hasExpiration() const = 0;
+ virtual std::string getContent() const = 0;
+ virtual void processProperties(MapHandler&) const = 0;
+ virtual std::string getUserId() const = 0;
+ };
+
+ QPID_BROKER_EXTERN Message(boost::intrusive_ptr<Encoding>, boost::intrusive_ptr<PersistableMessage>);
+ QPID_BROKER_EXTERN Message();
QPID_BROKER_EXTERN ~Message();
- uint64_t getPersistenceId() const { return persistenceId; }
- void setPersistenceId(uint64_t _persistenceId) const { persistenceId = _persistenceId; }
-
- bool getRedelivered() const { return redelivered; }
- void redeliver() { redelivered = true; }
+ bool isRedelivered() const { return deliveryCount > 1; }
+ void deliver() { ++deliveryCount; }
+ void undeliver() { --deliveryCount; }
+ int getDeliveryCount() const { return deliveryCount; }
+ void resetDeliveryCount() { deliveryCount = 0; }
const ConnectionToken* getPublisher() const { return publisher; }
void setPublisher(ConnectionToken* p) { publisher = p; }
- const framing::SequenceNumber& getCommandId() { return frames.getId(); }
-
- QPID_BROKER_EXTERN uint64_t contentSize() const;
QPID_BROKER_EXTERN std::string getRoutingKey() const;
- const boost::shared_ptr<Exchange> getExchange(ExchangeRegistry&) const;
- QPID_BROKER_EXTERN std::string getExchangeName() const;
- bool isImmediate() const;
- QPID_BROKER_EXTERN const framing::FieldTable* getApplicationHeaders() const;
- QPID_BROKER_EXTERN std::string getAppId() const;
QPID_BROKER_EXTERN bool isPersistent() const;
- bool requiresAccept();
/** determine msg expiration time using the TTL value if present */
QPID_BROKER_EXTERN void computeExpiration(const boost::intrusive_ptr<ExpiryPolicy>& e);
void setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e);
- bool hasExpired();
+
+ bool hasExpired() const;
sys::AbsTime getExpiration() const { return expiration; }
void setExpiration(sys::AbsTime exp) { expiration = exp; }
- void adjustTtl();
- void setRedelivered();
- QPID_BROKER_EXTERN void insertCustomProperty(const std::string& key, int64_t value);
- QPID_BROKER_EXTERN void insertCustomProperty(const std::string& key, const std::string& value);
- QPID_BROKER_EXTERN void removeCustomProperty(const std::string& key);
- void setExchange(const std::string&);
- void clearApplicationHeadersFlag();
+ uint64_t getTtl() const;
+
/** set the timestamp delivery property to the current time-of-day */
QPID_BROKER_EXTERN void setTimestamp();
+ QPID_BROKER_EXTERN uint64_t getTimestamp() const;
- framing::FrameSet& getFrames() { return frames; }
- const framing::FrameSet& getFrames() const { return frames; }
-
- template <class T> const T* getProperties() const {
- const qpid::framing::AMQHeaderBody* p = frames.getHeaders();
- return p->get<T>();
- }
-
- template <class T> const T* hasProperties() const {
- const qpid::framing::AMQHeaderBody* p = frames.getHeaders();
- return p->get<T>();
- }
-
- template <class T> void eraseProperties() {
- qpid::framing::AMQHeaderBody* p = frames.getHeaders();
- p->erase<T>();
- }
+ QPID_BROKER_EXTERN void addAnnotation(const std::string& key, const qpid::types::Variant& value);
+ QPID_BROKER_EXTERN bool isExcluded(const std::vector<std::string>& excludes) const;
+ QPID_BROKER_EXTERN void addTraceId(const std::string& id);
+ QPID_BROKER_EXTERN void clearTrace();
+ QPID_BROKER_EXTERN uint8_t getPriority() const;
+ QPID_BROKER_EXTERN std::string getPropertyAsString(const std::string& key) const;
+ QPID_BROKER_EXTERN qpid::types::Variant getProperty(const std::string& key) const;
+ void processProperties(MapHandler&) const;
- template <class T> const T* getMethod() const {
- return frames.as<T>();
- }
+ QPID_BROKER_EXTERN uint64_t getContentSize() const;
- template <class T> T* getMethod() {
- return frames.as<T>();
- }
+ Encoding& getEncoding();
+ const Encoding& getEncoding() const;
+ QPID_BROKER_EXTERN operator bool() const;
- template <class T> bool isA() const {
- return frames.isA<T>();
- }
-
- uint32_t getRequiredCredit();
-
- void encode(framing::Buffer& buffer) const;
- void encodeContent(framing::Buffer& buffer) const;
-
- /**
- * @returns the size of the buffer needed to encode this
- * message in its entirety
- */
- uint32_t encodedSize() const;
- /**
- * @returns the size of the buffer needed to encode the
- * 'header' of this message (not just the header frame,
- * but other meta data e.g.routing key and exchange)
- */
- uint32_t encodedHeaderSize() const;
- uint32_t encodedContentSize() const;
-
- QPID_BROKER_EXTERN void decodeHeader(framing::Buffer& buffer);
- QPID_BROKER_EXTERN void decodeContent(framing::Buffer& buffer);
-
- void QPID_BROKER_EXTERN tryReleaseContent();
- void releaseContent();
- void releaseContent(MessageStore* s);//deprecated, use 'setStore(store); releaseContent();' instead
- void destroy();
-
- bool getContentFrame(const Queue& queue, framing::AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const;
- QPID_BROKER_EXTERN void sendContent(const Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const;
- void sendHeader(framing::FrameHandler& out, uint16_t maxFrameSize) const;
+ bool getIsManagementMessage() const;
+ void setIsManagementMessage(bool b);
- QPID_BROKER_EXTERN bool isContentLoaded() const;
+ QPID_BROKER_EXTERN qpid::framing::SequenceNumber getSequence() const;
+ QPID_BROKER_EXTERN void setSequence(const qpid::framing::SequenceNumber&);
- bool isExcluded(const std::vector<std::string>& excludes) const;
- void addTraceId(const std::string& id);
- void clearTrace();
+ MessageState getState() const;
+ void setState(MessageState);
- void forcePersistent();
- bool isForcedPersistent();
+ QPID_BROKER_EXTERN qpid::types::Variant getAnnotation(const std::string& key) const;
+ QPID_BROKER_EXTERN const qpid::types::Variant::Map& getAnnotations() const;
+ std::string getUserId() const;
- /** Call cb when dequeue is complete, may call immediately. Holds cb by reference. */
- void setDequeueCompleteCallback(MessageCallback& cb);
- void resetDequeueCompleteCallback();
+ QPID_BROKER_EXTERN std::string getContent() const;//TODO: may be better to get rid of this...
- uint8_t getPriority() const;
- bool getIsManagementMessage() const;
- void setIsManagementMessage(bool b);
+ QPID_BROKER_EXTERN boost::intrusive_ptr<AsyncCompletion> getIngressCompletion() const;
+ QPID_BROKER_EXTERN boost::intrusive_ptr<PersistableMessage> getPersistentContext() const;
private:
- MessageAdapter& getAdapter() const;
- void allDequeuesComplete();
-
- mutable sys::Mutex lock;
- framing::FrameSet frames;
- mutable boost::shared_ptr<Exchange> exchange;
- mutable uint64_t persistenceId;
- bool redelivered;
- bool loaded;
- bool staged;
- bool forcePersistentPolicy; // used to force message as durable, via a broker policy
+ boost::intrusive_ptr<Encoding> encoding;
+ boost::intrusive_ptr<PersistableMessage> persistentContext;
+ int deliveryCount;
ConnectionToken* publisher;
- mutable MessageAdapter* adapter;
qpid::sys::AbsTime expiration;
boost::intrusive_ptr<ExpiryPolicy> expiryPolicy;
-
- static TransferAdapter TRANSFER;
-
- mutable boost::intrusive_ptr<Message> empty;
-
- sys::Monitor callbackLock;
- MessageCallback* dequeueCallback;
- bool inCallback;
-
- uint32_t requiredCredit;
+ uint64_t timestamp;
+ qpid::types::Variant::Map annotations;
bool isManagementMessage;
- mutable bool copyHeaderOnWrite;
-
- /**
- * Expects lock to be held
- */
- template <class T> T* getModifiableProperties() {
- return getHeaderBody()->get<T>(true);
- }
- qpid::framing::AMQHeaderBody* getHeaderBody();
+ MessageState state;
+ qpid::framing::SequenceNumber sequence;
+
+ void annotationsChanged();
};
+QPID_BROKER_EXTERN void encode(const Message&, std::string&);
+QPID_BROKER_EXTERN void decode(const std::string&, Message&);
+
}}
diff --git a/cpp/src/qpid/broker/MessageBuilder.cpp b/cpp/src/qpid/broker/MessageBuilder.cpp
index a6d605c296..7cb99514d5 100644
--- a/cpp/src/qpid/broker/MessageBuilder.cpp
+++ b/cpp/src/qpid/broker/MessageBuilder.cpp
@@ -21,10 +21,11 @@
#include "qpid/broker/MessageBuilder.h"
#include "qpid/broker/Message.h"
-#include "qpid/broker/MessageStore.h"
-#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
using boost::intrusive_ptr;
using namespace qpid::broker;
@@ -36,8 +37,7 @@ namespace
const std::string QPID_MANAGEMENT("qpid.management");
}
-MessageBuilder::MessageBuilder(MessageStore* const _store) :
- state(DORMANT), store(_store) {}
+MessageBuilder::MessageBuilder() : state(DORMANT) {}
void MessageBuilder::handle(AMQFrame& frame)
{
@@ -45,6 +45,7 @@ void MessageBuilder::handle(AMQFrame& frame)
switch(state) {
case METHOD:
checkType(METHOD_BODY, type);
+ exchange = frame.castBody<qpid::framing::MessageTransferBody>()->getDestination();
state = HEADER;
break;
case HEADER:
@@ -55,7 +56,9 @@ void MessageBuilder::handle(AMQFrame& frame)
header.setBof(false);
header.setEof(false);
message->getFrames().append(header);
- } else if (type != HEADER_BODY) {
+ } else if (type == HEADER_BODY) {
+ frame.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setExchange(exchange);
+ } else {
throw CommandInvalidException(
QPID_MSG("Invalid frame sequence for message, expected header or content got "
<< type_str(type) << ")"));
@@ -73,14 +76,14 @@ void MessageBuilder::handle(AMQFrame& frame)
void MessageBuilder::end()
{
+ message->computeRequiredCredit();
message = 0;
state = DORMANT;
}
void MessageBuilder::start(const SequenceNumber& id)
{
- message = intrusive_ptr<Message>(new Message(id));
- message->setStore(store);
+ message = intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer>(new qpid::broker::amqp_0_10::MessageTransfer(id));
state = METHOD;
}
@@ -112,3 +115,5 @@ void MessageBuilder::checkType(uint8_t expected, uint8_t actual)
<< type_str(expected) << " got " << type_str(actual) << ")"));
}
}
+
+boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> MessageBuilder::getMessage() { return message; }
diff --git a/cpp/src/qpid/broker/MessageBuilder.h b/cpp/src/qpid/broker/MessageBuilder.h
index b99b8efee6..5ca6fa0c66 100644
--- a/cpp/src/qpid/broker/MessageBuilder.h
+++ b/cpp/src/qpid/broker/MessageBuilder.h
@@ -30,21 +30,22 @@
namespace qpid {
namespace broker {
- class Message;
- class MessageStore;
+ namespace amqp_0_10 {
+ class MessageTransfer;
+ }
class QPID_BROKER_CLASS_EXTERN MessageBuilder : public framing::FrameHandler{
public:
- QPID_BROKER_EXTERN MessageBuilder(MessageStore* const store);
+ QPID_BROKER_EXTERN MessageBuilder();
QPID_BROKER_EXTERN void handle(framing::AMQFrame& frame);
- boost::intrusive_ptr<Message> getMessage() { return message; }
+ boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> getMessage();
QPID_BROKER_EXTERN void start(const framing::SequenceNumber& id);
void end();
private:
enum State {DORMANT, METHOD, HEADER, CONTENT};
State state;
- boost::intrusive_ptr<Message> message;
- MessageStore* const store;
+ boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> message;
+ std::string exchange;
void checkType(uint8_t expected, uint8_t actual);
};
diff --git a/cpp/src/qpid/broker/MessageDeque.cpp b/cpp/src/qpid/broker/MessageDeque.cpp
index 83c8ca6868..1529d4ac94 100644
--- a/cpp/src/qpid/broker/MessageDeque.cpp
+++ b/cpp/src/qpid/broker/MessageDeque.cpp
@@ -19,218 +19,71 @@
*
*/
#include "qpid/broker/MessageDeque.h"
-#include "qpid/broker/QueuedMessage.h"
-#include "qpid/log/Statement.h"
#include "assert.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/QueueCursor.h"
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/log/Statement.h"
namespace qpid {
namespace broker {
-
-MessageDeque::MessageDeque() : available(0), head(0) {}
-
-size_t MessageDeque::index(const framing::SequenceNumber& position)
-{
- //assuming a monotonic sequence, with no messages removed except
- //from the ends of the deque, we can use the position to determin
- //an index into the deque
- if (messages.empty() || position < messages.front().position) return 0;
- return position - messages.front().position;
+namespace {
+Message padding(qpid::framing::SequenceNumber id) {
+ Message m;
+ m.setState(DELETED);
+ m.setSequence(id);
+ return m;
}
-
-bool MessageDeque::deleted(const QueuedMessage& m)
-{
- size_t i = index(m.position);
- if (i < messages.size()) {
- QueuedMessage *qm = &messages[i];
- if (qm->status != QueuedMessage::DELETED) {
- qm->status = QueuedMessage::DELETED;
- qm->payload = 0; // message no longer needed
- clean();
- return true;
- }
- }
- return false;
}
-size_t MessageDeque::size()
-{
- return available;
-}
+using qpid::framing::SequenceNumber;
-QueuedMessage* MessageDeque::releasePtr(const QueuedMessage& message)
-{
- size_t i = index(message.position);
- if (i < messages.size()) {
- QueuedMessage& m = messages[i];
- if (m.status == QueuedMessage::ACQUIRED) {
- if (head > i) head = i;
- m.status = QueuedMessage::AVAILABLE;
- ++available;
- return &messages[i];
- }
- } else {
- assert(0);
- QPID_LOG(error, "Failed to release message at " << message.position << " " << message.payload->getFrames().getContent() << "; no such message (index=" << i << ", size=" << messages.size() << ")");
- }
- return 0;
-}
+MessageDeque::MessageDeque() : messages(&padding) {}
-void MessageDeque::release(const QueuedMessage& message) { releasePtr(message); }
-bool MessageDeque::acquire(const framing::SequenceNumber& position, QueuedMessage& message)
+bool MessageDeque::deleted(const QueueCursor& cursor)
{
- if (position < messages.front().position) return false;
- size_t i = index(position);
- if (i < messages.size()) {
- QueuedMessage& temp = messages[i];
- if (temp.status == QueuedMessage::AVAILABLE) {
- temp.status = QueuedMessage::ACQUIRED;
- --available;
- message = temp;
- return true;
- }
- }
- return false;
+ return messages.deleted(cursor);
}
-bool MessageDeque::find(const framing::SequenceNumber& position, QueuedMessage& message)
+void MessageDeque::publish(const Message& added)
{
- size_t i = index(position);
- if (i < messages.size()) {
- message = messages[i];
- return true;
- } else {
- return false;
- }
+ messages.publish(added);
}
-bool MessageDeque::browse(const framing::SequenceNumber& position, QueuedMessage& message, bool unacquired)
+Message* MessageDeque::release(const QueueCursor& cursor)
{
- //get first message that is greater than position
- size_t i = index(position + 1);
- while (i < messages.size()) {
- QueuedMessage& m = messages[i++];
- if (m.status == QueuedMessage::AVAILABLE || (!unacquired && m.status == QueuedMessage::ACQUIRED)) {
- message = m;
- return true;
- }
- }
- return false;
+ return messages.release(cursor);
}
-bool MessageDeque::consume(QueuedMessage& message)
+Message* MessageDeque::next(QueueCursor& cursor)
{
- while (head < messages.size()) {
- QueuedMessage& i = messages[head++];
- if (i.status == QueuedMessage::AVAILABLE) {
- i.status = QueuedMessage::ACQUIRED;
- --available;
- message = i;
- return true;
- }
- }
- return false;
+ return messages.next(cursor);
}
-namespace {
-QueuedMessage padding(uint32_t pos) {
- return QueuedMessage(0, 0, pos, QueuedMessage::DELETED);
-}
-} // namespace
-
-QueuedMessage* MessageDeque::pushPtr(const QueuedMessage& added) {
- //add padding to prevent gaps in sequence, which break the index
- //calculation (needed for queue replication)
- while (messages.size() && (added.position - messages.back().position) > 1)
- messages.push_back(padding(messages.back().position + 1));
- messages.push_back(added);
- messages.back().status = QueuedMessage::AVAILABLE;
- if (head >= messages.size()) head = messages.size() - 1;
- ++available;
- clean(); // QPID-4046: let producer help clean the backlog of deleted messages
- return &messages.back();
-}
-
-bool MessageDeque::push(const QueuedMessage& added, QueuedMessage& /*not needed*/) {
- pushPtr(added);
- return false; // adding a message never causes one to be removed for deque
-}
-
-void MessageDeque::updateAcquired(const QueuedMessage& acquired)
+size_t MessageDeque::size()
{
- // Pad the front of the queue if necessary
- while (messages.size() && (acquired.position < messages.front().position))
- messages.push_front(padding(uint32_t(messages.front().position) - 1));
- size_t i = index(acquired.position);
- if (i < messages.size()) { // Replace an existing padding message
- assert(messages[i].status == QueuedMessage::DELETED);
- messages[i] = acquired;
- messages[i].status = QueuedMessage::ACQUIRED;
- }
- else { // Push to the back
- // Pad the back of the queue if necessary
- while (messages.size() && (acquired.position - messages.back().position) > 1)
- messages.push_back(padding(messages.back().position + 1));
- assert(!messages.size() || (acquired.position - messages.back().position) == 1);
- messages.push_back(acquired);
- messages.back().status = QueuedMessage::ACQUIRED;
- }
+ return messages.size();
}
-namespace {
-bool isNotDeleted(const QueuedMessage& qm) { return qm.status != QueuedMessage::DELETED; }
-} // namespace
-
-void MessageDeque::setPosition(const framing::SequenceNumber& n) {
- size_t i = index(n+1);
- if (i >= messages.size()) return; // Nothing to do.
-
- // Assertion to verify the precondition: no messaages after n.
- assert(std::find_if(messages.begin()+i, messages.end(), &isNotDeleted) ==
- messages.end());
- messages.erase(messages.begin()+i, messages.end());
- if (head >= messages.size()) head = messages.size() - 1;
- // Re-count the available messages
- available = 0;
- for (Deque::iterator i = messages.begin(); i != messages.end(); ++i) {
- if (i->status == QueuedMessage::AVAILABLE) ++available;
- }
+Message* MessageDeque::find(const framing::SequenceNumber& position, QueueCursor* cursor)
+{
+ return messages.find(position, cursor);
}
-void MessageDeque::clean()
+Message* MessageDeque::find(const QueueCursor& cursor)
{
- // QPID-4046: If a queue has multiple consumers, then it is possible for a large
- // collection of deleted messages to build up. Limit the number of messages cleaned
- // up on each call to clean().
- size_t count = 0;
- while (messages.size() && messages.front().status == QueuedMessage::DELETED && count < 10) {
- messages.pop_front();
- count += 1;
- }
- head = (head > count) ? head - count : 0;
+ return messages.find(cursor);
}
void MessageDeque::foreach(Functor f)
{
- for (Deque::iterator i = messages.begin(); i != messages.end(); ++i) {
- if (i->status == QueuedMessage::AVAILABLE) {
- f(*i);
- }
- }
+ messages.foreach(f);
}
-void MessageDeque::removeIf(Predicate p)
+void MessageDeque::resetCursors()
{
- for (Deque::iterator i = messages.begin(); i != messages.end(); ++i) {
- if (i->status == QueuedMessage::AVAILABLE && p(*i)) {
- //Use special status for this as messages are not yet
- //dequeued, but should not be considered on the queue
- //either (used for purging and moving)
- i->status = QueuedMessage::REMOVED;
- --available;
- }
- }
- clean();
+ messages.resetCursors();
}
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/MessageDeque.h b/cpp/src/qpid/broker/MessageDeque.h
index c5670b2a72..ec67476926 100644
--- a/cpp/src/qpid/broker/MessageDeque.h
+++ b/cpp/src/qpid/broker/MessageDeque.h
@@ -22,8 +22,7 @@
*
*/
#include "qpid/broker/Messages.h"
-#include "qpid/broker/QueuedMessage.h"
-#include <deque>
+#include "qpid/broker/IndexedDeque.h"
namespace qpid {
namespace broker {
@@ -36,31 +35,20 @@ class MessageDeque : public Messages
public:
MessageDeque();
size_t size();
- bool deleted(const QueuedMessage&);
- void release(const QueuedMessage&);
- bool acquire(const framing::SequenceNumber&, QueuedMessage&);
- bool find(const framing::SequenceNumber&, QueuedMessage&);
- bool browse(const framing::SequenceNumber&, QueuedMessage&, bool);
- bool consume(QueuedMessage&);
- bool push(const QueuedMessage& added, QueuedMessage& removed);
- void updateAcquired(const QueuedMessage& acquired);
- void setPosition(const framing::SequenceNumber&);
+ bool deleted(const QueueCursor&);
+ void publish(const Message& added);
+ Message* next(QueueCursor&);
+ Message* release(const QueueCursor& cursor);
+ Message* find(const QueueCursor&);
+ Message* find(const framing::SequenceNumber&, QueueCursor*);
+
void foreach(Functor);
- void removeIf(Predicate);
- // For use by other Messages implementations that use MessageDeque as a FIFO index
- // and keep pointers to its elements in their own indexing strctures.
- void clean();
- QueuedMessage* releasePtr(const QueuedMessage&);
- QueuedMessage* pushPtr(const QueuedMessage& added);
+ void resetCursors();
private:
- typedef std::deque<QueuedMessage> Deque;
+ typedef IndexedDeque<Message> Deque;
Deque messages;
- size_t available;
- size_t head;
-
- size_t index(const framing::SequenceNumber&);
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/MessageDistributor.h b/cpp/src/qpid/broker/MessageDistributor.h
index 090393c160..c11e4495a1 100644
--- a/cpp/src/qpid/broker/MessageDistributor.h
+++ b/cpp/src/qpid/broker/MessageDistributor.h
@@ -21,51 +21,28 @@
* under the License.
*
*/
-
+#include "qpid/types/Variant.h"
/** Abstraction used by Queue to determine the next "most desirable" message to provide to
* a particular consuming client
*/
-
-#include "qpid/broker/Consumer.h"
-
namespace qpid {
namespace broker {
-struct QueuedMessage;
+class Message;
class MessageDistributor
{
public:
virtual ~MessageDistributor() {};
- /** Locking Note: all methods assume the caller is holding the Queue::messageLock
- * during the method call.
- */
-
- /** Determine the next message available for consumption by the consumer
- * @param consumer the consumer that needs a message to consume
- * @param next set to the next message that the consumer may consume.
- * @return true if message is available and next is set
- */
- virtual bool nextConsumableMessage( Consumer::shared_ptr& consumer,
- QueuedMessage& next ) = 0;
-
- /** Allow the comsumer to take ownership of the given message.
+ /**
+ * Determine whether the named consumer can take ownership of the specified message.
* @param consumer the name of the consumer that is attempting to acquire the message
- * @param qm the message to be acquired, previously returned from nextConsumableMessage()
+ * @param target the message to be acquired
* @return true if ownership is permitted, false if ownership cannot be assigned.
*/
- virtual bool allocate( const std::string& consumer,
- const QueuedMessage& target) = 0;
-
- /** Determine the next message available for browsing by the consumer
- * @param consumer the consumer that is browsing the queue
- * @param next set to the next message that the consumer may browse.
- * @return true if a message is available and next is returned
- */
- virtual bool nextBrowsableMessage( Consumer::shared_ptr& consumer,
- QueuedMessage& next ) = 0;
+ virtual bool acquire(const std::string& consumer, Message& target) = 0;
/** hook to add any interesting management state to the status map */
virtual void query(qpid::types::Variant::Map&) const = 0;
diff --git a/cpp/src/qpid/broker/MessageGroupManager.cpp b/cpp/src/qpid/broker/MessageGroupManager.cpp
index 15cd56a676..47e40a4794 100644
--- a/cpp/src/qpid/broker/MessageGroupManager.cpp
+++ b/cpp/src/qpid/broker/MessageGroupManager.cpp
@@ -1,4 +1,4 @@
-/*
+ /*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -20,10 +20,16 @@
*/
#include "qpid/broker/MessageGroupManager.h"
-
-#include "qpid/broker/Queue.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/Messages.h"
+#include "qpid/broker/MessageDeque.h"
+#include "qpid/broker/QueueSettings.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/DeliveryProperties.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/TypeCode.h"
+#include "qpid/types/Variant.h"
#include "qpid/log/Statement.h"
#include "qpid/types/Variant.h"
@@ -75,24 +81,16 @@ void MessageGroupManager::disown( GroupState& state )
freeGroups[state.members.front().position] = &state;
}
-MessageGroupManager::GroupState& MessageGroupManager::findGroup( const QueuedMessage& qm )
+MessageGroupManager::GroupState& MessageGroupManager::findGroup( const Message& m )
{
- uint32_t thisMsg = qm.position.getValue();
+ uint32_t thisMsg = m.getSequence().getValue();
if (cachedGroup && lastMsg == thisMsg) {
hits++;
return *cachedGroup;
}
- std::string group = defaultGroupId;
- const qpid::framing::FieldTable* headers = qm.payload->getApplicationHeaders();
- if (headers) {
- qpid::framing::FieldTable::ValuePtr id = headers->get( groupIdHeader );
- if (id && id->convertsTo<std::string>()) {
- std::string tmp = id->get<std::string>();
- if (!tmp.empty()) // empty group is reserved
- group = tmp;
- }
- }
+ std::string group = m.getPropertyAsString(groupIdHeader);
+ if (group.empty()) group = defaultGroupId; //empty group is reserved
if (cachedGroup && group == lastGroup) {
hits++;
@@ -112,48 +110,48 @@ MessageGroupManager::GroupState& MessageGroupManager::findGroup( const QueuedMes
}
-void MessageGroupManager::enqueued( const QueuedMessage& qm )
+void MessageGroupManager::enqueued( const Message& m )
{
// @todo KAG optimization - store reference to group state in QueuedMessage
// issue: const-ness??
- GroupState& state = findGroup(qm);
- GroupState::MessageState mState(qm.position);
+ GroupState& state = findGroup(m);
+ GroupState::MessageState mState(m.getSequence());
state.members.push_back(mState);
uint32_t total = state.members.size();
QPID_LOG( trace, "group queue " << qName <<
": added message to group id=" << state.group << " total=" << total );
if (total == 1) {
// newly created group, no owner
- assert(freeGroups.find(qm.position) == freeGroups.end());
- freeGroups[qm.position] = &state;
+ assert(freeGroups.find(m.getSequence()) == freeGroups.end());
+ freeGroups[m.getSequence()] = &state;
}
}
-void MessageGroupManager::acquired( const QueuedMessage& qm )
+void MessageGroupManager::acquired( const Message& m )
{
// @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage
// issue: const-ness??
- GroupState& state = findGroup(qm);
- GroupState::MessageFifo::iterator m = state.findMsg(qm.position);
- assert(m != state.members.end());
- m->acquired = true;
+ GroupState& state = findGroup(m);
+ GroupState::MessageFifo::iterator gm = state.findMsg(m.getSequence());
+ assert(gm != state.members.end());
+ gm->acquired = true;
state.acquired += 1;
QPID_LOG( trace, "group queue " << qName <<
": acquired message in group id=" << state.group << " acquired=" << state.acquired );
}
-void MessageGroupManager::requeued( const QueuedMessage& qm )
+void MessageGroupManager::requeued( const Message& m )
{
// @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage
// issue: const-ness??
- GroupState& state = findGroup(qm);
+ GroupState& state = findGroup(m);
assert( state.acquired != 0 );
state.acquired -= 1;
- GroupState::MessageFifo::iterator m = state.findMsg(qm.position);
- assert(m != state.members.end());
- m->acquired = false;
+ GroupState::MessageFifo::iterator i = state.findMsg(m.getSequence());
+ assert(i != state.members.end());
+ i->acquired = false;
if (state.acquired == 0 && state.owned()) {
QPID_LOG( trace, "group queue " << qName <<
": consumer name=" << state.owner << " released group id=" << state.group);
@@ -164,14 +162,14 @@ void MessageGroupManager::requeued( const QueuedMessage& qm )
}
-void MessageGroupManager::dequeued( const QueuedMessage& qm )
+void MessageGroupManager::dequeued( const Message& m )
{
// @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage
// issue: const-ness??
- GroupState& state = findGroup(qm);
- GroupState::MessageFifo::iterator m = state.findMsg(qm.position);
- assert(m != state.members.end());
- if (m->acquired) {
+ GroupState& state = findGroup(m);
+ GroupState::MessageFifo::iterator i = state.findMsg(m.getSequence());
+ assert(i != state.members.end());
+ if (i->acquired) {
assert( state.acquired != 0 );
state.acquired -= 1;
}
@@ -179,7 +177,7 @@ void MessageGroupManager::dequeued( const QueuedMessage& qm )
// special case if qm is first (oldest) message in the group:
// may need to re-insert it back on the freeGroups list, as the index will change
bool reFreeNeeded = false;
- if (m == state.members.begin()) {
+ if (i == state.members.begin()) {
if (!state.owned()) {
// will be on the freeGroups list if mgmt is dequeueing rather than a consumer!
// if on freelist, it is indexed by first member, which is about to be removed!
@@ -188,7 +186,7 @@ void MessageGroupManager::dequeued( const QueuedMessage& qm )
}
state.members.pop_front();
} else {
- state.members.erase(m);
+ state.members.erase(i);
}
uint32_t total = state.members.size();
@@ -206,6 +204,12 @@ void MessageGroupManager::dequeued( const QueuedMessage& qm )
QPID_LOG( trace, "group queue " << qName <<
": consumer name=" << state.owner << " released group id=" << state.group);
disown(state);
+ MessageDeque* md = dynamic_cast<MessageDeque*>(&messages);
+ if (md) {
+ md->resetCursors();
+ } else {
+ QPID_LOG(warning, "Could not reset cursors for message group, unexpected container type");
+ }
} else if (reFreeNeeded) {
disown(state);
}
@@ -215,55 +219,27 @@ MessageGroupManager::~MessageGroupManager()
{
QPID_LOG( debug, "group queue " << qName << " cache results: hits=" << hits << " misses=" << misses );
}
-bool MessageGroupManager::nextConsumableMessage( Consumer::shared_ptr& c, QueuedMessage& next )
+
+bool MessageGroupManager::acquire(const std::string& consumer, Message& m)
{
- if (!messages.size())
- return false;
+ if (m.getState() == AVAILABLE) {
+ // @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage
+ GroupState& state = findGroup(m);
- next.position = c->getPosition();
- if (!freeGroups.empty()) {
- const framing::SequenceNumber& nextFree = freeGroups.begin()->first;
- if (nextFree <= next.position) { // take oldest free
- next.position = nextFree;
- --next.position;
+ if (!state.owned()) {
+ own( state, consumer );
+ QPID_LOG( trace, "group queue " << qName <<
+ ": consumer name=" << consumer << " has acquired group id=" << state.group);
}
- }
-
- while (messages.browse( next.position, next, true )) {
- GroupState& group = findGroup(next);
- if (!group.owned()) {
- //TODO: make acquire more efficient when we already have the message in question
- if (group.members.front().position == next.position && messages.acquire(next.position, next)) { // only take from head!
- return true;
- }
- QPID_LOG(debug, "Skipping " << next.position << " since group " << group.group
- << "'s head message still pending. pos=" << group.members.front().position);
- } else if (group.owner == c->getName() && messages.acquire(next.position, next)) {
+ if (state.owner == consumer) {
+ m.setState(ACQUIRED);
return true;
+ } else {
+ return false;
}
+ } else {
+ return false;
}
- return false;
-}
-
-
-bool MessageGroupManager::allocate(const std::string& consumer, const QueuedMessage& qm)
-{
- // @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage
- GroupState& state = findGroup(qm);
-
- if (!state.owned()) {
- own( state, consumer );
- QPID_LOG( trace, "group queue " << qName <<
- ": consumer name=" << consumer << " has acquired group id=" << state.group);
- return true;
- }
- return state.owner == consumer;
-}
-
-bool MessageGroupManager::nextBrowsableMessage( Consumer::shared_ptr& c, QueuedMessage& next )
-{
- // browse: allow access to any available msg, regardless of group ownership (?ok?)
- return messages.browse(c->getPosition(), next, false);
}
void MessageGroupManager::query(qpid::types::Variant::Map& status) const
@@ -296,11 +272,9 @@ void MessageGroupManager::query(qpid::types::Variant::Map& status) const
// set the timestamp to the arrival timestamp of the oldest (HEAD) message, if present
info[GROUP_TIMESTAMP] = 0;
if (g->second.members.size() != 0) {
- QueuedMessage qm;
- if (messages.find(g->second.members.front().position, qm) &&
- qm.payload &&
- qm.payload->hasProperties<framing::DeliveryProperties>()) {
- info[GROUP_TIMESTAMP] = qm.payload->getProperties<framing::DeliveryProperties>()->getTimestamp();
+ Message* m = messages.find(g->second.members.front().position, 0);
+ if (m && m->getTimestamp()) {
+ info[GROUP_TIMESTAMP] = m->getTimestamp();
}
}
info[GROUP_CONSUMER] = g->second.owner;
@@ -313,33 +287,13 @@ void MessageGroupManager::query(qpid::types::Variant::Map& status) const
boost::shared_ptr<MessageGroupManager> MessageGroupManager::create( const std::string& qName,
Messages& messages,
- const qpid::framing::FieldTable& settings )
+ const QueueSettings& settings )
{
- boost::shared_ptr<MessageGroupManager> empty;
-
- if (settings.isSet(qpidMessageGroupKey)) {
-
- // @todo: remove once "sticky" consumers are supported - see QPID-3347
- if (!settings.isSet(qpidSharedGroup)) {
- QPID_LOG( error, "Only shared groups are supported in this version of the broker. Use '--shared-groups' in qpid-config." );
- return empty;
- }
-
- std::string headerKey = settings.getAsString(qpidMessageGroupKey);
- if (headerKey.empty()) {
- QPID_LOG( error, "A Message Group header key must be configured, queue=" << qName);
- return empty;
- }
- unsigned int timestamp = settings.getAsInt(qpidMessageGroupTimestamp);
-
- boost::shared_ptr<MessageGroupManager> manager( new MessageGroupManager( headerKey, qName, messages, timestamp ) );
-
- QPID_LOG( debug, "Configured Queue '" << qName <<
- "' for message grouping using header key '" << headerKey << "'" <<
- " (timestamp=" << timestamp << ")");
- return manager;
- }
- return empty;
+ boost::shared_ptr<MessageGroupManager> manager( new MessageGroupManager( settings.groupKey, qName, messages, settings.addTimestamp ) );
+ QPID_LOG( debug, "Configured Queue '" << qName <<
+ "' for message grouping using header key '" << settings.groupKey << "'" <<
+ " (timestamp=" << settings.addTimestamp << ")");
+ return manager;
}
std::string MessageGroupManager::defaultGroupId;
diff --git a/cpp/src/qpid/broker/MessageGroupManager.h b/cpp/src/qpid/broker/MessageGroupManager.h
index 2dd97ea2ff..fe39e007b5 100644
--- a/cpp/src/qpid/broker/MessageGroupManager.h
+++ b/cpp/src/qpid/broker/MessageGroupManager.h
@@ -24,8 +24,10 @@
/* for managing message grouping on Queues */
+#include "qpid/broker/BrokerImportExport.h"
#include "qpid/broker/StatefulQueueObserver.h"
#include "qpid/broker/MessageDistributor.h"
+#include "qpid/framing/SequenceNumber.h"
#include "qpid/sys/unordered_map.h"
#include <deque>
@@ -34,6 +36,7 @@ namespace qpid {
namespace broker {
class QueueObserver;
+struct QueueSettings;
class MessageDistributor;
class Messages;
@@ -76,11 +79,7 @@ class MessageGroupManager : public StatefulQueueObserver, public MessageDistribu
GroupFifo freeGroups; // ordered by oldest free msg
//Consumers consumers; // index: consumer name
- static const std::string qpidMessageGroupKey;
- static const std::string qpidSharedGroup; // if specified, one group can be consumed by multiple receivers
- static const std::string qpidMessageGroupTimestamp;
-
- GroupState& findGroup( const QueuedMessage& qm );
+ GroupState& findGroup( const Message& m );
unsigned long hits, misses; // for debug
uint32_t lastMsg;
std::string lastGroup;
@@ -91,11 +90,14 @@ class MessageGroupManager : public StatefulQueueObserver, public MessageDistribu
void disown( GroupState& state );
public:
+ static const std::string qpidMessageGroupKey;
+ static const std::string qpidSharedGroup; // if specified, one group can be consumed by multiple receivers
+ static const std::string qpidMessageGroupTimestamp;
static QPID_BROKER_EXTERN void setDefaults(const std::string& groupId);
static boost::shared_ptr<MessageGroupManager> create( const std::string& qName,
Messages& messages,
- const qpid::framing::FieldTable& settings );
+ const QueueSettings& settings );
MessageGroupManager(const std::string& header, const std::string& _qName,
Messages& container, unsigned int _timestamp=0 )
@@ -106,22 +108,20 @@ class MessageGroupManager : public StatefulQueueObserver, public MessageDistribu
virtual ~MessageGroupManager();
// QueueObserver iface
- void enqueued( const QueuedMessage& qm );
- void acquired( const QueuedMessage& qm );
- void requeued( const QueuedMessage& qm );
- void dequeued( const QueuedMessage& qm );
+ void enqueued( const Message& qm );
+ void acquired( const Message& qm );
+ void requeued( const Message& qm );
+ void dequeued( const Message& qm );
void consumerAdded( const Consumer& ) {};
void consumerRemoved( const Consumer& ) {};
void getState(qpid::framing::FieldTable& state ) const;
void setState(const qpid::framing::FieldTable&);
// MessageDistributor iface
- bool nextConsumableMessage(Consumer::shared_ptr& c, QueuedMessage& next);
- bool allocate(const std::string& c, const QueuedMessage& qm);
- bool nextBrowsableMessage(Consumer::shared_ptr& c, QueuedMessage& next);
+ bool acquire(const std::string& c, Message& );
void query(qpid::types::Variant::Map&) const;
- bool match(const qpid::types::Variant::Map*, const QueuedMessage&) const;
+ bool match(const qpid::types::Variant::Map*, const Message&) const;
};
}}
diff --git a/cpp/src/qpid/broker/MessageMap.cpp b/cpp/src/qpid/broker/MessageMap.cpp
index 592f3fefde..4cdd83c9aa 100644
--- a/cpp/src/qpid/broker/MessageMap.cpp
+++ b/cpp/src/qpid/broker/MessageMap.cpp
@@ -19,7 +19,8 @@
*
*/
#include "qpid/broker/MessageMap.h"
-#include "qpid/broker/QueuedMessage.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/QueueCursor.h"
#include "qpid/log/Statement.h"
#include <algorithm>
@@ -29,29 +30,17 @@ namespace {
const std::string EMPTY;
}
-bool MessageMap::deleted(const QueuedMessage& message)
-{
- Ordering::iterator i = messages.find(message.position);
- if (i != messages.end()) {
- erase(i);
- return true;
- } else {
- return false;
- }
-}
-std::string MessageMap::getKey(const QueuedMessage& message)
+std::string MessageMap::getKey(const Message& message)
{
- const framing::FieldTable* ft = message.payload->getApplicationHeaders();
- if (ft) return ft->getAsString(key);
- else return EMPTY;
+ return message.getPropertyAsString(key);
}
size_t MessageMap::size()
{
size_t count(0);
for (Ordering::iterator i = messages.begin(); i != messages.end(); ++i) {
- if (i->second.status == QueuedMessage::AVAILABLE) ++count;
+ if (i->second.getState() == AVAILABLE) ++count;
}
return count;
}
@@ -61,116 +50,103 @@ bool MessageMap::empty()
return size() == 0;//TODO: more efficient implementation
}
-void MessageMap::release(const QueuedMessage& message)
+bool MessageMap::deleted(const QueueCursor& cursor)
{
- Ordering::iterator i = messages.find(message.position);
- if (i != messages.end() && i->second.status == QueuedMessage::ACQUIRED) {
- i->second.status = QueuedMessage::AVAILABLE;
- }
-}
-
-bool MessageMap::acquire(const framing::SequenceNumber& position, QueuedMessage& message)
-{
- Ordering::iterator i = messages.find(position);
- if (i != messages.end() && i->second.status == QueuedMessage::AVAILABLE) {
- i->second.status = QueuedMessage::ACQUIRED;
- message = i->second;
+ Ordering::iterator i = messages.find(cursor.position);
+ if (i != messages.end()) {
+ erase(i);
return true;
} else {
return false;
}
}
-bool MessageMap::find(const framing::SequenceNumber& position, QueuedMessage& message)
+Message* MessageMap::find(const QueueCursor& cursor)
{
- Ordering::iterator i = messages.find(position);
- if (i != messages.end() && i->second.status == QueuedMessage::AVAILABLE) {
- message = i->second;
- return true;
- } else {
- return false;
- }
+ if (cursor.valid) return find(cursor.position, 0);
+ else return 0;
}
-bool MessageMap::browse(const framing::SequenceNumber& position, QueuedMessage& message, bool unacquired)
+Message* MessageMap::find(const framing::SequenceNumber& position, QueueCursor* cursor)
{
- Ordering::iterator i = messages.lower_bound(position+1);
- if (i != messages.end() && (i->second.status == QueuedMessage::AVAILABLE || (!unacquired && i->second.status == QueuedMessage::ACQUIRED))) {
- message = i->second;
- return true;
+ Ordering::iterator i = messages.lower_bound(position);
+ if (i != messages.end()) {
+ if (cursor) cursor->setPosition(i->first, version);
+ if (i->first == position) return &(i->second);
+ else return 0;
} else {
- return false;
+ //there is no message whose sequence is greater than position,
+ //i.e. haven't got there yet
+ if (cursor) cursor->setPosition(position, version);
+ return 0;
}
}
-bool MessageMap::consume(QueuedMessage& message)
+Message* MessageMap::next(QueueCursor& cursor)
{
- for (Ordering::iterator i = messages.begin(); i != messages.end(); ++i) {
- if (i->second.status == QueuedMessage::AVAILABLE) {
- i->second.status = QueuedMessage::ACQUIRED;
- message = i->second;
- return true;
+ Ordering::iterator i;
+ if (!cursor.valid) i = messages.begin(); //start with oldest message
+ else i = messages.upper_bound(cursor.position); //get first message that is greater than position
+
+ while (i != messages.end()) {
+ Message& m = i->second;
+ cursor.setPosition(m.getSequence(), version);
+ if (cursor.check(m)) {
+ return &m;
+ } else {
+ ++i;
}
}
- return false;
+ return 0;
}
-const QueuedMessage& MessageMap::replace(const QueuedMessage& original, const QueuedMessage& update)
+const Message& MessageMap::replace(const Message& original, const Message& update)
{
- messages.erase(original.position);
- messages[update.position] = update;
- return update;
+ messages.erase(original.getSequence());
+ std::pair<Ordering::iterator, bool> i = messages.insert(Ordering::value_type(update.getSequence(), update));
+ i.first->second.setState(AVAILABLE);
+ return i.first->second;
}
-bool MessageMap::push(const QueuedMessage& added, QueuedMessage& removed)
+void MessageMap::publish(const Message& added)
+{
+ Message dummy;
+ update(added, dummy);
+}
+
+bool MessageMap::update(const Message& added, Message& removed)
{
std::pair<Index::iterator, bool> result = index.insert(Index::value_type(getKey(added), added));
if (result.second) {
//there was no previous message for this key; nothing needs to
//be removed, just add the message into its correct position
- QueuedMessage& a = messages[added.position];
- a = added;
- a.status = QueuedMessage::AVAILABLE;
- QPID_LOG(debug, "Added message " << a);
+ messages.insert(Ordering::value_type(added.getSequence(), added)).first->second.setState(AVAILABLE);
return false;
} else {
//there is already a message with that key which needs to be replaced
removed = result.first->second;
result.first->second = replace(result.first->second, added);
- result.first->second.status = QueuedMessage::AVAILABLE;
- QPID_LOG(debug, "Displaced message " << removed << " with " << result.first->second << ": " << result.first->first);
+ result.first->second.setState(AVAILABLE);
+ QPID_LOG(debug, "Displaced message at " << removed.getSequence() << " with " << result.first->second.getSequence() << ": " << result.first->first);
return true;
}
}
-void MessageMap::setPosition(const framing::SequenceNumber& seq) {
- // Nothing to do, just assert that the precondition is respected and there
- // are no undeleted messages after seq.
- (void) seq; assert(messages.empty() || (--messages.end())->first <= seq);
-}
-
-void MessageMap::foreach(Functor f)
+Message* MessageMap::release(const QueueCursor& cursor)
{
- for (Ordering::iterator i = messages.begin(); i != messages.end(); ++i) {
- if (i->second.status == QueuedMessage::AVAILABLE) f(i->second);
+ Ordering::iterator i = messages.find(cursor.position);
+ if (i != messages.end()) {
+ i->second.setState(AVAILABLE);
+ return &i->second;
+ } else {
+ return 0;
}
}
-void MessageMap::removeIf(Predicate p)
+void MessageMap::foreach(Functor f)
{
- for (Ordering::iterator i = messages.begin(); i != messages.end();) {
- if (i->second.status == QueuedMessage::AVAILABLE && p(i->second)) {
- index.erase(getKey(i->second));
- //Note: Removing from messages means that the subsequent
- //call to deleted() for the same message will return
- //false. At present that is not a problem. If this were
- //changed to hold onto the message until dequeued
- //(e.g. with REMOVED state), then the erase() below would
- //need to take that into account.
- messages.erase(i++);
- } else {
- ++i;
- }
+ for (Ordering::iterator i = messages.begin(); i != messages.end(); ++i) {
+ if (i->second.getState() == AVAILABLE) f(i->second);
}
}
@@ -180,6 +156,6 @@ void MessageMap::erase(Ordering::iterator i)
messages.erase(i);
}
-MessageMap::MessageMap(const std::string& k) : key(k) {}
+MessageMap::MessageMap(const std::string& k) : key(k), version(0) {}
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/MessageMap.h b/cpp/src/qpid/broker/MessageMap.h
index 1f0481cb6b..c30606d0ff 100644
--- a/cpp/src/qpid/broker/MessageMap.h
+++ b/cpp/src/qpid/broker/MessageMap.h
@@ -6,7 +6,7 @@
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
-o * regarding copyright ownership. The ASF licenses this file
+ * regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
@@ -22,6 +22,7 @@ o * regarding copyright ownership. The ASF licenses this file
*
*/
#include "qpid/broker/Messages.h"
+#include "qpid/broker/Message.h"
#include "qpid/framing/SequenceNumber.h"
#include <map>
#include <string>
@@ -38,32 +39,31 @@ class MessageMap : public Messages
{
public:
MessageMap(const std::string& key);
- virtual ~MessageMap() {}
size_t size();
bool empty();
- virtual bool deleted(const QueuedMessage&);
- void release(const QueuedMessage&);
- virtual bool acquire(const framing::SequenceNumber&, QueuedMessage&);
- bool find(const framing::SequenceNumber&, QueuedMessage&);
- virtual bool browse(const framing::SequenceNumber&, QueuedMessage&, bool);
- bool consume(QueuedMessage&);
- virtual bool push(const QueuedMessage& added, QueuedMessage& removed);
- void setPosition(const framing::SequenceNumber&);
+ bool deleted(const QueueCursor&);
+ void publish(const Message& added);//use update instead to get replaced message
+ Message* next(QueueCursor&);
+ Message* release(const QueueCursor& cursor);
+ Message* find(const QueueCursor&);
+ Message* find(const framing::SequenceNumber&, QueueCursor*);
void foreach(Functor);
- virtual void removeIf(Predicate);
+
+ bool update(const Message& added, Message& removed);
protected:
- typedef std::map<std::string, QueuedMessage> Index;
- typedef std::map<framing::SequenceNumber, QueuedMessage> Ordering;
+ typedef std::map<std::string, Message> Index;
+ typedef std::map<framing::SequenceNumber, Message> Ordering;
const std::string key;
Index index;
Ordering messages;
+ int32_t version;
- std::string getKey(const QueuedMessage&);
- virtual const QueuedMessage& replace(const QueuedMessage&, const QueuedMessage&);
+ std::string getKey(const Message&);
+ virtual const Message& replace(const Message&, const Message&);
void erase(Ordering::iterator);
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Messages.h b/cpp/src/qpid/broker/Messages.h
index 45f5e6cd81..a94ac7e0bf 100644
--- a/cpp/src/qpid/broker/Messages.h
+++ b/cpp/src/qpid/broker/Messages.h
@@ -29,7 +29,8 @@ namespace framing {
class SequenceNumber;
}
namespace broker {
-struct QueuedMessage;
+class Message;
+class QueueCursor;
/**
* This interface abstracts out the access to the messages held for
@@ -39,8 +40,7 @@ struct QueuedMessage;
class Messages
{
public:
- typedef boost::function1<void, QueuedMessage&> Functor;
- typedef boost::function1<bool, QueuedMessage&> Predicate;
+ typedef boost::function1<void, Message&> Functor;
virtual ~Messages() {}
/**
@@ -51,47 +51,44 @@ class Messages
/**
* Called when a message is deleted from the queue.
*/
- virtual bool deleted(const QueuedMessage&) = 0;
+ virtual bool deleted(const QueueCursor&) = 0;
/**
- * Releases an acquired message, making it available again.
+ * Makes a message available.
*/
- virtual void release(const QueuedMessage&) = 0;
+ virtual void publish(const Message& added) = 0;
/**
- * Acquire the message at the specified position, returning true
- * if found, false otherwise. The acquired message is passed back
- * via the second parameter.
- */
- virtual bool acquire(const framing::SequenceNumber&, QueuedMessage&) = 0;
- /**
- * Find the message at the specified position, returning true if
- * found, false otherwise. The matched message is passed back via
- * the second parameter.
+ * Retrieve the next message for the given cursor. A reference to
+ * the message is passed back via the second parameter.
+ *
+ * @return a pointer to the message if there is one, in which case
+ * the cursor that points to it is assigned to cursor; null
+ * otherwise.
*/
- virtual bool find(const framing::SequenceNumber&, QueuedMessage&) = 0;
+ virtual Message* next(QueueCursor& cursor) = 0;
+
/**
- * Retrieve the next message to be given to a browsing
- * subscription that has reached the specified position. The next
- * message is passed back via the second parameter.
+ * Release the message i.e. return it to the available state
+ * unless it has already been deleted.
*
- * @param unacquired, if true, will only browse unacquired messages
- *
- * @return true if there is another message, false otherwise.
+ * @return a pointer to the Message if it is still in acquired state and
+ * hence can be released; null if it has already been deleted
*/
- virtual bool browse(const framing::SequenceNumber&, QueuedMessage&, bool unacquired) = 0;
+ virtual Message* release(const QueueCursor& cursor) = 0;
/**
- * Retrieve the next message available for a consuming
- * subscription.
- *
- * @return true if there is such a message, false otherwise.
+ * Find the message with the specified sequence number, returning
+ * a pointer if found, null otherwise. A cursor to the matched
+ * message can be passed back via the second parameter, regardless
+ * of whether the message is found, using this cursor to call
+ * next() will give the next message greater than position if one
+ * exists.
*/
- virtual bool consume(QueuedMessage&) = 0;
+ virtual Message* find(const framing::SequenceNumber&, QueueCursor*) = 0;
+
/**
- * Pushes a message to the back of the 'queue'. For some types of
- * queue this may cause another message to be removed; if that is
- * the case the method will return true and the removed message
- * will be passed out via the second parameter.
+ * Find the message at the specified position, returning a pointer if
+ * found, null otherwise.
*/
- virtual bool push(const QueuedMessage& added, QueuedMessage& removed) = 0;
+ virtual Message* find(const QueueCursor&) = 0;
/**
* Add an already acquired message to the queue.
@@ -99,25 +96,11 @@ class Messages
* Only need be implemented by subclasses that keep track of
* acquired messages.
*/
- virtual void updateAcquired(const QueuedMessage&) { }
-
- /**
- * Set the position of the back of the queue. Next message enqueued will be n+1.
- *@pre Any messages with seq > n must already be dequeued.
- */
- virtual void setPosition(const framing::SequenceNumber& /*n*/) = 0;
-
+ //virtual void updateAcquired(const QueuedMessage&) { }
/**
* Apply, the functor to each message held
*/
-
virtual void foreach(Functor) = 0;
- /**
- * Remove every message held that for which the specified
- * predicate returns true
- */
- virtual void removeIf(Predicate) = 0;
-
private:
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Persistable.h b/cpp/src/qpid/broker/Persistable.h
index 36499c7a1a..444aca3295 100644
--- a/cpp/src/qpid/broker/Persistable.h
+++ b/cpp/src/qpid/broker/Persistable.h
@@ -32,7 +32,7 @@ namespace broker {
/**
* Base class for all persistable objects
*/
-class Persistable : public RefCounted
+class Persistable : public virtual RefCounted
{
public:
/**
diff --git a/cpp/src/qpid/broker/PersistableMessage.cpp b/cpp/src/qpid/broker/PersistableMessage.cpp
index 957248b522..9601b8dcce 100644
--- a/cpp/src/qpid/broker/PersistableMessage.cpp
+++ b/cpp/src/qpid/broker/PersistableMessage.cpp
@@ -30,163 +30,58 @@ using namespace qpid::broker;
namespace qpid {
namespace broker {
+PersistableMessage::PersistableMessage() : ingressCompletion(0), persistenceId(0) {}
PersistableMessage::~PersistableMessage() {}
-PersistableMessage::PersistableMessage() :
- asyncDequeueCounter(0),
- store(0),
- asyncStore(0)
-{}
-
-void PersistableMessage::flush()
+void PersistableMessage::setIngressCompletion(boost::intrusive_ptr<AsyncCompletion> i)
{
- syncList copy;
- {
- sys::ScopedLock<sys::Mutex> l(storeLock);
- if (store) {
- copy = synclist;
- } else {
- return;//early exit as nothing to do
- }
+ ingressCompletion = i.get();
+ /**
+ * What follows is a hack to account for the fact that the
+ * AsyncCompletion to use may be, but is not always, this same
+ * object.
+ *
+ * This is hopefully temporary, and allows the store interface to
+ * remain unchanged without requiring another object to be allocated
+ * for every message.
+ *
+ * The case in question is where a message previously passed to
+ * the store is modified by some other queue onto which it is
+ * pushed, and then again persisted to the store. These will be
+ * two separate PersistableMessage instances (since the latter now
+ * has different content), but need to share the same
+ * AsyncCompletion (since they refer to the same incoming transfer
+ * command).
+ */
+ if (static_cast<RefCounted*>(ingressCompletion) != static_cast<RefCounted*>(this)) {
+ holder = i;
}
- for (syncList::iterator i = copy.begin(); i != copy.end(); ++i) {
- PersistableQueue::shared_ptr q(i->lock());
- if (q) {
- q->flush();
- }
- }
-}
-
-void PersistableMessage::setContentReleased()
-{
- contentReleaseState.released = true;
}
-bool PersistableMessage::isContentReleased() const
-{
- return contentReleaseState.released;
-}
-
-
-bool PersistableMessage::isStoredOnQueue(PersistableQueue::shared_ptr queue){
- if (store && (queue->getPersistenceId()!=0)) {
- for (syncList::iterator i = synclist.begin(); i != synclist.end(); ++i) {
- PersistableQueue::shared_ptr q(i->lock());
- if (q && q->getPersistenceId() == queue->getPersistenceId()) return true;
- }
- }
- return false;
-}
-
-// deprecated
-void PersistableMessage::addToSyncList(PersistableQueue::shared_ptr queue, MessageStore* _store) {
- if (_store){
- sys::ScopedLock<sys::Mutex> l(storeLock);
- store = _store;
- boost::weak_ptr<PersistableQueue> q(queue);
- synclist.push_back(q);
- }
-}
-void PersistableMessage::addToSyncList(PersistableQueue::shared_ptr queue, AsyncStore* _store) {
- if (_store){
- sys::ScopedLock<sys::Mutex> l(storeLock);
- asyncStore = _store;
- boost::weak_ptr<PersistableQueue> q(queue);
- synclist.push_back(q);
- }
+void PersistableMessage::flush()
+{
+ //TODO: is this really the right place for this?
}
// deprecated
-void PersistableMessage::enqueueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) {
- addToSyncList(queue, _store);
+void PersistableMessage::enqueueAsync(PersistableQueue::shared_ptr, MessageStore*)
+{
enqueueStart();
}
-void PersistableMessage::enqueueAsync(PersistableQueue::shared_ptr queue, AsyncStore* _store) {
- addToSyncList(queue, _store);
+void PersistableMessage::enqueueAsync(PersistableQueue::shared_ptr, AsyncStore*)
+{
enqueueStart();
}
-bool PersistableMessage::isDequeueComplete() {
- sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
- return asyncDequeueCounter == 0;
-}
-
-void PersistableMessage::dequeueComplete() {
- bool notify = false;
- {
- sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
- if (asyncDequeueCounter > 0) {
- if (--asyncDequeueCounter == 0) {
- notify = true;
- }
- }
- }
- if (notify) allDequeuesComplete();
-}
-
-// deprecated
-void PersistableMessage::dequeueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) {
- if (_store){
- sys::ScopedLock<sys::Mutex> l(storeLock);
- store = _store;
- boost::weak_ptr<PersistableQueue> q(queue);
- synclist.push_back(q);
- }
- dequeueAsync();
-}
-
-void PersistableMessage::dequeueAsync(PersistableQueue::shared_ptr queue, AsyncStore* _store) {
- if (_store){
- sys::ScopedLock<sys::Mutex> l(storeLock);
- asyncStore = _store;
- boost::weak_ptr<PersistableQueue> q(queue);
- synclist.push_back(q);
- }
- dequeueAsync();
-}
-
-void PersistableMessage::dequeueAsync() {
- sys::ScopedLock<sys::Mutex> l(asyncDequeueLock);
- asyncDequeueCounter++;
-}
-
-PersistableMessage::ContentReleaseState::ContentReleaseState() : blocked(false), requested(false), released(false) {}
-
// deprecated
-void PersistableMessage::setStore(MessageStore* s)
-{
- store = s;
-}
-
-void PersistableMessage::setStore(AsyncStore* s)
-{
- asyncStore = s;
-}
+void PersistableMessage::dequeueAsync(PersistableQueue::shared_ptr, MessageStore*) {}
-void PersistableMessage::requestContentRelease()
-{
- contentReleaseState.requested = true;
-}
-void PersistableMessage::blockContentRelease()
-{
- contentReleaseState.blocked = true;
-}
-bool PersistableMessage::checkContentReleasable()
-{
- return contentReleaseState.requested && !contentReleaseState.blocked;
-}
+void PersistableMessage::dequeueAsync(PersistableQueue::shared_ptr, AsyncStore*) {}
-bool PersistableMessage::isContentReleaseBlocked()
-{
- return contentReleaseState.blocked;
-}
-
-bool PersistableMessage::isContentReleaseRequested()
-{
- return contentReleaseState.requested;
-}
+bool PersistableMessage::isDequeueComplete() { return false; }
+void PersistableMessage::dequeueComplete() {}
}}
diff --git a/cpp/src/qpid/broker/PersistableMessage.h b/cpp/src/qpid/broker/PersistableMessage.h
index 8823cfa638..be2910280c 100644
--- a/cpp/src/qpid/broker/PersistableMessage.h
+++ b/cpp/src/qpid/broker/PersistableMessage.h
@@ -24,30 +24,32 @@
#include <string>
#include <list>
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
+#include <map>
+#include <boost/intrusive_ptr.hpp>
#include "qpid/broker/BrokerImportExport.h"
#include "qpid/broker/Persistable.h"
#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/amqp_framing.h"
#include "qpid/sys/Mutex.h"
#include "qpid/broker/PersistableQueue.h"
#include "qpid/broker/AsyncCompletion.h"
+#include "qpid/broker/MessageHandle.h"
namespace qpid {
+namespace types {
+class Variant;
+}
namespace broker {
class MessageStore;
class AsyncStore;
+class Queue;
/**
* Base class for persistable messages.
*/
class PersistableMessage : public Persistable
{
- typedef std::list< boost::weak_ptr<PersistableQueue> > syncList;
- sys::Mutex asyncDequeueLock;
- sys::Mutex storeLock;
-
/**
* "Ingress" messages == messages sent _to_ the broker.
* Tracks the number of outstanding asynchronous operations that must
@@ -57,72 +59,26 @@ class PersistableMessage : public Persistable
* operations have completed, the transfer of this message from the client
* may be considered complete.
*/
- AsyncCompletion ingressCompletion;
-
- /**
- * Tracks the number of outstanding asynchronous dequeue
- * operations. When the message is dequeued asynchronously the
- * count is incremented; when that dequeue completes it is
- * decremented. Thus when it is 0, there are no outstanding
- * dequeues.
- */
- int asyncDequeueCounter;
-
- void dequeueAsync();
-
- syncList synclist;
- struct ContentReleaseState
- {
- bool blocked;
- bool requested;
- bool released;
-
- ContentReleaseState();
- };
- ContentReleaseState contentReleaseState;
-
- protected:
- /** Called when all dequeues are complete for this message. */
- virtual void allDequeuesComplete() = 0;
-
- void setContentReleased();
-
- MessageStore* store; // deprecated, use AsyncStore
- AsyncStore* asyncStore; // new AsyncStore interface
-
+ AsyncCompletion* ingressCompletion;
+ boost::intrusive_ptr<AsyncCompletion> holder;
+ mutable uint64_t persistenceId;
+ MessageHandle msgHandle;
public:
- typedef boost::shared_ptr<PersistableMessage> shared_ptr;
-
- /**
- * @returns the size of the headers when encoded
- */
- virtual uint32_t encodedHeaderSize() const = 0;
-
- virtual ~PersistableMessage();
-
PersistableMessage();
+ virtual ~PersistableMessage();
void flush();
-
- QPID_BROKER_EXTERN bool isContentReleased() const;
-
- QPID_BROKER_EXTERN void setStore(MessageStore*); // deprecated
- QPID_BROKER_EXTERN void setStore(AsyncStore*);
- void requestContentRelease();
- void blockContentRelease();
- bool checkContentReleasable();
- bool isContentReleaseBlocked();
- bool isContentReleaseRequested();
virtual QPID_BROKER_EXTERN bool isPersistent() const = 0;
/** track the progress of a message received by the broker - see ingressCompletion above */
- QPID_BROKER_INLINE_EXTERN bool isIngressComplete() { return ingressCompletion.isDone(); }
- QPID_BROKER_INLINE_EXTERN AsyncCompletion& getIngressCompletion() { return ingressCompletion; }
+ QPID_BROKER_INLINE_EXTERN bool isIngressComplete() { return ingressCompletion->isDone(); }
+ QPID_BROKER_INLINE_EXTERN AsyncCompletion& getIngressCompletion() { return *ingressCompletion; }
+ QPID_BROKER_EXTERN void setIngressCompletion(boost::intrusive_ptr<AsyncCompletion> i);
- QPID_BROKER_INLINE_EXTERN void enqueueStart() { ingressCompletion.startCompleter(); }
- QPID_BROKER_INLINE_EXTERN void enqueueComplete() { ingressCompletion.finishCompleter(); }
+ QPID_BROKER_INLINE_EXTERN void enqueueStart() { ingressCompletion->startCompleter(); }
+ QPID_BROKER_INLINE_EXTERN void enqueueComplete() { ingressCompletion->finishCompleter(); }
QPID_BROKER_EXTERN void enqueueAsync(PersistableQueue::shared_ptr queue, // deprecated
MessageStore* _store);
@@ -131,18 +87,23 @@ class PersistableMessage : public Persistable
QPID_BROKER_EXTERN bool isDequeueComplete();
-
QPID_BROKER_EXTERN void dequeueComplete();
-
QPID_BROKER_EXTERN void dequeueAsync(PersistableQueue::shared_ptr queue, // deprecated
MessageStore* _store);
QPID_BROKER_EXTERN void dequeueAsync(PersistableQueue::shared_ptr queue,
AsyncStore* _store);
- bool isStoredOnQueue(PersistableQueue::shared_ptr queue);
-
- void addToSyncList(PersistableQueue::shared_ptr queue, MessageStore* _store); // deprecated
- void addToSyncList(PersistableQueue::shared_ptr queue, AsyncStore* _store);
+ uint64_t getPersistenceId() const { return persistenceId; }
+ void setPersistenceId(uint64_t _persistenceId) const { persistenceId = _persistenceId; }
+
+ MessageHandle& getMessageHandle() { return msgHandle; }
+ const MessageHandle& getMessagehandle() const { return msgHandle; }
+
+
+ virtual void decodeHeader(framing::Buffer& buffer) = 0;
+ virtual void decodeContent(framing::Buffer& buffer) = 0;
+ virtual uint32_t encodedHeaderSize() const = 0;
+ virtual boost::intrusive_ptr<PersistableMessage> merge(const std::map<std::string, qpid::types::Variant>& annotations) const = 0;
};
}}
diff --git a/cpp/src/qpid/broker/PriorityQueue.cpp b/cpp/src/qpid/broker/PriorityQueue.cpp
index 9a0fead744..99488ded13 100644
--- a/cpp/src/qpid/broker/PriorityQueue.cpp
+++ b/cpp/src/qpid/broker/PriorityQueue.cpp
@@ -19,24 +19,53 @@
*
*/
#include "qpid/broker/PriorityQueue.h"
+#include "qpid/broker/Message.h"
#include "qpid/broker/Queue.h"
-#include "qpid/broker/QueuedMessage.h"
+#include "qpid/broker/QueueCursor.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/log/Statement.h"
+#include <algorithm>
#include <cmath>
+#include <boost/bind.hpp>
namespace qpid {
namespace broker {
+namespace {
+class PriorityContext : public CursorContext {
+ public:
+ std::vector<QueueCursor> position;
+ PriorityContext(size_t levels, SubscriptionType type) : position(levels, QueueCursor(type)) {}
+};
+}
+
PriorityQueue::PriorityQueue(int l) :
levels(l),
- messages(levels, Deque()),
- frontLevel(0), haveFront(false), cached(false) {}
+ messages(levels, Deque(boost::bind(&PriorityQueue::priorityPadding, this, _1))),
+ counters(levels, framing::SequenceNumber()),
+ fifo(boost::bind(&PriorityQueue::fifoPadding, this, _1)),
+ frontLevel(0), haveFront(false), cached(false)
+{
+}
-bool PriorityQueue::deleted(const QueuedMessage& qm) {
- bool deleted = fifo.deleted(qm);
- if (deleted) erase(qm);
- return deleted;
+bool PriorityQueue::deleted(const QueueCursor& c)
+{
+ MessagePointer* ptr = fifo.find(c);
+ if (ptr && ptr->holder) {
+ //mark the message as deleted
+ ptr->holder->message.setState(DELETED);
+ //clean the deque for the relevant priority level
+ boost::shared_ptr<PriorityContext> ctxt = boost::dynamic_pointer_cast<PriorityContext>(c.context);
+ messages[ptr->holder->priority].clean();
+ //stop referencing that message holder (it may now have been
+ //deleted)
+ ptr->holder = 0;
+ //clean fifo index
+ fifo.clean();
+ return true;
+ } else {
+ return false;
+ }
}
size_t PriorityQueue::size()
@@ -44,85 +73,69 @@ size_t PriorityQueue::size()
return fifo.size();
}
-namespace {
-bool before(QueuedMessage* a, QueuedMessage* b) { return *a < *b; }
-}
-
-void PriorityQueue::release(const QueuedMessage& message)
-{
- QueuedMessage* qm = fifo.releasePtr(message);
- if (qm) {
- uint p = getPriorityLevel(message);
- messages[p].insert(
- lower_bound(messages[p].begin(), messages[p].end(), qm, before), qm);
- clearCache();
+Message* PriorityQueue::next(QueueCursor& cursor)
+{
+ boost::shared_ptr<PriorityContext> ctxt = boost::dynamic_pointer_cast<PriorityContext>(cursor.context);
+ if (!ctxt) {
+ ctxt = boost::shared_ptr<PriorityContext>(new PriorityContext(levels, CONSUMER));
+ cursor.context = ctxt;
}
-}
-
-
-void PriorityQueue::erase(const QueuedMessage& qm) {
- size_t i = getPriorityLevel(qm);
- if (!messages[i].empty()) {
- long diff = qm.position.getValue() - messages[i].front()->position.getValue();
- if (diff < 0) return;
- long maxEnd = std::min(size_t(diff), messages[i].size());
- QueuedMessage mutableQm = qm; // need non-const qm for lower_bound
- Deque::iterator l =
- lower_bound(messages[i].begin(),messages[i].begin()+maxEnd, &mutableQm, before);
- if (l != messages[i].end() && (*l)->position == qm.position) {
- messages[i].erase(l);
- clearCache();
- return;
+ if (cursor.type == REPLICATOR) {
+ //browse in fifo order
+ MessagePointer* ptr = fifo.next(cursor);
+ return ptr ? &(ptr->holder->message) : 0;
+ } else if (cursor.type == PURGE) {
+ //iterate over message in reverse priority order (i.e. purge lowest priority message first)
+ //ignore any fairshare configuration here as well
+ for (int p = 0; p < levels; ++p) {
+ MessageHolder* holder = messages[p].next(ctxt->position[p]);
+ if (holder) {
+ cursor.setPosition(holder->message.getSequence(), 0);
+ return &(holder->message);
+ }
}
+ return 0;
+ } else {
+ //check each level in turn, in priority order, for any more messages
+ Priority p = firstLevel();
+ do {
+ MessageHolder* holder = messages[p.current].next(ctxt->position[p.current]);
+ if (holder) {
+ cursor.setPosition(holder->message.getSequence(), 0);
+ return &(holder->message);
+ }
+ } while (nextLevel(p));
+ return 0;
}
}
-bool PriorityQueue::acquire(const framing::SequenceNumber& position, QueuedMessage& message)
+Message* PriorityQueue::find(const QueueCursor& cursor)
{
- bool acquired = fifo.acquire(position, message);
- if (acquired) erase(message); // No longer available
- return acquired;
+ return find(cursor.position, 0);
}
-bool PriorityQueue::find(const framing::SequenceNumber& position, QueuedMessage& message)
+Message* PriorityQueue::find(const framing::SequenceNumber& position, QueueCursor* cursor)
{
- return fifo.find(position, message);
+ MessagePointer* ptr = fifo.find(position, cursor);
+ return ptr ? &(ptr->holder->message) : 0;
}
-bool PriorityQueue::browse(
- const framing::SequenceNumber& position, QueuedMessage& message, bool unacquired)
+void PriorityQueue::publish(const Message& published)
{
- return fifo.browse(position, message, unacquired);
+ MessageHolder holder;
+ holder.message = published;
+ holder.priority = getPriorityLevel(published);
+ holder.id = ++(counters[holder.priority]);
+ MessagePointer pointer;
+ pointer.holder = &(messages[holder.priority].publish(holder));
+ pointer.id = published.getSequence();
+ fifo.publish(pointer);
}
-bool PriorityQueue::consume(QueuedMessage& message)
-{
- if (checkFront()) {
- QueuedMessage* pm = messages[frontLevel].front();
- messages[frontLevel].pop_front();
- clearCache();
- pm->status = QueuedMessage::ACQUIRED; // Updates FIFO index
- message = *pm;
- return true;
- } else {
- return false;
- }
-}
-
-bool PriorityQueue::push(const QueuedMessage& added, QueuedMessage& /*not needed*/)
+Message* PriorityQueue::release(const QueueCursor& cursor)
{
- QueuedMessage* qmp = fifo.pushPtr(added);
- messages[getPriorityLevel(added)].push_back(qmp);
- clearCache();
- return false; // Adding a message never causes one to be removed for deque
-}
-
-void PriorityQueue::updateAcquired(const QueuedMessage& acquired) {
- fifo.updateAcquired(acquired);
-}
-
-void PriorityQueue::setPosition(const framing::SequenceNumber& n) {
- fifo.setPosition(n);
+ MessagePointer* ptr = fifo.release(cursor);
+ return ptr ? &(ptr->holder->message) : 0;
}
void PriorityQueue::foreach(Functor f)
@@ -130,62 +143,87 @@ void PriorityQueue::foreach(Functor f)
fifo.foreach(f);
}
-void PriorityQueue::removeIf(Predicate p)
-{
- for (int priority = 0; priority < levels; ++priority) {
- for (Deque::iterator i = messages[priority].begin(); i != messages[priority].end();) {
- if (p(**i)) {
- (*i)->status = QueuedMessage::DELETED; // Updates fifo index
- i = messages[priority].erase(i);
- clearCache();
- } else {
- ++i;
- }
- }
- }
- fifo.clean();
-}
-
-uint PriorityQueue::getPriorityLevel(const QueuedMessage& m) const
+uint PriorityQueue::getPriorityLevel(const Message& m) const
{
- uint priority = m.payload->getPriority();
+ uint priority = m.getPriority();
//Use AMQP 0-10 approach to mapping priorities to a fixed level
//(see rule priority-level-implementation)
const uint firstLevel = 5 - uint(std::min(5.0, std::ceil((double) levels/2.0)));
if (priority <= firstLevel) return 0;
return std::min(priority - firstLevel, (uint)levels-1);
}
+PriorityQueue::MessagePointer PriorityQueue::fifoPadding(qpid::framing::SequenceNumber id)
+{
+ PriorityQueue::MessagePointer pointer;
+ pointer.holder = 0;
+ pointer.id = id;
+ return pointer;
+}
-void PriorityQueue::clearCache()
+PriorityQueue::MessageHolder PriorityQueue::priorityPadding(qpid::framing::SequenceNumber id)
{
- cached = false;
+ PriorityQueue::MessageHolder holder;
+ holder.id = id;
+ holder.message.setState(DELETED);
+ return holder;
}
-bool PriorityQueue::findFrontLevel(uint& l, PriorityLevels& m)
+PriorityQueue::Priority PriorityQueue::firstLevel()
{
- for (int p = levels-1; p >= 0; --p) {
- if (!m[p].empty()) {
- l = p;
- return true;
- }
+ return Priority(levels - 1);
+}
+bool PriorityQueue::nextLevel(Priority& p)
+{
+ if (p.current > 0) {
+ --(p.current);
+ return true;
+ } else {
+ return false;
}
- return false;
}
-bool PriorityQueue::checkFront()
+framing::SequenceNumber PriorityQueue::MessageHolder::getSequence() const
+{
+ return id;
+}
+void PriorityQueue::MessageHolder::setState(MessageState s)
+{
+ message.setState(s);
+}
+MessageState PriorityQueue::MessageHolder::getState() const
+{
+ return message.getState();
+}
+PriorityQueue::MessageHolder::operator Message&()
+{
+ return message;
+}
+framing::SequenceNumber PriorityQueue::MessagePointer::getSequence() const
{
- if (!cached) {
- haveFront = findFrontLevel(frontLevel, messages);
- cached = true;
+ if (holder) {
+ return holder->message.getSequence();
+ } else {
+ //this is used when the instance is merely acting as padding
+ return id;
}
- return haveFront;
}
-
-uint PriorityQueue::getPriority(const QueuedMessage& message)
+void PriorityQueue::MessagePointer::setState(MessageState s)
{
- const PriorityQueue* queue = dynamic_cast<const PriorityQueue*>(&(message.queue->getMessages()));
- if (queue) return queue->getPriorityLevel(message);
- else return 0;
+ if (holder) {
+ holder->message.setState(s);
+ }
+}
+MessageState PriorityQueue::MessagePointer::getState() const
+{
+ if (holder) {
+ return holder->message.getState();
+ } else {
+ return DELETED;
+ }
+}
+PriorityQueue::MessagePointer::operator Message&()
+{
+ assert(holder);
+ return holder->message;
}
-
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/PriorityQueue.h b/cpp/src/qpid/broker/PriorityQueue.h
index 301367358b..16432bfb54 100644
--- a/cpp/src/qpid/broker/PriorityQueue.h
+++ b/cpp/src/qpid/broker/PriorityQueue.h
@@ -22,6 +22,7 @@
*
*/
#include "qpid/broker/MessageDeque.h"
+#include "qpid/broker/IndexedDeque.h"
#include "qpid/sys/IntegerTypes.h"
#include <deque>
#include <vector>
@@ -44,42 +45,63 @@ class PriorityQueue : public Messages
virtual ~PriorityQueue() {}
size_t size();
- bool deleted(const QueuedMessage&);
- void release(const QueuedMessage&);
- bool acquire(const framing::SequenceNumber&, QueuedMessage&);
- bool find(const framing::SequenceNumber&, QueuedMessage&);
- bool browse(const framing::SequenceNumber&, QueuedMessage&, bool);
- bool consume(QueuedMessage&);
- bool push(const QueuedMessage& added, QueuedMessage& removed);
- void updateAcquired(const QueuedMessage& acquired);
- void setPosition(const framing::SequenceNumber&);
- void foreach(Functor);
- void removeIf(Predicate);
-
- static uint getPriority(const QueuedMessage&);
+ bool deleted(const QueueCursor&);
+ void publish(const Message& added);
+ Message* next(QueueCursor&);
+ Message* release(const QueueCursor& cursor);
+ Message* find(const QueueCursor&);
+ Message* find(const framing::SequenceNumber&, QueueCursor*);
+ void foreach(Functor);
+ static uint getPriority(const Message&);
protected:
- typedef std::deque<QueuedMessage*> Deque;
- typedef std::vector<Deque> PriorityLevels;
- virtual bool findFrontLevel(uint& p, PriorityLevels&);
-
const int levels;
+ struct Priority
+ {
+ const int start;
+ int current;
+ Priority(int s) : start(s), current(start) {}
+ };
+ virtual Priority firstLevel();
+ virtual bool nextLevel(Priority& );
private:
- /** Available messages separated by priority and sorted in priority order.
- * Holds pointers to the QueuedMessages in fifo
+ struct MessageHolder
+ {
+ Message message;
+ int priority;
+ framing::SequenceNumber id;
+ framing::SequenceNumber getSequence() const;
+ void setState(MessageState);
+ MessageState getState() const;
+ operator Message&();
+ };
+ struct MessagePointer
+ {
+ MessageHolder* holder;
+ framing::SequenceNumber id;//used only for padding
+ framing::SequenceNumber getSequence() const;
+ void setState(MessageState);
+ MessageState getState() const;
+ operator Message&();
+ };
+ typedef IndexedDeque<MessageHolder> Deque;
+ typedef std::vector<Deque> PriorityLevels;
+ typedef std::vector<framing::SequenceNumber> Counters;
+
+ /** Holds pointers to messages (stored in the fifo index) separated by priority.
*/
PriorityLevels messages;
- /** FIFO index of all messsagse (including acquired messages) for fast browsing and indexing */
- MessageDeque fifo;
+ Counters counters;
+ /** FIFO index of messages for fast browsing and indexing */
+ IndexedDeque<MessagePointer> fifo;
uint frontLevel;
bool haveFront;
bool cached;
- void erase(const QueuedMessage&);
- uint getPriorityLevel(const QueuedMessage&) const;
- void clearCache();
- bool checkFront();
+ uint getPriorityLevel(const Message&) const;
+ MessageHolder priorityPadding(qpid::framing::SequenceNumber);
+ MessagePointer fifoPadding(qpid::framing::SequenceNumber);
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Queue.cpp b/cpp/src/qpid/broker/Queue.cpp
index d5267c78dc..0dd4cb7b10 100644
--- a/cpp/src/qpid/broker/Queue.cpp
+++ b/cpp/src/qpid/broker/Queue.cpp
@@ -20,23 +20,23 @@
*/
#include "qpid/broker/Queue.h"
-
#include "qpid/broker/Broker.h"
-#include "qpid/broker/QueueEvents.h"
+#include "qpid/broker/QueueCursor.h"
+#include "qpid/broker/QueueDepth.h"
+#include "qpid/broker/QueueSettings.h"
#include "qpid/broker/Exchange.h"
-#include "qpid/broker/Fairshare.h"
#include "qpid/broker/DeliverableMessage.h"
-#include "qpid/broker/LegacyLVQ.h"
-#include "qpid/broker/MessageDeque.h"
-#include "qpid/broker/MessageMap.h"
#include "qpid/broker/MessageStore.h"
+#include "qpid/broker/MessageDeque.h"
+#include "qpid/broker/MessageDistributor.h"
+#include "qpid/broker/FifoDistributor.h"
#include "qpid/broker/NullMessageStore.h"
#include "qpid/broker/QueueRegistry.h"
-#include "qpid/broker/QueueFlowLimit.h"
-#include "qpid/broker/ThresholdAlerts.h"
-#include "qpid/broker/FifoDistributor.h"
-#include "qpid/broker/MessageGroupManager.h"
+//TODO: get rid of this
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
+
+#include "qpid/amqp_0_10/Codecs.h"
#include "qpid/StringUtils.h"
#include "qpid/log/Statement.h"
#include "qpid/management/ManagementAgent.h"
@@ -76,26 +76,8 @@ namespace _qmf = qmf::org::apache::qpid::broker;
namespace
{
-const std::string qpidMaxSize("qpid.max_size");
-const std::string qpidMaxCount("qpid.max_count");
-const std::string qpidNoLocal("no-local");
-const std::string qpidTraceIdentity("qpid.trace.id");
-const std::string qpidTraceExclude("qpid.trace.exclude");
-const std::string qpidLastValueQueueKey("qpid.last_value_queue_key");
-const std::string qpidLastValueQueue("qpid.last_value_queue");
-const std::string qpidLastValueQueueNoBrowse("qpid.last_value_queue_no_browse");
-const std::string qpidPersistLastNode("qpid.persist_last_node");
-const std::string qpidVQMatchProperty("qpid.LVQ_key");
-const std::string qpidQueueEventGeneration("qpid.queue_event_generation");
-const std::string qpidAutoDeleteTimeout("qpid.auto_delete_timeout");
-//following feature is not ready for general use as it doesn't handle
-//the case where a message is enqueued on more than one queue well enough:
-const std::string qpidInsertSequenceNumbers("qpid.insert_sequence_numbers");
-
-const int ENQUEUE_ONLY=1;
-const int ENQUEUE_AND_DEQUEUE=2;
-
-inline void mgntEnqStats(const boost::intrusive_ptr<Message>& msg,
+
+inline void mgntEnqStats(const Message& msg,
_qmf::Queue* mgmtObject,
_qmf::Broker* brokerMgmtObject)
{
@@ -103,12 +85,12 @@ inline void mgntEnqStats(const boost::intrusive_ptr<Message>& msg,
_qmf::Queue::PerThreadStats *qStats = mgmtObject->getStatistics();
_qmf::Broker::PerThreadStats *bStats = brokerMgmtObject->getStatistics();
- uint64_t contentSize = msg->contentSize();
+ uint64_t contentSize = msg.getContentSize();
qStats->msgTotalEnqueues +=1;
bStats->msgTotalEnqueues += 1;
qStats->byteTotalEnqueues += contentSize;
bStats->byteTotalEnqueues += contentSize;
- if (msg->isPersistent ()) {
+ if (msg.isPersistent ()) {
qStats->msgPersistEnqueues += 1;
bStats->msgPersistEnqueues += 1;
qStats->bytePersistEnqueues += contentSize;
@@ -119,20 +101,20 @@ inline void mgntEnqStats(const boost::intrusive_ptr<Message>& msg,
}
}
-inline void mgntDeqStats(const boost::intrusive_ptr<Message>& msg,
+inline void mgntDeqStats(const Message& msg,
_qmf::Queue* mgmtObject,
_qmf::Broker* brokerMgmtObject)
{
if (mgmtObject != 0){
_qmf::Queue::PerThreadStats *qStats = mgmtObject->getStatistics();
_qmf::Broker::PerThreadStats *bStats = brokerMgmtObject->getStatistics();
- uint64_t contentSize = msg->contentSize();
+ uint64_t contentSize = msg.getContentSize();
qStats->msgTotalDequeues += 1;
bStats->msgTotalDequeues += 1;
qStats->byteTotalDequeues += contentSize;
bStats->byteTotalDequeues += contentSize;
- if (msg->isPersistent ()){
+ if (msg.isPersistent ()){
qStats->msgPersistDequeues += 1;
bStats->msgPersistDequeues += 1;
qStats->bytePersistDequeues += contentSize;
@@ -143,43 +125,81 @@ inline void mgntDeqStats(const boost::intrusive_ptr<Message>& msg,
}
}
-} // namespace
+QueueSettings merge(const QueueSettings& inputs, const Broker::Options& globalOptions)
+{
+ QueueSettings settings(inputs);
+ if (!settings.maxDepth.hasSize() && globalOptions.queueLimit) {
+ settings.maxDepth.setSize(globalOptions.queueLimit);
+ }
+ return settings;
+}
+
+}
-Queue::Queue(const string& _name, bool _autodelete,
+Queue::TxPublish::TxPublish(const Message& m, boost::shared_ptr<Queue> q) : message(m), queue(q), prepared(false) {}
+bool Queue::TxPublish::prepare(TransactionContext* ctxt) throw()
+{
+ try {
+ prepared = queue->enqueue(ctxt, message);
+ return true;
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to prepare: " << e.what());
+ return false;
+ }
+}
+void Queue::TxPublish::commit() throw()
+{
+ try {
+ if (prepared) queue->process(message);
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to commit: " << e.what());
+ }
+}
+void Queue::TxPublish::rollback() throw()
+{
+ try {
+ if (prepared) queue->enqueueAborted(message);
+ } catch (const std::exception& e) {
+ QPID_LOG(error, "Failed to rollback: " << e.what());
+ }
+}
+
+Queue::Queue(const string& _name, const QueueSettings& _settings,
MessageStore* const _store,
- const OwnershipToken* const _owner,
Manageable* parent,
Broker* b) :
name(_name),
- autodelete(_autodelete),
store(_store),
- owner(_owner),
+ owner(0),
consumerCount(0),
browserCount(0),
exclusive(0),
- noLocal(false),
persistLastNode(false),
inLastNodeFailure(false),
messages(new MessageDeque()),
persistenceId(0),
- policyExceeded(false),
+ settings(b ? merge(_settings, b->getOptions()) : _settings),
mgmtObject(0),
brokerMgmtObject(0),
eventMode(0),
- insertSeqNo(0),
broker(b),
deleted(false),
barrier(*this),
- autoDeleteTimeout(0),
allocator(new FifoDistributor( *messages ))
{
+ if (settings.maxDepth.hasCount()) current.setCount(0);
+ if (settings.maxDepth.hasSize()) current.setSize(0);
+ if (settings.traceExcludes.size()) {
+ split(traceExclude, settings.traceExcludes, ", ");
+ }
+ qpid::amqp_0_10::translate(settings.asMap(), encodableSettings);
if (parent != 0 && broker != 0) {
ManagementAgent* agent = broker->getManagementAgent();
if (agent != 0) {
- mgmtObject = new _qmf::Queue(agent, this, parent, _name, _store != 0, _autodelete);
- mgmtObject->set_exclusive(_owner != 0);
+ mgmtObject = new _qmf::Queue(agent, this, parent, _name, _store != 0, settings.autodelete);
+ mgmtObject->set_arguments(settings.asMap());
agent->addObject(mgmtObject, 0, store != 0);
brokerMgmtObject = (qmf::org::apache::qpid::broker::Broker*) broker->GetManagementObject();
if (brokerMgmtObject)
@@ -197,32 +217,36 @@ Queue::~Queue()
}
}
-bool isLocalTo(const OwnershipToken* token, boost::intrusive_ptr<Message>& msg)
+bool isLocalTo(const OwnershipToken* token, const Message& msg)
{
- return token && token->isLocal(msg->getPublisher());
+ return token && token->isLocal(msg.getPublisher());
}
-bool Queue::isLocal(boost::intrusive_ptr<Message>& msg)
+bool Queue::isLocal(const Message& msg)
{
//message is considered local if it was published on the same
//connection as that of the session which declared this queue
//exclusive (owner) or which has an exclusive subscription
//(exclusive)
- return noLocal && (isLocalTo(owner, msg) || isLocalTo(exclusive, msg));
+ return settings.noLocal && (isLocalTo(owner, msg) || isLocalTo(exclusive, msg));
}
-bool Queue::isExcluded(boost::intrusive_ptr<Message>& msg)
+bool Queue::isExcluded(const Message& msg)
{
- return traceExclude.size() && msg->isExcluded(traceExclude);
+ return traceExclude.size() && msg.isExcluded(traceExclude);
}
-void Queue::deliver(boost::intrusive_ptr<Message> msg){
+void Queue::deliver(Message msg, TxBuffer* txn){
+ //TODO: move some of this out of the queue and into the publishing
+ //'link' for whatever protocol is used; that would let protocol
+ //specific stuff be kept out the queue
+
// Check for deferred delivery in a cluster.
if (broker && broker->deferDelivery(name, msg))
return;
- if (msg->isImmediate() && getConsumerCount() == 0) {
+ if (broker::amqp_0_10::MessageTransfer::isImmediateDeliveryRequired(msg) && getConsumerCount() == 0) {
if (alternateExchange) {
- DeliverableMessage deliverable(msg);
+ DeliverableMessage deliverable(msg, 0);
alternateExchange->route(deliverable);
}
} else if (isLocal(msg)) {
@@ -232,47 +256,38 @@ void Queue::deliver(boost::intrusive_ptr<Message> msg){
//drop message
QPID_LOG(info, "Dropping excluded message from " << getName());
} else {
- enqueue(0, msg);
- push(msg);
- QPID_LOG(debug, "Message " << msg << " enqueued on " << name);
+ if (txn) {
+ TxOp::shared_ptr op(new TxPublish(msg, shared_from_this()));
+ txn->enlist(op);
+ } else {
+ if (enqueue(0, msg)) {
+ push(msg);
+ QPID_LOG(debug, "Message " << msg << " enqueued on " << name);
+ } else {
+ QPID_LOG(debug, "Message " << msg << " dropped from " << name);
+ }
+ }
}
}
-void Queue::recoverPrepared(boost::intrusive_ptr<Message>& msg)
+void Queue::recoverPrepared(const Message& msg)
{
Mutex::ScopedLock locker(messageLock);
- if (policy.get()) policy->recoverEnqueued(msg);
+ current += QueueDepth(1, msg.getContentSize());
}
-void Queue::recover(boost::intrusive_ptr<Message>& msg)
+void Queue::recover(Message& msg)
{
- {
- Mutex::ScopedLock locker(messageLock);
- if (policy.get()) policy->recoverEnqueued(msg);
- }
-
+ recoverPrepared(msg);
push(msg, true);
- if (store){
- // setup synclist for recovered messages, so they don't get re-stored on lastNodeFailure
- msg->addToSyncList(shared_from_this(), store);
- }
-
- if (store && (!msg->isContentLoaded() || msg->checkContentReleasable())) {
- //content has not been loaded, need to ensure that lazy loading mode is set:
- //TODO: find a nicer way to do this
- msg->releaseContent(store);
- // NOTE: The log message in this section are used for flow-to-disk testing (which checks the log for the
- // presence of this message). Do not change this without also checking these tests.
- QPID_LOG(debug, "Message id=\"" << msg->getProperties<MessageProperties>()->getMessageId() << "\"; pid=0x" <<
- std::hex << msg->getPersistenceId() << std::dec << ": Content released after recovery");
- }
}
-void Queue::process(boost::intrusive_ptr<Message>& msg){
+void Queue::process(Message& msg)
+{
push(msg);
if (mgmtObject != 0){
_qmf::Queue::PerThreadStats *qStats = mgmtObject->getStatistics();
- const uint64_t contentSize = msg->contentSize();
+ const uint64_t contentSize = msg.getContentSize();
qStats->msgTxnEnqueues += 1;
qStats->byteTxnEnqueues += contentSize;
mgmtObject->statisticsUpdated();
@@ -285,46 +300,22 @@ void Queue::process(boost::intrusive_ptr<Message>& msg){
}
}
-void Queue::requeue(const QueuedMessage& msg){
+void Queue::release(const QueueCursor& position, bool markRedelivered)
+{
assertClusterSafe();
QueueListeners::NotificationSet copy;
{
- if (!isEnqueued(msg)) return;
- if (deleted) {
- //
- // If the queue has been deleted, requeued messages must be sent to the alternate exchange
- // if one is configured.
- //
- if (alternateExchange.get()) {
- DeliverableMessage dmsg(msg.payload);
- alternateExchange->routeWithAlternate(dmsg);
- if (brokerMgmtObject)
- brokerMgmtObject->inc_abandonedViaAlt();
- } else {
- if (brokerMgmtObject)
- brokerMgmtObject->inc_abandoned();
- }
- mgntDeqStats(msg.payload, mgmtObject, brokerMgmtObject);
- } else {
- {
- Mutex::ScopedLock locker(messageLock);
- messages->release(msg);
- observeRequeue(msg, locker);
+ Mutex::ScopedLock locker(messageLock);
+ if (!deleted) {
+ Message* message = messages->release(position);
+ if (message) {
+ if (!markRedelivered) message->undeliver();
listeners.populate(copy);
- }
-
- if (mgmtObject) {
- mgmtObject->inc_releases();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_releases();
- }
-
- // for persistLastNode - don't force a message twice to disk, but force it if no force before
- if(inLastNodeFailure && persistLastNode && !msg.payload->isStoredOnQueue(shared_from_this())) {
- msg.payload->forcePersistent();
- if (msg.payload->isForcedPersistent() ){
- boost::intrusive_ptr<Message> payload = msg.payload;
- enqueue(0, payload);
+ observeRequeue(*message, locker);
+ if (mgmtObject) {
+ mgmtObject->inc_releases();
+ if (brokerMgmtObject)
+ brokerMgmtObject->inc_releases();
}
}
}
@@ -332,163 +323,118 @@ void Queue::requeue(const QueuedMessage& msg){
copy.notify();
}
-bool Queue::acquireMessageAt(const SequenceNumber& position, QueuedMessage& message)
+bool Queue::dequeueMessageAt(const SequenceNumber& position)
{
- assertClusterSafe();
- QPID_LOG(debug, "Attempting to acquire message at " << position);
- if (acquire(position, message)) {
- QPID_LOG(debug, "Acquired message at " << position << " from " << name);
- return true;
- } else {
- QPID_LOG(debug, "Could not acquire message at " << position << " from " << name << "; no message at that position");
- return false;
- }
-}
-
-bool Queue::acquire(const QueuedMessage& msg, const std::string& consumer)
-{
- assertClusterSafe();
- QPID_LOG(debug, consumer << " attempting to acquire message at " << msg.position);
- bool ok;
+ boost::intrusive_ptr<PersistableMessage> pmsg;
{
Mutex::ScopedLock locker(messageLock);
- ok = allocator->allocate( consumer, msg );
- }
- if (!ok) {
- QPID_LOG(debug, "Not permitted to acquire msg at " << msg.position << " from '" << name);
- return false;
- }
-
- QueuedMessage copy(msg);
- if (acquire( msg.position, copy)) {
- QPID_LOG(debug, "Acquired message at " << msg.position << " from " << name);
- return true;
+ assertClusterSafe();
+ QPID_LOG(debug, "Attempting to dequeue message at " << position);
+ QueueCursor cursor;
+ Message* msg = messages->find(position, &cursor);
+ if (msg) {
+ if (msg->isPersistent()) pmsg = msg->getPersistentContext();
+ observeDequeue(*msg, locker);
+ messages->deleted(cursor);
+ } else {
+ QPID_LOG(debug, "Could not dequeue message at " << position << "; no such message");
+ return false;
+ }
}
- QPID_LOG(debug, "Could not acquire message at " << msg.position << " from " << name << "; no message at that position");
- return false;
+ dequeueFromStore(pmsg);
+ return true;
}
-void Queue::notifyListener()
+bool Queue::acquire(const QueueCursor& position, const std::string& consumer)
{
+ Mutex::ScopedLock locker(messageLock);
assertClusterSafe();
- QueueListeners::NotificationSet set;
- {
- Mutex::ScopedLock locker(messageLock);
- if (messages->size()) {
- listeners.populate(set);
- }
- }
- set.notify();
-}
+ Message* msg;
-bool Queue::getNextMessage(QueuedMessage& m, Consumer::shared_ptr& c)
-{
- checkNotDeleted(c);
- if (c->preAcquires()) {
- switch (consumeNextMessage(m, c)) {
- case CONSUMED:
- return true;
- case CANT_CONSUME:
- notifyListener();//let someone else try
- case NO_MESSAGES:
- default:
+ msg = messages->find(position);
+ if (msg) {
+ QPID_LOG(debug, consumer << " attempting to acquire message at " << msg->getSequence());
+ if (!allocator->acquire(consumer, *msg)) {
+ QPID_LOG(debug, "Not permitted to acquire msg at " << msg->getSequence() << " from '" << name);
return false;
+ } else {
+ observeAcquire(*msg, locker);
+ QPID_LOG(debug, "Acquired message at " << msg->getSequence() << " from " << name);
+ return true;
}
} else {
- return browseNextMessage(m, c);
+ QPID_LOG(debug, "Failed to acquire message which no longer exists on " << name);
+ return false;
}
}
-Queue::ConsumeCode Queue::consumeNextMessage(QueuedMessage& m, Consumer::shared_ptr& c)
+bool Queue::getNextMessage(Message& m, Consumer::shared_ptr& c)
{
+ checkNotDeleted(c);
+ QueueListeners::NotificationSet set;
while (true) {
- QueuedMessage msg;
- bool found;
- {
- Mutex::ScopedLock locker(messageLock);
- found = allocator->nextConsumableMessage(c, msg);
- if (!found) listeners.addListener(c);
- }
- if (!found) {
- QPID_LOG(debug, "No messages to dispatch on queue '" << name << "'");
- return NO_MESSAGES;
- }
-
- if (msg.payload->hasExpired()) {
- QPID_LOG(debug, "Message expired from queue '" << name << "'");
- c->setPosition(msg.position);
- dequeue(0, msg);
- if (mgmtObject) {
- mgmtObject->inc_discardsTtl();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_discardsTtl();
- }
- continue;
- }
-
- if (c->filter(msg.payload)) {
- if (c->accept(msg.payload)) {
- {
- Mutex::ScopedLock locker(messageLock);
- bool ok = allocator->allocate( c->getName(), msg ); // inform allocator
- (void) ok; assert(ok);
- observeAcquire(msg, locker);
- }
+ //TODO: reduce lock scope
+ Mutex::ScopedLock locker(messageLock);
+ Message* msg = messages->next(*c);
+ if (msg) {
+ if (msg->hasExpired()) {
+ QPID_LOG(debug, "Message expired from queue '" << name << "'");
+ observeDequeue(*msg, locker);
+ //ERROR: don't hold lock across call to store!!
+ if (msg->isPersistent()) dequeueFromStore(msg->getPersistentContext());
if (mgmtObject) {
- mgmtObject->inc_acquires();
+ mgmtObject->inc_discardsTtl();
if (brokerMgmtObject)
- brokerMgmtObject->inc_acquires();
+ brokerMgmtObject->inc_discardsTtl();
}
- m = msg;
- return CONSUMED;
- } else {
- //message(s) are available but consumer hasn't got enough credit
- QPID_LOG(debug, "Consumer can't currently accept message from '" << name << "'");
+ messages->deleted(*c);
+ continue;
}
- } else {
- //consumer will never want this message
- QPID_LOG(debug, "Consumer doesn't want message from '" << name << "'");
- }
-
- Mutex::ScopedLock locker(messageLock);
- messages->release(msg);
- return CANT_CONSUME;
- }
-}
-bool Queue::browseNextMessage(QueuedMessage& m, Consumer::shared_ptr& c)
-{
- while (true) {
- QueuedMessage msg;
- bool found;
- {
- Mutex::ScopedLock locker(messageLock);
- found = allocator->nextBrowsableMessage(c, msg);
- if (!found) listeners.addListener(c);
- }
- if (!found) { // no next available
- QPID_LOG(debug, "No browsable messages available for consumer " <<
- c->getName() << " on queue '" << name << "'");
- return false;
- }
-
- if (c->filter(msg.payload) && !msg.payload->hasExpired()) {
- if (c->accept(msg.payload)) {
- //consumer wants the message
- c->setPosition(msg.position);
- m = msg;
- return true;
+ if (c->filter(*msg)) {
+ if (c->accept(*msg)) {
+ if (c->preAcquires()) {
+ QPID_LOG(debug, "Attempting to acquire message " << msg << " from '" << name << "' with state " << msg->getState());
+ if (allocator->acquire(c->getName(), *msg)) {
+ if (mgmtObject) {
+ mgmtObject->inc_acquires();
+ if (brokerMgmtObject)
+ brokerMgmtObject->inc_acquires();
+ }
+ observeAcquire(*msg, locker);
+ msg->deliver();
+ } else {
+ QPID_LOG(debug, "Could not acquire message from '" << name << "'");
+ continue; //try another message
+ }
+ }
+ QPID_LOG(debug, "Message retrieved from '" << name << "'");
+ m = *msg;
+ return true;
+ } else {
+ //message(s) are available but consumer hasn't got enough credit
+ QPID_LOG(debug, "Consumer can't currently accept message from '" << name << "'");
+ if (c->preAcquires()) {
+ //let someone else try
+ listeners.populate(set);
+ }
+ break;
+ }
} else {
- //browser hasn't got enough credit for the message
- QPID_LOG(debug, "Browser can't currently accept message from '" << name << "'");
- return false;
+ //consumer will never want this message, try another one
+ QPID_LOG(debug, "Consumer doesn't want message from '" << name << "'");
+ if (c->preAcquires()) {
+ //let someone else try to take this one
+ listeners.populate(set);
+ }
}
} else {
- //consumer will never want this message, continue seeking
- QPID_LOG(debug, "Browser skipping message from '" << name << "'");
- c->setPosition(msg.position);
+ QPID_LOG(debug, "No messages to dispatch on queue '" << name << "'");
+ listeners.addListener(c);
+ return false;
}
}
+ set.notify();
return false;
}
@@ -507,23 +453,28 @@ void Queue::removeListener(Consumer::shared_ptr c)
bool Queue::dispatch(Consumer::shared_ptr c)
{
- QueuedMessage msg(this);
+ Message msg;
if (getNextMessage(msg, c)) {
- c->deliver(msg);
+ c->deliver(*c, msg);
return true;
} else {
return false;
}
}
-bool Queue::find(SequenceNumber pos, QueuedMessage& msg) const {
+bool Queue::find(SequenceNumber pos, Message& msg) const
+{
Mutex::ScopedLock locker(messageLock);
- if (messages->find(pos, msg))
+ Message* ptr = messages->find(pos, 0);
+ if (ptr) {
+ msg = *ptr;
return true;
+ }
return false;
}
-void Queue::consume(Consumer::shared_ptr c, bool requestExclusive){
+void Queue::consume(Consumer::shared_ptr c, bool requestExclusive)
+{
assertClusterSafe();
{
Mutex::ScopedLock locker(messageLock);
@@ -550,7 +501,7 @@ void Queue::consume(Consumer::shared_ptr c, bool requestExclusive){
browserCount++;
consumerCount++;
//reset auto deletion timer if necessary
- if (autoDeleteTimeout && autoDeleteTask) {
+ if (settings.autoDeleteDelay && autoDeleteTask) {
autoDeleteTask->cancel();
}
observeConsumerAdd(*c, locker);
@@ -559,7 +510,8 @@ void Queue::consume(Consumer::shared_ptr c, bool requestExclusive){
mgmtObject->inc_consumerCount ();
}
-void Queue::cancel(Consumer::shared_ptr c){
+void Queue::cancel(Consumer::shared_ptr c)
+{
removeListener(c);
{
Mutex::ScopedLock locker(messageLock);
@@ -572,65 +524,6 @@ void Queue::cancel(Consumer::shared_ptr c){
mgmtObject->dec_consumerCount ();
}
-QueuedMessage Queue::get(){
- QueuedMessage msg(this);
- bool ok;
- {
- Mutex::ScopedLock locker(messageLock);
- ok = messages->consume(msg);
- if (ok) observeAcquire(msg, locker);
- }
-
- if (ok && mgmtObject) {
- mgmtObject->inc_acquires();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_acquires();
- }
-
- return msg;
-}
-
-namespace {
-bool collectIf(QueuedMessage& qm, Messages::Predicate predicate,
- std::deque<QueuedMessage>& collection)
-{
- if (predicate(qm)) {
- collection.push_back(qm);
- return true;
- } else {
- return false;
- }
-}
-
-bool isExpired(const QueuedMessage& qm) { return qm.payload->hasExpired(); }
-} // namespace
-
-void Queue::dequeueIf(Messages::Predicate predicate,
- std::deque<QueuedMessage>& dequeued)
-{
- {
- Mutex::ScopedLock locker(messageLock);
- messages->removeIf(boost::bind(&collectIf, _1, predicate, boost::ref(dequeued)));
- }
- if (!dequeued.empty()) {
- if (mgmtObject) {
- mgmtObject->inc_acquires(dequeued.size());
- if (brokerMgmtObject)
- brokerMgmtObject->inc_acquires(dequeued.size());
- }
- for (std::deque<QueuedMessage>::const_iterator i = dequeued.begin();
- i != dequeued.end(); ++i) {
- {
- // KAG: should be safe to retake lock after the removeIf, since
- // no other thread can touch these messages after the removeIf() call
- Mutex::ScopedLock locker(messageLock);
- observeAcquire(*i, locker);
- }
- dequeue( 0, *i );
- }
- }
-}
-
/**
*@param lapse: time since the last purgeExpired
*/
@@ -642,13 +535,17 @@ void Queue::purgeExpired(sys::Duration lapse) {
dequeueSincePurge -= count;
int seconds = int64_t(lapse)/qpid::sys::TIME_SEC;
if (seconds == 0 || count / seconds < 1) {
- std::deque<QueuedMessage> dequeued;
- dequeueIf(boost::bind(&isExpired, _1), dequeued);
- if (dequeued.size()) {
- if (mgmtObject) {
- mgmtObject->inc_discardsTtl(dequeued.size());
- if (brokerMgmtObject)
- brokerMgmtObject->inc_discardsTtl(dequeued.size());
+ uint32_t count = remove(0, boost::bind(&Message::hasExpired, _1), 0, CONSUMER);
+ QPID_LOG(debug, "Purged " << count << " expired messages from " << getName());
+ //
+ // Report the count of discarded-by-ttl messages
+ //
+ if (mgmtObject && count) {
+ mgmtObject->inc_acquires(count);
+ mgmtObject->inc_discardsTtl(count);
+ if (brokerMgmtObject) {
+ brokerMgmtObject->inc_acquires(count);
+ brokerMgmtObject->inc_discardsTtl(count);
}
}
}
@@ -663,7 +560,7 @@ namespace {
static const std::string typeKey;
static const std::string paramsKey;
static MessageFilter *create( const ::qpid::types::Variant::Map *filter );
- virtual bool match( const QueuedMessage& ) const { return true; }
+ virtual bool match( const Message& ) const { return true; }
virtual ~MessageFilter() {}
protected:
MessageFilter() {};
@@ -687,13 +584,9 @@ namespace {
static const std::string valueKey;
HeaderMatchFilter( const std::string& _header, const std::string& _value )
: MessageFilter (), header(_header), value(_value) {}
- bool match( const QueuedMessage& msg ) const
+ bool match( const Message& msg ) const
{
- const qpid::framing::FieldTable* headers = msg.payload->getApplicationHeaders();
- if (!headers) return false;
- FieldTable::ValuePtr h = headers->get(header);
- if (!h || !h->convertsTo<std::string>()) return false;
- return h->get<std::string>() == value;
+ return msg.getPropertyAsString(header) == value;
}
private:
const std::string header;
@@ -730,36 +623,68 @@ namespace {
return new MessageFilter();
}
- // used by removeIf() to collect all messages matching a filter, maximum match count is
- // optional.
- struct Collector {
- const uint32_t maxMatches;
- MessageFilter& filter;
- std::deque<QueuedMessage> matches;
- Collector(MessageFilter& filter, uint32_t max)
- : maxMatches(max), filter(filter) {}
- bool operator() (QueuedMessage& qm)
- {
- if (maxMatches == 0 || matches.size() < maxMatches) {
- if (filter.match( qm )) {
- matches.push_back(qm);
- return true;
- }
- }
+ bool reroute(boost::shared_ptr<Exchange> e, const Message& m)
+ {
+ if (e) {
+ DeliverableMessage d(m, 0);
+ d.getMessage().clearTrace();
+ e->routeWithAlternate(d);
+ return true;
+ } else {
return false;
}
- };
-
+ }
+ void moveTo(boost::shared_ptr<Queue> q, Message& m)
+ {
+ if (q) {
+ q->deliver(m);
+ }
+ }
} // end namespace
+uint32_t Queue::remove(const uint32_t maxCount, MessagePredicate p, MessageFunctor f, SubscriptionType type)
+{
+ std::deque<Message> removed;
+ {
+ QueueCursor c(type);
+ uint32_t count(0);
+ Mutex::ScopedLock locker(messageLock);
+ Message* m = messages->next(c);
+ while (m){
+ if (!p || p(*m)) {
+ if (!maxCount || count++ < maxCount) {
+ if (m->getState() == AVAILABLE) {
+ //don't actually acquire, just act as if we did
+ observeAcquire(*m, locker);
+ }
+ observeDequeue(*m, locker);
+ removed.push_back(*m);//takes a copy of the message
+ if (!messages->deleted(c)) {
+ QPID_LOG(warning, "Failed to correctly remove message from " << name << "; state is not consistent!");
+ assert(false);
+ }
+ } else {
+ break;
+ }
+ }
+ m = messages->next(c);
+ }
+ }
+ for (std::deque<Message>::iterator i = removed.begin(); i != removed.end(); ++i) {
+ if (f) f(*i);//ERROR? need to clear old persistent context?
+ if (i->isPersistent()) dequeueFromStore(i->getPersistentContext());//do this outside of lock and after any re-routing
+ }
+ return removed.size();
+}
+
/**
* purge - for purging all or some messages on a queue
* depending on the purge_request
*
- * purge_request == 0 then purge all messages
- * == N then purge N messages from queue
- * Sometimes purge_request == 1 to unblock the top of queue
+ * qty == 0 then purge all messages
+ * == N then purge N messages from queue
+ * Sometimes qty == 1 to unblock the top of queue
*
* The dest exchange may be supplied to re-route messages through the exchange.
* It is safe to re-route messages such that they arrive back on the same queue,
@@ -768,172 +693,53 @@ namespace {
* An optional filter can be supplied that will be applied against each message. The
* message is purged only if the filter matches. See MessageDistributor for more detail.
*/
-uint32_t Queue::purge(const uint32_t purge_request, boost::shared_ptr<Exchange> dest,
+uint32_t Queue::purge(const uint32_t qty, boost::shared_ptr<Exchange> dest,
const qpid::types::Variant::Map *filter)
{
std::auto_ptr<MessageFilter> mf(MessageFilter::create(filter));
- Collector c(*mf.get(), purge_request);
-
- {
- Mutex::ScopedLock locker(messageLock);
- messages->removeIf( boost::bind<bool>(boost::ref(c), _1) );
- }
+ uint32_t count = remove(qty, boost::bind(&MessageFilter::match, mf.get(), _1), boost::bind(&reroute, dest, _1), CONSUMER/*?*/);
- if (!c.matches.empty()) {
- if (mgmtObject) {
- mgmtObject->inc_acquires(c.matches.size());
- if (dest.get()) {
- mgmtObject->inc_reroutes(c.matches.size());
- if (brokerMgmtObject) {
- brokerMgmtObject->inc_acquires(c.matches.size());
- brokerMgmtObject->inc_reroutes(c.matches.size());
- }
- } else {
- mgmtObject->inc_discardsPurge(c.matches.size());
- if (brokerMgmtObject) {
- brokerMgmtObject->inc_acquires(c.matches.size());
- brokerMgmtObject->inc_discardsPurge(c.matches.size());
- }
- }
- }
-
- for (std::deque<QueuedMessage>::iterator qmsg = c.matches.begin();
- qmsg != c.matches.end(); ++qmsg) {
-
- {
- // KAG: should be safe to retake lock after the removeIf, since
- // no other thread can touch these messages after the removeIf call
- Mutex::ScopedLock locker(messageLock);
- observeAcquire(*qmsg, locker);
+ if (mgmtObject && count) {
+ mgmtObject->inc_acquires(count);
+ if (dest.get()) {
+ mgmtObject->inc_reroutes(count);
+ if (brokerMgmtObject) {
+ brokerMgmtObject->inc_acquires(count);
+ brokerMgmtObject->inc_reroutes(count);
}
- dequeue(0, *qmsg);
- QPID_LOG(debug, "Purged message at " << qmsg->position << " from " << getName());
- // now reroute if necessary
- if (dest.get()) {
- assert(qmsg->payload);
- qmsg->payload->clearTrace();
- DeliverableMessage dmsg(qmsg->payload);
- dest->routeWithAlternate(dmsg);
+ } else {
+ mgmtObject->inc_discardsPurge(count);
+ if (brokerMgmtObject) {
+ brokerMgmtObject->inc_acquires(count);
+ brokerMgmtObject->inc_discardsPurge(count);
}
}
}
- return c.matches.size();
+
+ return count;
}
uint32_t Queue::move(const Queue::shared_ptr destq, uint32_t qty,
const qpid::types::Variant::Map *filter)
{
std::auto_ptr<MessageFilter> mf(MessageFilter::create(filter));
- Collector c(*mf.get(), qty);
-
- {
- Mutex::ScopedLock locker(messageLock);
- messages->removeIf( boost::bind<bool>(boost::ref(c), _1) );
- }
-
-
- if (!c.matches.empty()) {
- // Update observers and message state:
-
- if (mgmtObject) {
- mgmtObject->inc_acquires(c.matches.size());
- if (brokerMgmtObject)
- brokerMgmtObject->inc_acquires(c.matches.size());
- }
-
- for (std::deque<QueuedMessage>::iterator qmsg = c.matches.begin();
- qmsg != c.matches.end(); ++qmsg) {
- {
- Mutex::ScopedLock locker(messageLock);
- observeAcquire(*qmsg, locker);
- }
- dequeue(0, *qmsg);
- // and move to destination Queue.
- assert(qmsg->payload);
- destq->deliver(qmsg->payload);
- }
- }
- return c.matches.size();
+ return remove(qty, boost::bind(&MessageFilter::match, mf.get(), _1), boost::bind(&moveTo, destq, _1), CONSUMER/*?*/);
}
-/** Acquire the message at the given position, return true and msg if acquire succeeds */
-bool Queue::acquire(const qpid::framing::SequenceNumber& position, QueuedMessage& msg)
+void Queue::push(Message& message, bool /*isRecovery*/)
{
- bool ok;
- {
- Mutex::ScopedLock locker(messageLock);
- ok = messages->acquire(position, msg);
- if (ok) observeAcquire(msg, locker);
- }
- if (ok) {
- if (mgmtObject) {
- mgmtObject->inc_acquires();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_acquires();
- }
- ++dequeueSincePurge;
- return true;
- }
- return false;
-}
-
-void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){
assertClusterSafe();
QueueListeners::NotificationSet copy;
- QueuedMessage removed, qm(this, msg);
- bool dequeueRequired = false;
{
Mutex::ScopedLock locker(messageLock);
- qm.position = ++sequence;
- if (messages->push(qm, removed)) {
- dequeueRequired = true;
- observeAcquire(removed, locker);
- }
- observeEnqueue(qm, locker);
- if (policy.get()) {
- policy->enqueued(qm);
- }
+ message.setSequence(++sequence);
+ messages->publish(message);
listeners.populate(copy);
- }
- if (insertSeqNo) msg->insertCustomProperty(seqNoKey, qm.position);
-
- mgntEnqStats(msg, mgmtObject, brokerMgmtObject);
-
- if (dequeueRequired) {
- if (mgmtObject) {
- mgmtObject->inc_acquires();
- mgmtObject->inc_discardsLvq();
- if (brokerMgmtObject) {
- brokerMgmtObject->inc_acquires();
- brokerMgmtObject->inc_discardsLvq();
- }
- }
- if (isRecovery) {
- //can't issue new requests for the store until
- //recovery is complete
- Mutex::ScopedLock locker(messageLock);
- pendingDequeues.push_back(removed);
- } else {
- dequeue(0, removed);
- }
+ observeEnqueue(message, locker);
}
copy.notify();
}
-void isEnqueueComplete(uint32_t* result, const QueuedMessage& message)
-{
- if (message.payload->isIngressComplete()) (*result)++;
-}
-
-/** function only provided for unit tests, or code not in critical message path */
-uint32_t Queue::getEnqueueCompleteMessageCount() const
-{
- uint32_t count = 0;
- Mutex::ScopedLock locker(messageLock);
- messages->foreach(boost::bind(&isEnqueueComplete, &count, _1));
- return count;
-}
-
uint32_t Queue::getMessageCount() const
{
Mutex::ScopedLock locker(messageLock);
@@ -949,7 +755,7 @@ uint32_t Queue::getConsumerCount() const
bool Queue::canAutoDelete() const
{
Mutex::ScopedLock locker(messageLock);
- return autodelete && !consumerCount && !owner;
+ return settings.autodelete && !consumerCount && !owner;
}
void Queue::clearLastNodeFailure()
@@ -957,14 +763,9 @@ void Queue::clearLastNodeFailure()
inLastNodeFailure = false;
}
-void Queue::forcePersistent(QueuedMessage& message)
+void Queue::forcePersistent(const Message& /*message*/)
{
- if(!message.payload->isStoredOnQueue(shared_from_this())) {
- message.payload->forcePersistent();
- if (message.payload->isForcedPersistent() ){
- enqueue(0, message.payload);
- }
- }
+ //TODO
}
void Queue::setLastNodeFailure()
@@ -982,153 +783,129 @@ void Queue::setLastNodeFailure()
}
-// return true if store exists,
-bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg, bool suppressPolicyCheck)
+/*
+ * return true if enqueue succeeded and message should be made
+ * available; returning false will result in the message being dropped
+ */
+bool Queue::enqueue(TransactionContext* ctxt, Message& msg)
{
ScopedUse u(barrier);
if (!u.acquired) return false;
- if (policy.get() && !suppressPolicyCheck) {
- std::deque<QueuedMessage> dequeues;
- {
- Mutex::ScopedLock locker(messageLock);
- try {
- policy->tryEnqueue(msg);
- } catch(ResourceLimitExceededException&) {
- if (mgmtObject) {
- mgmtObject->inc_discardsOverflow();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_discardsOverflow();
- }
- throw;
- }
- policy->getPendingDequeues(dequeues);
- }
- //depending on policy, may have some dequeues that need to performed without holding the lock
-
- //
- // Count the dequeues as ring-discards. We know that these aren't rejects because
- // policy->tryEnqueue would have thrown an exception.
- //
- if (mgmtObject && !dequeues.empty()) {
- mgmtObject->inc_discardsRing(dequeues.size());
- if (brokerMgmtObject)
- brokerMgmtObject->inc_discardsRing(dequeues.size());
+ {
+ Mutex::ScopedLock locker(messageLock);
+ if (!checkDepth(QueueDepth(1, msg.getContentSize()), msg)) {
+ return false;
}
-
- for_each(dequeues.begin(), dequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
}
if (inLastNodeFailure && persistLastNode){
- msg->forcePersistent();
+ forcePersistent(msg);
}
- if (traceId.size()) {
- msg->addTraceId(traceId);
+ if (settings.traceId.size()) {
+ msg.addTraceId(settings.traceId);
}
- if ((msg->isPersistent() || msg->checkContentReleasable()) && store) {
+ if (msg.isPersistent() && store) {
// mark the message as being enqueued - the store MUST CALL msg->enqueueComplete()
// when it considers the message stored.
- msg->enqueueAsync(shared_from_this(), store);
- boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg);
+ boost::intrusive_ptr<PersistableMessage> pmsg = msg.getPersistentContext();
+ assert(pmsg);
+ pmsg->enqueueAsync(shared_from_this(), store);
store->enqueue(ctxt, pmsg, *this);
- return true;
}
- if (!store) {
- //Messages enqueued on a transient queue should be prevented
- //from having their content released as it may not be
- //recoverable by these queue for delivery
- msg->blockContentRelease();
- }
- return false;
+ return true;
}
-void Queue::enqueueAborted(boost::intrusive_ptr<Message> msg)
+void Queue::enqueueAborted(const Message& msg)
{
+ //Called when any transactional enqueue is aborted (including but
+ //not limited to a recovered dtx transaction)
Mutex::ScopedLock locker(messageLock);
- if (policy.get()) policy->enqueueAborted(msg);
+ current -= QueueDepth(1, msg.getContentSize());
}
-// return true if store exists,
-bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg)
+void Queue::enqueueCommited(Message& msg)
{
- ScopedUse u(barrier);
- if (!u.acquired) return false;
- {
- Mutex::ScopedLock locker(messageLock);
- if (!isEnqueued(msg)) return false;
- if (!ctxt) {
- if (policy.get()) policy->dequeued(msg);
- messages->deleted(msg);
- observeDequeue(msg, locker);
- }
+ //called when a recovered dtx enqueue operation is committed; the
+ //message is already on disk and space has been reserved in policy
+ //but it should now be made available
+ process(msg);
+}
+void Queue::dequeueAborted(Message& msg)
+{
+ //called when a recovered dtx dequeue operation is aborted; the
+ //message should be added back to the queue
+ push(msg);
+}
+void Queue::dequeueCommited(const Message& msg)
+{
+ //called when a recovered dtx dequeue operation is committed; the
+ //message will at this point have already been removed from the
+ //store and will not be available for delivery. The only action
+ //required is to ensure the observers are notified and the
+ //management stats are correctly decremented
+ Mutex::ScopedLock locker(messageLock);
+ observeDequeue(msg, locker);
+ if (mgmtObject != 0) {
+ mgmtObject->inc_msgTxnDequeues();
+ mgmtObject->inc_byteTxnDequeues(msg.getContentSize());
}
+}
- if (!ctxt) {
- mgntDeqStats(msg.payload, mgmtObject, brokerMgmtObject);
- }
- // This check prevents messages which have been forced persistent on one queue from dequeuing
- // from another on which no forcing has taken place and thus causing a store error.
- bool fp = msg.payload->isForcedPersistent();
- if (!fp || (fp && msg.payload->isStoredOnQueue(shared_from_this()))) {
- if ((msg.payload->isPersistent() || msg.payload->checkContentReleasable()) && store) {
- msg.payload->dequeueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue
- boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg.payload);
- store->dequeue(ctxt, pmsg, *this);
- return true;
- }
+void Queue::dequeueFromStore(boost::intrusive_ptr<PersistableMessage> msg)
+{
+ ScopedUse u(barrier);
+ if (u.acquired && msg && store) {
+ store->dequeue(0, msg, *this);
}
- return false;
}
-void Queue::dequeueCommitted(const QueuedMessage& msg)
+void Queue::dequeue(TransactionContext* ctxt, const QueueCursor& cursor)
{
+ ScopedUse u(barrier);
+ if (!u.acquired) return;
+ boost::intrusive_ptr<PersistableMessage> pmsg;
{
Mutex::ScopedLock locker(messageLock);
- if (policy.get()) policy->dequeued(msg);
- messages->deleted(msg);
- observeDequeue(msg, locker);
+ Message* msg = messages->find(cursor);
+ if (msg) {
+ if (msg->isPersistent()) pmsg = msg->getPersistentContext();
+ if (!ctxt) {
+ observeDequeue(*msg, locker);
+ messages->deleted(cursor);//message pointer not valid after this
+ }
+ } else {
+ return;
+ }
}
- mgntDeqStats(msg.payload, mgmtObject, brokerMgmtObject);
- if (mgmtObject != 0) {
- _qmf::Queue::PerThreadStats *qStats = mgmtObject->getStatistics();
- const uint64_t contentSize = msg.payload->contentSize();
- qStats->msgTxnDequeues += 1;
- qStats->byteTxnDequeues += contentSize;
- mgmtObject->statisticsUpdated();
+ if (store && pmsg) {
+ store->dequeue(ctxt, pmsg, *this);
+ }
+}
+
+void Queue::dequeueCommitted(const QueueCursor& cursor)
+{
+ Mutex::ScopedLock locker(messageLock);
+ Message* msg = messages->find(cursor);
+ if (msg) {
+ const uint64_t contentSize = msg->getContentSize();
+ observeDequeue(*msg, locker);
+ if (mgmtObject != 0) {
+ mgmtObject->inc_msgTxnDequeues();
+ mgmtObject->inc_byteTxnDequeues(contentSize);
+ }
if (brokerMgmtObject) {
_qmf::Broker::PerThreadStats *bStats = brokerMgmtObject->getStatistics();
bStats->msgTxnDequeues += 1;
bStats->byteTxnDequeues += contentSize;
brokerMgmtObject->statisticsUpdated();
}
- }
-}
-
-/**
- * Removes the first (oldest) message from the in-memory delivery queue as well dequeing
- * it from the logical (and persistent if applicable) queue
- */
-bool Queue::popAndDequeue(QueuedMessage& msg)
-{
- bool popped;
- {
- Mutex::ScopedLock locker(messageLock);
- popped = messages->consume(msg);
- if (popped) observeAcquire(msg, locker);
- }
- if (popped) {
- if (mgmtObject) {
- mgmtObject->inc_acquires();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_acquires();
- }
- dequeue(0, msg);
- return true;
+ messages->deleted(cursor);
} else {
- return false;
+ QPID_LOG(error, "Could not find dequeued message on commit");
}
}
@@ -1136,8 +913,10 @@ bool Queue::popAndDequeue(QueuedMessage& msg)
* Updates policy and management when a message has been dequeued,
* Requires messageLock be held by caller.
*/
-void Queue::observeDequeue(const QueuedMessage& msg, const qpid::sys::Mutex::ScopedLock&)
+void Queue::observeDequeue(const Message& msg, const Mutex::ScopedLock&)
{
+ current -= QueueDepth(1, msg.getContentSize());
+ mgntDeqStats(msg, mgmtObject, brokerMgmtObject);
for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
try{
(*i)->dequeued(msg);
@@ -1150,7 +929,7 @@ void Queue::observeDequeue(const QueuedMessage& msg, const qpid::sys::Mutex::Sco
/** updates queue observers when a message has become unavailable for transfer.
* Requires messageLock be held by caller.
*/
-void Queue::observeAcquire(const QueuedMessage& msg, const qpid::sys::Mutex::ScopedLock&)
+void Queue::observeAcquire(const Message& msg, const Mutex::ScopedLock&)
{
for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
try{
@@ -1164,7 +943,7 @@ void Queue::observeAcquire(const QueuedMessage& msg, const qpid::sys::Mutex::Sco
/** updates queue observers when a message has become re-available for transfer
* Requires messageLock be held by caller.
*/
-void Queue::observeRequeue(const QueuedMessage& msg, const qpid::sys::Mutex::ScopedLock&)
+void Queue::observeRequeue(const Message& msg, const Mutex::ScopedLock&)
{
for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
try{
@@ -1202,13 +981,11 @@ void Queue::observeConsumerRemove( const Consumer& c, const qpid::sys::Mutex::Sc
}
-void Queue::create(const FieldTable& _settings)
+void Queue::create()
{
- settings = _settings;
if (store) {
- store->create(*this, _settings);
+ store->create(*this, settings.storeSettings);
}
- configureImpl(_settings);
}
@@ -1258,112 +1035,21 @@ bool getBoolSetting(const qpid::framing::FieldTable& settings, const std::string
}
}
-void Queue::configure(const FieldTable& _settings)
+void Queue::abandoned(const Message& message)
{
- settings = _settings;
- configureImpl(settings);
-}
-
-void Queue::configureImpl(const FieldTable& _settings)
-{
- eventMode = _settings.getAsInt(qpidQueueEventGeneration);
- if (eventMode && broker) {
- broker->getQueueEvents().observe(*this, eventMode == ENQUEUE_ONLY);
- }
-
- if (QueuePolicy::getType(_settings) == QueuePolicy::FLOW_TO_DISK &&
- (!store || NullMessageStore::isNullStore(store) || (broker && !(broker->getQueueEvents().isSync())) )) {
- if ( NullMessageStore::isNullStore(store)) {
- QPID_LOG(warning, "Flow to disk not valid for non-persisted queue:" << getName());
- } else if (broker && !(broker->getQueueEvents().isSync()) ) {
- QPID_LOG(warning, "Flow to disk not valid with async Queue Events:" << getName());
- }
- FieldTable copy(_settings);
- copy.erase(QueuePolicy::typeKey);
- setPolicy(QueuePolicy::createQueuePolicy(getName(), copy));
- } else {
- setPolicy(QueuePolicy::createQueuePolicy(getName(), _settings));
- }
- if (broker && broker->getManagementAgent()) {
- ThresholdAlerts::observe(*this, *(broker->getManagementAgent()), _settings, broker->getOptions().queueThresholdEventRatio);
- }
-
- //set this regardless of owner to allow use of no-local with exclusive consumers also
- noLocal = getBoolSetting(_settings, qpidNoLocal);
- QPID_LOG(debug, "Configured queue " << getName() << " with no-local=" << noLocal);
-
- std::string lvqKey = _settings.getAsString(qpidLastValueQueueKey);
- if (lvqKey.size()) {
- QPID_LOG(debug, "Configured queue " << getName() << " as Last Value Queue with key " << lvqKey);
- messages = std::auto_ptr<Messages>(new MessageMap(lvqKey));
- allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *messages ));
- } else if (getBoolSetting(_settings, qpidLastValueQueueNoBrowse)) {
- QPID_LOG(debug, "Configured queue " << getName() << " as Legacy Last Value Queue with 'no-browse' on");
- messages = LegacyLVQ::updateOrReplace(messages, qpidVQMatchProperty, true, broker);
- allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *messages ));
- } else if (getBoolSetting(_settings, qpidLastValueQueue)) {
- QPID_LOG(debug, "Configured queue " << getName() << " as Legacy Last Value Queue");
- messages = LegacyLVQ::updateOrReplace(messages, qpidVQMatchProperty, false, broker);
- allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *messages ));
- } else {
- std::auto_ptr<Messages> m = Fairshare::create(_settings);
- if (m.get()) {
- messages = m;
- allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *messages ));
- QPID_LOG(debug, "Configured queue " << getName() << " as priority queue.");
- } else { // default (FIFO) queue type
- // override default message allocator if message groups configured.
- boost::shared_ptr<MessageGroupManager> mgm(MessageGroupManager::create( getName(), *messages, _settings));
- if (mgm) {
- allocator = mgm;
- addObserver(mgm);
- }
- }
- }
-
- persistLastNode = getBoolSetting(_settings, qpidPersistLastNode);
- if (persistLastNode) QPID_LOG(debug, "Configured queue to Persist data if cluster fails to one node for: " << getName());
-
- traceId = _settings.getAsString(qpidTraceIdentity);
- std::string excludeList = _settings.getAsString(qpidTraceExclude);
- if (excludeList.size()) {
- split(traceExclude, excludeList, ", ");
- }
- QPID_LOG(debug, "Configured queue " << getName() << " with qpid.trace.id='" << traceId
- << "' and qpid.trace.exclude='"<< excludeList << "' i.e. " << traceExclude.size() << " elements");
-
- FieldTable::ValuePtr p =_settings.get(qpidInsertSequenceNumbers);
- if (p && p->convertsTo<std::string>()) insertSequenceNumbers(p->get<std::string>());
-
- autoDeleteTimeout = getIntegerSetting(_settings, qpidAutoDeleteTimeout);
- if (autoDeleteTimeout)
- QPID_LOG(debug, "Configured queue " << getName() << " with qpid.auto_delete_timeout=" << autoDeleteTimeout);
-
- if (mgmtObject != 0) {
- mgmtObject->set_arguments(ManagementAgent::toMap(_settings));
- }
-
- QueueFlowLimit::observe(*this, _settings);
+ if (reroute(alternateExchange, message) && brokerMgmtObject)
+ brokerMgmtObject->inc_abandonedViaAlt();
+ else if (brokerMgmtObject)
+ brokerMgmtObject->inc_abandoned();
}
void Queue::destroyed()
{
unbind(broker->getExchanges());
-
- QueuedMessage m;
- while(popAndDequeue(m)) {
- DeliverableMessage msg(m.payload);
- if (alternateExchange.get()) {
- if (brokerMgmtObject)
- brokerMgmtObject->inc_abandonedViaAlt();
- alternateExchange->routeWithAlternate(msg);
- } else {
- if (brokerMgmtObject)
- brokerMgmtObject->inc_abandoned();
- }
- }
- if (alternateExchange.get())
+ remove(0, 0, boost::bind(&Queue::abandoned, this, _1), REPLICATOR/*even acquired message are treated as abandoned*/);
+ if (alternateExchange.get()) {
alternateExchange->decAlternateUsers();
+ }
if (store) {
barrier.destroy();
@@ -1401,20 +1087,6 @@ void Queue::unbind(ExchangeRegistry& exchanges)
bindings.unbind(exchanges, shared_from_this());
}
-void Queue::setPolicy(std::auto_ptr<QueuePolicy> _policy)
-{
- Mutex::ScopedLock locker(messageLock);
- policy = _policy;
- if (policy.get())
- policy->setQueue(this);
-}
-
-const QueuePolicy* Queue::getPolicy()
-{
- Mutex::ScopedLock locker(messageLock);
- return policy.get();
-}
-
uint64_t Queue::getPersistenceId() const
{
return persistenceId;
@@ -1434,10 +1106,7 @@ void Queue::setPersistenceId(uint64_t _persistenceId) const
void Queue::encode(Buffer& buffer) const
{
buffer.putShortString(name);
- buffer.put(settings);
- if (policy.get()) {
- buffer.put(*policy);
- }
+ buffer.put(encodableSettings);
buffer.putShortString(alternateExchange.get() ? alternateExchange->getName() : std::string(""));
}
@@ -1445,21 +1114,19 @@ uint32_t Queue::encodedSize() const
{
return name.size() + 1/*short string size octet*/
+ (alternateExchange.get() ? alternateExchange->getName().size() : 0) + 1 /* short string */
- + settings.encodedSize()
- + (policy.get() ? (*policy).encodedSize() : 0);
+ + encodableSettings.encodedSize();
}
Queue::shared_ptr Queue::restore( QueueRegistry& queues, Buffer& buffer )
{
string name;
buffer.getShortString(name);
- FieldTable settings;
- buffer.get(settings);
+ FieldTable ft;
+ buffer.get(ft);
boost::shared_ptr<Exchange> alternate;
- std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true, false, 0, alternate, settings, true);
- if (result.first->policy.get() && buffer.available() >= result.first->policy->encodedSize()) {
- buffer.get ( *(result.first->policy) );
- }
+ QueueSettings settings(true, false);
+ settings.populate(ft, settings.storeSettings);
+ std::pair<Queue::shared_ptr, bool> result = queues.declare(name, settings, alternate, true);
if (buffer.available()) {
string altExch;
buffer.getShortString(altExch);
@@ -1523,8 +1190,8 @@ struct AutoDeleteTask : qpid::sys::TimerTask
void Queue::tryAutoDelete(Broker& broker, Queue::shared_ptr queue, const std::string& connectionId, const std::string& userId)
{
- if (queue->autoDeleteTimeout && queue->canAutoDelete()) {
- AbsTime time(now(), Duration(queue->autoDeleteTimeout * TIME_SEC));
+ if (queue->settings.autoDeleteDelay && queue->canAutoDelete()) {
+ AbsTime time(now(), Duration(queue->settings.autoDeleteDelay * TIME_SEC));
queue->autoDeleteTask = boost::intrusive_ptr<qpid::sys::TimerTask>(new AutoDeleteTask(broker, queue, connectionId, userId, time));
broker.getClusterTimer().add(queue->autoDeleteTask);
QPID_LOG(debug, "Timed auto-delete for " << queue->getName() << " initiated");
@@ -1543,12 +1210,15 @@ void Queue::releaseExclusiveOwnership()
{
Mutex::ScopedLock locker(ownershipLock);
owner = 0;
+ if (mgmtObject) {
+ mgmtObject->set_exclusive(false);
+ }
}
bool Queue::setExclusiveOwner(const OwnershipToken* const o)
{
//reset auto deletion timer if necessary
- if (autoDeleteTimeout && autoDeleteTask) {
+ if (settings.autoDeleteDelay && autoDeleteTask) {
autoDeleteTask->cancel();
}
Mutex::ScopedLock locker(ownershipLock);
@@ -1556,6 +1226,9 @@ bool Queue::setExclusiveOwner(const OwnershipToken* const o)
return false;
} else {
owner = o;
+ if (mgmtObject) {
+ mgmtObject->set_exclusive(true);
+ }
return true;
}
}
@@ -1687,7 +1360,7 @@ namespace {
struct After {
framing::SequenceNumber seq;
After(framing::SequenceNumber s) : seq(s) {}
- bool operator()(const QueuedMessage& qm) { return qm.position > seq; }
+ bool operator()(const Message& m) { return m.getSequence() > seq; }
};
} // namespace
@@ -1695,12 +1368,10 @@ struct After {
void Queue::setPosition(SequenceNumber n) {
Mutex::ScopedLock locker(messageLock);
if (n < sequence) {
- std::deque<QueuedMessage> dequeued;
- dequeueIf(After(n), dequeued);
- messages->setPosition(n);
+ remove(0, After(n), MessagePredicate(), BROWSER);
}
sequence = n;
- QPID_LOG(trace, "Set position to " << sequence << " on " << getName());
+ QPID_LOG(debug, "Set position to " << sequence << " on " << getName());
}
SequenceNumber Queue::getPosition() {
@@ -1721,25 +1392,16 @@ void Queue::recoveryComplete(ExchangeRegistry& exchanges)
<< "\": exchange does not exist.");
}
//process any pending dequeues
- std::deque<QueuedMessage> pd;
- {
- Mutex::ScopedLock locker(messageLock);
- pendingDequeues.swap(pd);
+ for (std::vector<Message>::iterator i = pendingDequeues.begin(); i != pendingDequeues.end(); ++i) {
+ dequeueFromStore(i->getPersistentContext());
}
- for_each(pd.begin(), pd.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
-}
-
-void Queue::insertSequenceNumbers(const std::string& key)
-{
- seqNoKey = key;
- insertSeqNo = !seqNoKey.empty();
- QPID_LOG(debug, "Inserting sequence numbers as " << key);
+ pendingDequeues.clear();
}
/** updates queue observers and state when a message has become available for transfer
* Requires messageLock be held by caller.
*/
-void Queue::observeEnqueue(const QueuedMessage& m, const qpid::sys::Mutex::ScopedLock&)
+void Queue::observeEnqueue(const Message& m, const Mutex::ScopedLock&)
{
for (Observers::iterator i = observers.begin(); i != observers.end(); ++i) {
try {
@@ -1748,32 +1410,7 @@ void Queue::observeEnqueue(const QueuedMessage& m, const qpid::sys::Mutex::Scope
QPID_LOG(warning, "Exception on notification of enqueue for queue " << getName() << ": " << e.what());
}
}
-}
-
-void Queue::updateEnqueued(const QueuedMessage& m)
-{
- if (m.payload) {
- boost::intrusive_ptr<Message> payload = m.payload;
- enqueue(0, payload, true);
- {
- Mutex::ScopedLock locker(messageLock);
- messages->updateAcquired(m);
- observeEnqueue(m, locker);
- if (policy.get()) {
- policy->recoverEnqueued(payload);
- policy->enqueued(m);
- }
- }
- mgntEnqStats(m.payload, mgmtObject, brokerMgmtObject);
- } else {
- QPID_LOG(warning, "Queue informed of enqueued message that has no payload");
- }
-}
-
-bool Queue::isEnqueued(const QueuedMessage& msg)
-{
- Mutex::ScopedLock locker(messageLock);
- return !policy.get() || policy->isEnqueued(msg);
+ mgntEnqStats(m, mgmtObject, brokerMgmtObject);
}
// Note: accessing listeners outside of lock is dangerous. Caller must ensure the queue's
@@ -1835,28 +1472,82 @@ void Queue::setDequeueSincePurge(uint32_t value) {
dequeueSincePurge = value;
}
-namespace{
-class FindLowest
+void Queue::reject(const QueueCursor& cursor)
{
- public:
- FindLowest() : init(false) {}
- void process(const QueuedMessage& message) {
- QPID_LOG(debug, "FindLowest processing: " << message.position);
- if (!init || message.position < lowest) lowest = message.position;
- init = true;
- }
- bool getLowest(qpid::framing::SequenceNumber& result) {
- if (init) {
- result = lowest;
- return true;
+ Exchange::shared_ptr alternate = getAlternateExchange();
+ Message copy;
+ boost::intrusive_ptr<PersistableMessage> pmsg;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ Message* message = messages->find(cursor);
+ if (message) {
+ if (alternate) copy = *message;
+ if (message->isPersistent()) pmsg = message->getPersistentContext();
+ countRejected();
+ observeDequeue(*message, locker);
+ messages->deleted(cursor);
} else {
- return false;
+ return;
}
}
- private:
- bool init;
- qpid::framing::SequenceNumber lowest;
-};
+ if (alternate) {
+ copy.resetDeliveryCount();
+ DeliverableMessage delivery(copy, 0);
+ alternate->routeWithAlternate(delivery);
+ QPID_LOG(info, "Routed rejected message from " << getName() << " to "
+ << alternate->getName());
+ } else {
+ //just drop it
+ QPID_LOG(info, "Dropping rejected message from " << getName());
+ }
+ dequeueFromStore(pmsg);
+}
+
+bool Queue::checkDepth(const QueueDepth& increment, const Message&)
+{
+ if (current && (settings.maxDepth - current < increment)) {
+ if (mgmtObject) {
+ mgmtObject->inc_discardsOverflow();
+ if (brokerMgmtObject)
+ brokerMgmtObject->inc_discardsOverflow();
+ }
+ throw ResourceLimitExceededException(QPID_MSG("Maximum depth exceeded on " << name << ": current=[" << current << "], max=[" << settings.maxDepth << "]"));
+ } else {
+ current += increment;
+ return true;
+ }
+}
+
+bool Queue::seek(QueueCursor& cursor, MessagePredicate predicate)
+{
+ Mutex::ScopedLock locker(messageLock);
+ //hold lock across calls to predicate, or take copy of message?
+ //currently hold lock, may want to revise depending on any new use
+ //cases
+ Message* message = messages->next(cursor);
+ while (message && (predicate && !predicate(*message))) {
+ message = messages->next(cursor);
+ }
+ return message != 0;
+}
+
+bool Queue::seek(QueueCursor& cursor, MessagePredicate predicate, qpid::framing::SequenceNumber start)
+{
+ Mutex::ScopedLock locker(messageLock);
+ //hold lock across calls to predicate, or take copy of message?
+ //currently hold lock, may want to revise depending on any new use
+ //cases
+ Message* message;
+ message = messages->find(start, &cursor);
+ if (message && (!predicate || predicate(*message))) return true;
+
+ return seek(cursor, predicate);
+}
+
+bool Queue::seek(QueueCursor& cursor, qpid::framing::SequenceNumber start)
+{
+ Mutex::ScopedLock locker(messageLock);
+ return messages->find(start, &cursor);
}
Queue::UsageBarrier::UsageBarrier(Queue& q) : parent(q), count(0) {}
diff --git a/cpp/src/qpid/broker/Queue.h b/cpp/src/qpid/broker/Queue.h
index a31e0002ea..671a24d53e 100644
--- a/cpp/src/qpid/broker/Queue.h
+++ b/cpp/src/qpid/broker/Queue.h
@@ -28,12 +28,14 @@
#include "qpid/broker/Message.h"
#include "qpid/broker/Messages.h"
#include "qpid/broker/PersistableQueue.h"
-#include "qpid/broker/QueuePolicy.h"
#include "qpid/broker/QueueBindings.h"
#include "qpid/broker/QueueListeners.h"
#include "qpid/broker/QueueObserver.h"
+#include "qpid/broker/QueueSettings.h"
+#include "qpid/broker/TxOp.h"
#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/SequenceNumber.h"
#include "qpid/sys/AtomicValue.h"
#include "qpid/sys/Monitor.h"
#include "qpid/sys/Timer.h"
@@ -56,10 +58,14 @@
namespace qpid {
namespace broker {
class Broker;
+class Exchange;
class MessageStore;
+class QueueDepth;
class QueueEvents;
class QueueRegistry;
+class QueueFactory;
class TransactionContext;
+class TxBuffer;
class MessageDistributor;
/**
@@ -70,7 +76,9 @@ class MessageDistributor;
*/
class Queue : public boost::enable_shared_from_this<Queue>,
public PersistableQueue, public management::Manageable {
-
+ public:
+ typedef boost::function1<bool, const Message&> MessagePredicate;
+ protected:
struct UsageBarrier
{
Queue& parent;
@@ -90,31 +98,40 @@ class Queue : public boost::enable_shared_from_this<Queue>,
~ScopedUse() { if (acquired) barrier.release(); }
};
+ class TxPublish : public TxOp
+ {
+ Message message;
+ boost::shared_ptr<Queue> queue;
+ bool prepared;
+ public:
+ TxPublish(const Message&,boost::shared_ptr<Queue>);
+ bool prepare(TransactionContext* ctxt) throw();
+ void commit() throw();
+ void rollback() throw();
+ };
+
typedef std::set< boost::shared_ptr<QueueObserver> > Observers;
enum ConsumeCode {NO_MESSAGES=0, CANT_CONSUME=1, CONSUMED=2};
+ typedef boost::function1<void, Message&> MessageFunctor;
const std::string name;
- const bool autodelete;
MessageStore* store;
const OwnershipToken* owner;
uint32_t consumerCount; // Actually a count of all subscriptions, acquiring or not.
uint32_t browserCount; // Count of non-acquiring subscriptions.
OwnershipToken* exclusive;
- bool noLocal;
bool persistLastNode;
bool inLastNodeFailure;
- std::string traceId;
std::vector<std::string> traceExclude;
QueueListeners listeners;
std::auto_ptr<Messages> messages;
- std::deque<QueuedMessage> pendingDequeues;//used to avoid dequeuing during recovery
+ std::vector<Message> pendingDequeues;
/** messageLock is used to keep the Queue's state consistent while processing message
* events, such as message dispatch, enqueue, acquire, and dequeue. It must be held
* while updating certain members in order to keep these members consistent with
* each other:
* o messages
* o sequence
- * o policy
* o listeners
* o allocator
* o observeXXX() methods
@@ -127,9 +144,9 @@ class Queue : public boost::enable_shared_from_this<Queue>,
mutable qpid::sys::Monitor messageLock;
mutable qpid::sys::Mutex ownershipLock;
mutable uint64_t persistenceId;
- framing::FieldTable settings;
- std::auto_ptr<QueuePolicy> policy;
- bool policyExceeded;
+ const QueueSettings settings;
+ qpid::framing::FieldTable encodableSettings;
+ QueueDepth current;
QueueBindings bindings;
std::string alternateExchangeName;
boost::shared_ptr<Exchange> alternateExchange;
@@ -139,43 +156,42 @@ class Queue : public boost::enable_shared_from_this<Queue>,
sys::AtomicValue<uint32_t> dequeueSincePurge; // Count dequeues since last purge.
int eventMode;
Observers observers;
- bool insertSeqNo;
std::string seqNoKey;
Broker* broker;
bool deleted;
UsageBarrier barrier;
- int autoDeleteTimeout;
boost::intrusive_ptr<qpid::sys::TimerTask> autoDeleteTask;
boost::shared_ptr<MessageDistributor> allocator;
- void push(boost::intrusive_ptr<Message>& msg, bool isRecovery=false);
- void setPolicy(std::auto_ptr<QueuePolicy> policy);
- bool getNextMessage(QueuedMessage& msg, Consumer::shared_ptr& c);
- ConsumeCode consumeNextMessage(QueuedMessage& msg, Consumer::shared_ptr& c);
- bool browseNextMessage(QueuedMessage& msg, Consumer::shared_ptr& c);
- void notifyListener();
+ virtual void push(Message& msg, bool isRecovery=false);
+ void process(Message& msg);
+ bool enqueue(TransactionContext* ctxt, Message& msg);
+ bool getNextMessage(Message& msg, Consumer::shared_ptr& c);
void removeListener(Consumer::shared_ptr);
- bool isExcluded(boost::intrusive_ptr<Message>& msg);
+ bool isExcluded(const Message& msg);
- /** update queue observers, stats, policy, etc when the messages' state changes.
- * messageLock is held by caller */
- void observeEnqueue(const QueuedMessage& msg, const sys::Mutex::ScopedLock& lock);
- void observeAcquire(const QueuedMessage& msg, const sys::Mutex::ScopedLock& lock);
- void observeRequeue(const QueuedMessage& msg, const sys::Mutex::ScopedLock& lock);
- void observeDequeue(const QueuedMessage& msg, const sys::Mutex::ScopedLock& lock);
+ /** update queue observers, stats, policy, etc when the messages' state changes. Lock
+ * must be held by caller */
+ void observeEnqueue(const Message& msg, const sys::Mutex::ScopedLock& lock);
+ void observeAcquire(const Message& msg, const sys::Mutex::ScopedLock& lock);
+ void observeRequeue(const Message& msg, const sys::Mutex::ScopedLock& lock);
+ void observeDequeue(const Message& msg, const sys::Mutex::ScopedLock& lock);
void observeConsumerAdd( const Consumer&, const sys::Mutex::ScopedLock& lock);
void observeConsumerRemove( const Consumer&, const sys::Mutex::ScopedLock& lock);
- bool popAndDequeue(QueuedMessage&);
- bool acquire(const qpid::framing::SequenceNumber& position, QueuedMessage& msg);
- void forcePersistent(QueuedMessage& msg);
+ bool acquire(const qpid::framing::SequenceNumber& position, Message& msg,
+ const qpid::sys::Mutex::ScopedLock& locker);
+
+ void forcePersistent(const Message& msg);
int getEventMode();
- void configureImpl(const qpid::framing::FieldTable& settings);
- void checkNotDeleted(const Consumer::shared_ptr& c);
+ void dequeueFromStore(boost::intrusive_ptr<PersistableMessage>);
+ void abandoned(const Message& message);
+ void checkNotDeleted(const Consumer::shared_ptr&);
void notifyDeleted();
- void dequeueIf(Messages::Predicate predicate, std::deque<QueuedMessage>& dequeued);
+ uint32_t remove(uint32_t maxCount, MessagePredicate, MessageFunctor, SubscriptionType);
+ virtual bool checkDepth(const QueueDepth& increment, const Message&);
public:
@@ -184,12 +200,11 @@ class Queue : public boost::enable_shared_from_this<Queue>,
typedef std::vector<shared_ptr> vector;
QPID_BROKER_EXTERN Queue(const std::string& name,
- bool autodelete = false,
+ const QueueSettings& settings = QueueSettings(),
MessageStore* const store = 0,
- const OwnershipToken* const owner = 0,
management::Manageable* parent = 0,
Broker* broker = 0);
- QPID_BROKER_EXTERN ~Queue();
+ QPID_BROKER_EXTERN virtual ~Queue();
/** allow the Consumer to consume or browse the next available message */
QPID_BROKER_EXTERN bool dispatch(Consumer::shared_ptr);
@@ -198,19 +213,13 @@ class Queue : public boost::enable_shared_from_this<Queue>,
* @param msg - message to be acquired.
* @return false if message is no longer available for acquire.
*/
- QPID_BROKER_EXTERN bool acquire(const QueuedMessage& msg, const std::string& consumer);
+ QPID_BROKER_EXTERN bool acquire(const QueueCursor& msg, const std::string& consumer);
/**
- * Used to configure a new queue and create a persistent record
- * for it in store if required.
+ * Used to create a persistent record for the queue in store if required.
*/
- QPID_BROKER_EXTERN void create(const qpid::framing::FieldTable& settings);
+ QPID_BROKER_EXTERN void create();
- /**
- * Used to reconfigure a recovered queue (does not create
- * persistent record in store).
- */
- QPID_BROKER_EXTERN void configure(const qpid::framing::FieldTable& settings);
void destroyed();
QPID_BROKER_EXTERN void bound(const std::string& exchange,
const std::string& key,
@@ -224,34 +233,36 @@ class Queue : public boost::enable_shared_from_this<Queue>,
boost::shared_ptr<Exchange> exchange, const std::string& key,
const qpid::framing::FieldTable& arguments=qpid::framing::FieldTable());
- /** Acquire the message at the given position if it is available for acquire. Not to
- * be used by clients, but used by the broker for queue management.
- * @param message - set to the acquired message if true returned.
- * @return true if the message has been acquired.
+ /**
+ * Removes (and dequeues) a message by its sequence number (used
+ * for some broker features, e.g. queue replication)
+ *
+ * @param position the sequence number of the message to be dequeued.
+ * @return true if the message is dequeued.
*/
- QPID_BROKER_EXTERN bool acquireMessageAt(const qpid::framing::SequenceNumber& position, QueuedMessage& message);
+ QPID_BROKER_EXTERN bool dequeueMessageAt(const qpid::framing::SequenceNumber& position);
/**
* Delivers a message to the queue. Will record it as
* enqueued if persistent then process it.
*/
- QPID_BROKER_EXTERN void deliver(boost::intrusive_ptr<Message> msg);
- /**
- * Dispatches the messages immediately to a consumer if
- * one is available or stores it for later if not.
- */
- QPID_BROKER_EXTERN void process(boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN void deliver(Message, TxBuffer* = 0);
/**
* Returns a message to the in-memory queue (due to lack
* of acknowledegement from a receiver). If a consumer is
* available it will be dispatched immediately, else it
* will be returned to the front of the queue.
*/
- QPID_BROKER_EXTERN void requeue(const QueuedMessage& msg);
+ QPID_BROKER_EXTERN void release(const QueueCursor& msg, bool markRedelivered=true);
+ QPID_BROKER_EXTERN void reject(const QueueCursor& msg);
+
+ QPID_BROKER_EXTERN bool seek(QueueCursor&, MessagePredicate);
+ QPID_BROKER_EXTERN bool seek(QueueCursor&, MessagePredicate, qpid::framing::SequenceNumber start);
+ QPID_BROKER_EXTERN bool seek(QueueCursor&, qpid::framing::SequenceNumber start);
/**
* Used during recovery to add stored messages back to the queue
*/
- QPID_BROKER_EXTERN void recover(boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN void recover(Message& msg);
QPID_BROKER_EXTERN void consume(Consumer::shared_ptr c,
bool exclusive = false);
@@ -268,7 +279,6 @@ class Queue : public boost::enable_shared_from_this<Queue>,
const qpid::types::Variant::Map *filter=0);
QPID_BROKER_EXTERN uint32_t getMessageCount() const;
- QPID_BROKER_EXTERN uint32_t getEnqueueCompleteMessageCount() const;
QPID_BROKER_EXTERN uint32_t getConsumerCount() const;
inline const std::string& getName() const { return name; }
QPID_BROKER_EXTERN bool isExclusiveOwner(const OwnershipToken* const o) const;
@@ -277,8 +287,9 @@ class Queue : public boost::enable_shared_from_this<Queue>,
QPID_BROKER_EXTERN bool hasExclusiveConsumer() const;
QPID_BROKER_EXTERN bool hasExclusiveOwner() const;
inline bool isDurable() const { return store != 0; }
- inline const framing::FieldTable& getSettings() const { return settings; }
- inline bool isAutoDelete() const { return autodelete; }
+ inline const QueueSettings& getSettings() const { return settings; }
+ inline const qpid::framing::FieldTable& getEncodableSettings() const { return encodableSettings; }
+ inline bool isAutoDelete() const { return settings.autodelete; }
QPID_BROKER_EXTERN bool canAutoDelete() const;
const QueueBindings& getBindings() const { return bindings; }
@@ -288,48 +299,22 @@ class Queue : public boost::enable_shared_from_this<Queue>,
QPID_BROKER_EXTERN void setLastNodeFailure();
QPID_BROKER_EXTERN void clearLastNodeFailure();
- QPID_BROKER_EXTERN bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg, bool suppressPolicyCheck = false);
- QPID_BROKER_EXTERN void enqueueAborted(boost::intrusive_ptr<Message> msg);
/**
* dequeue from store (only done once messages is acknowledged)
*/
- QPID_BROKER_EXTERN bool dequeue(TransactionContext* ctxt, const QueuedMessage &msg);
+ QPID_BROKER_EXTERN void dequeue(TransactionContext* ctxt, const QueueCursor&);
/**
* Inform the queue that a previous transactional dequeue
* committed.
*/
- QPID_BROKER_EXTERN void dequeueCommitted(const QueuedMessage& msg);
-
- /**
- * Inform queue of messages that were enqueued, have since
- * been acquired but not yet accepted or released (and
- * thus are still logically on the queue) - used in
- * clustered broker.
- */
- QPID_BROKER_EXTERN void updateEnqueued(const QueuedMessage& msg);
-
- /**
- * Test whether the specified message (identified by its
- * sequence/position), is still enqueued (note this
- * doesn't mean it is available for delivery as it may
- * have been delievered to a subscriber who has not yet
- * accepted it).
- */
- QPID_BROKER_EXTERN bool isEnqueued(const QueuedMessage& msg);
-
- /**
- * Acquires the next available (oldest) message
- */
- QPID_BROKER_EXTERN QueuedMessage get();
+ void dequeueCommitted(const QueueCursor& msg);
/** Get the message at position pos, returns true if found and sets msg */
- QPID_BROKER_EXTERN bool find(framing::SequenceNumber pos, QueuedMessage& msg ) const;
-
- QPID_BROKER_EXTERN const QueuePolicy* getPolicy();
+ QPID_BROKER_EXTERN bool find(framing::SequenceNumber pos, Message& msg ) const;
QPID_BROKER_EXTERN void setAlternateExchange(boost::shared_ptr<Exchange> exchange);
QPID_BROKER_EXTERN boost::shared_ptr<Exchange> getAlternateExchange();
- QPID_BROKER_EXTERN bool isLocal(boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN bool isLocal(const Message& msg);
//PersistableQueue support:
QPID_BROKER_EXTERN uint64_t getPersistenceId() const;
@@ -410,7 +395,11 @@ class Queue : public boost::enable_shared_from_this<Queue>,
* Reserve space in policy for an enqueued message that
* has been recovered in the prepared state (dtx only)
*/
- QPID_BROKER_EXTERN void recoverPrepared(boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN void recoverPrepared(const Message& msg);
+ void enqueueAborted(const Message& msg);
+ void enqueueCommited(Message& msg);
+ void dequeueAborted(Message& msg);
+ void dequeueCommited(const Message& msg);
QPID_BROKER_EXTERN void flush();
@@ -418,6 +407,7 @@ class Queue : public boost::enable_shared_from_this<Queue>,
uint32_t getDequeueSincePurge() { return dequeueSincePurge.get(); }
QPID_BROKER_EXTERN void setDequeueSincePurge(uint32_t value);
+ friend class QueueFactory;
};
}
}
diff --git a/cpp/src/qpid/broker/QueueAsyncContext.cpp b/cpp/src/qpid/broker/QueueAsyncContext.cpp
index 02eb2e9546..1bad5387a3 100644
--- a/cpp/src/qpid/broker/QueueAsyncContext.cpp
+++ b/cpp/src/qpid/broker/QueueAsyncContext.cpp
@@ -37,6 +37,7 @@ QueueAsyncContext::QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
m_arq(arq)
{}
+/*
QueueAsyncContext::QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
boost::intrusive_ptr<PersistableMessage> msg,
AsyncResultCallback rcb,
@@ -46,6 +47,7 @@ QueueAsyncContext::QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
m_rcb(rcb),
m_arq(arq)
{}
+*/
QueueAsyncContext::QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
SimpleTxnBuffer* tb,
@@ -59,6 +61,7 @@ QueueAsyncContext::QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
assert(m_q.get() != 0);
}
+/*
QueueAsyncContext::QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
boost::intrusive_ptr<PersistableMessage> msg,
SimpleTxnBuffer* tb,
@@ -73,6 +76,7 @@ QueueAsyncContext::QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
assert(m_q.get() != 0);
assert(m_msg.get() != 0);
}
+*/
QueueAsyncContext::~QueueAsyncContext()
{}
@@ -83,11 +87,13 @@ QueueAsyncContext::getQueue() const
return m_q;
}
+/*
boost::intrusive_ptr<PersistableMessage>
QueueAsyncContext::getMessage() const
{
return m_msg;
}
+*/
SimpleTxnBuffer*
QueueAsyncContext::getTxnBuffer() const {
diff --git a/cpp/src/qpid/broker/QueueAsyncContext.h b/cpp/src/qpid/broker/QueueAsyncContext.h
index 8657922377..7a159f2639 100644
--- a/cpp/src/qpid/broker/QueueAsyncContext.h
+++ b/cpp/src/qpid/broker/QueueAsyncContext.h
@@ -47,22 +47,22 @@ public:
QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
AsyncResultCallback rcb,
AsyncResultQueue* const arq);
- QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
+/* QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
boost::intrusive_ptr<PersistableMessage> msg,
AsyncResultCallback rcb,
- AsyncResultQueue* const arq);
+ AsyncResultQueue* const arq);*/
QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
SimpleTxnBuffer* tb,
AsyncResultCallback rcb,
AsyncResultQueue* const arq);
- QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
+/* QueueAsyncContext(boost::shared_ptr<PersistableQueue> q,
boost::intrusive_ptr<PersistableMessage> msg,
SimpleTxnBuffer* tb,
AsyncResultCallback rcb,
- AsyncResultQueue* const arq);
+ AsyncResultQueue* const arq);*/
virtual ~QueueAsyncContext();
boost::shared_ptr<PersistableQueue> getQueue() const;
- boost::intrusive_ptr<PersistableMessage> getMessage() const;
+// boost::intrusive_ptr<PersistableMessage> getMessage() const;
SimpleTxnBuffer* getTxnBuffer() const;
AsyncResultQueue* getAsyncResultQueue() const;
AsyncResultCallback getAsyncResultCallback() const;
@@ -71,7 +71,7 @@ public:
private:
boost::shared_ptr<PersistableQueue> m_q;
- boost::intrusive_ptr<PersistableMessage> m_msg;
+// boost::intrusive_ptr<PersistableMessage> m_msg;
SimpleTxnBuffer* m_tb;
AsyncResultCallback m_rcb;
AsyncResultQueue* const m_arq;
diff --git a/cpp/src/qpid/cluster/ExpiryPolicy.cpp b/cpp/src/qpid/broker/QueueCursor.cpp
index 0ef5c2a35d..e48b18b748 100644
--- a/cpp/src/qpid/cluster/ExpiryPolicy.cpp
+++ b/cpp/src/qpid/broker/QueueCursor.cpp
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,24 +18,27 @@
* under the License.
*
*/
-
+#include "QueueCursor.h"
#include "qpid/broker/Message.h"
-#include "qpid/cluster/ExpiryPolicy.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/sys/Time.h"
-#include "qpid/log/Statement.h"
namespace qpid {
-namespace cluster {
+namespace broker {
+QueueCursor::QueueCursor(SubscriptionType t) : type(t), position(0), version(0), valid(false) {}
-ExpiryPolicy::ExpiryPolicy(Cluster& cluster) : cluster(cluster) {}
-
-bool ExpiryPolicy::hasExpired(broker::Message& m) {
- return m.getExpiration() < cluster.getClusterTime();
+void QueueCursor::setPosition(int32_t p, int32_t v)
+{
+ position = p;
+ version = v;
+ valid = true;
}
-sys::AbsTime ExpiryPolicy::getCurrentTime() {
- return cluster.getClusterTime();
+bool QueueCursor::check(const Message& m)
+{
+ return (m.getState() == AVAILABLE || ((type == REPLICATOR || type == PURGE) && m.getState() == ACQUIRED));
}
-}} // namespace qpid::cluster
+bool QueueCursor::isValid(int32_t v)
+{
+ return valid && (valid = (v == version));
+}
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/cluster/SecureConnectionFactory.h b/cpp/src/qpid/broker/QueueCursor.h
index 24d1fcfee5..2551b64a48 100644
--- a/cpp/src/qpid/cluster/SecureConnectionFactory.h
+++ b/cpp/src/qpid/broker/QueueCursor.h
@@ -1,3 +1,6 @@
+#ifndef QPID_BROKER_QUEUECURSOR_H
+#define QPID_BROKER_QUEUECURSOR_H
+
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -7,9 +10,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,41 +21,51 @@
* under the License.
*
*/
-#ifndef QPID_CLUSTER_SecureconnectionFactory
-#define QPID_CLUSTER_SecureconnectionFactory
-
-#include "qpid/sys/ConnectionCodec.h"
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
#include <boost/shared_ptr.hpp>
namespace qpid {
-
namespace broker {
- class Broker;
-}
-namespace cluster {
+class Message;
+
+enum SubscriptionType
+{
+ CONSUMER,
+ BROWSER,
+ PURGE,
+ REPLICATOR
+};
-class SecureConnectionFactory : public qpid::sys::ConnectionCodec::Factory
+class CursorContext {
+ public:
+ virtual ~CursorContext() {}
+};
+/**
+ *
+ */
+class QueueCursor
{
public:
- typedef boost::shared_ptr<qpid::sys::ConnectionCodec::Factory> CodecFactoryPtr;
- SecureConnectionFactory(CodecFactoryPtr f);
-
- qpid::sys::ConnectionCodec* create(
- framing::ProtocolVersion, qpid::sys::OutputControl&, const std::string& id,
- const qpid::sys::SecuritySettings&
- );
-
- /** Return "preferred" codec for outbound connections. */
- qpid::sys::ConnectionCodec* create(
- qpid::sys::OutputControl&, const std::string& id, const qpid::sys::SecuritySettings&
- );
+ QPID_BROKER_EXTERN QueueCursor(SubscriptionType type = CONSUMER);
private:
- CodecFactoryPtr codecFactory;
-};
+ SubscriptionType type;
+ int32_t position;
+ int32_t version;
+ bool valid;
+ boost::shared_ptr<CursorContext> context;
-}} // namespace qpid::cluster
+ void setPosition(int32_t p, int32_t v);
+ bool check(const Message& m);
+ bool isValid(int32_t v);
+ friend class MessageDeque;
+ friend class MessageMap;
+ friend class PriorityQueue;
+ template <typename T> friend class IndexedDeque;
+};
+}} // namespace qpid::broker
-#endif // QPID_CLUSTER_SecureconnectionFactory
+#endif /*!QPID_BROKER_QUEUECURSOR_H*/
diff --git a/cpp/src/qpid/broker/QueueDepth.cpp b/cpp/src/qpid/broker/QueueDepth.cpp
new file mode 100644
index 0000000000..69ec0ab4ac
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueDepth.cpp
@@ -0,0 +1,127 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "QueueDepth.h"
+
+namespace qpid {
+namespace broker {
+
+QueueDepth::QueueDepth() {}
+QueueDepth::QueueDepth(uint32_t c, uint64_t s) : count(c), size(s) {}
+QueueDepth& QueueDepth::operator+=(const QueueDepth& other)
+{
+ if (count.valid) count.value += other.count.value;
+ if (size.valid) size.value += other.size.value;
+ return *this;
+}
+QueueDepth& QueueDepth::operator-=(const QueueDepth& other)
+{
+ if (count.valid) count.value -= other.count.value;
+ if (size.valid) size.value -= other.size.value;
+ return *this;
+}
+bool QueueDepth::operator==(const QueueDepth& other) const
+{
+ //only compare values, not validity an invalid value is always 0;
+ //this means that an invalid value will match an empty queue
+ //depth, which is fine
+ return (count.value == other.count.value)
+ && (size.value == other.size.value);
+}
+bool QueueDepth::operator!=(const QueueDepth& other) const
+{
+ return !(*this == other);
+}
+bool QueueDepth::operator<(const QueueDepth& other) const
+{
+ if (count.valid && size.valid)
+ return count.value < other.count.value || size.value < other.size.value;
+ else if (count.valid)
+ return count.value < other.count.value;
+ else
+ return size.value < other.size.value;
+}
+bool QueueDepth::operator>(const QueueDepth& other) const
+{
+ if (count.valid && size.valid)
+ return count.value > other.count.value || size.value > other.size.value;
+ else if (count.valid)
+ return count.value > other.count.value;
+ else
+ return size.value > other.size.value;
+}
+bool QueueDepth::hasCount() const { return count.valid; }
+uint32_t QueueDepth::getCount() const { return count.value; }
+void QueueDepth::setCount(uint32_t c) { count.value = c; count.valid = true; }
+bool QueueDepth::hasSize() const { return size.valid; }
+uint64_t QueueDepth::getSize() const { return size.value; }
+void QueueDepth::setSize(uint64_t c) { size.value = c; size.valid = true; }
+
+namespace{
+ template <typename T> QueueDepth::Optional<T> add(const QueueDepth::Optional<T>& a, const QueueDepth::Optional<T>& b)
+ {
+ QueueDepth::Optional<T> result;
+ if (a.valid && b.valid) {
+ result.valid = true;
+ result.value = a.value + b.value;
+ }
+ return result;
+ }
+ template <typename T> QueueDepth::Optional<T> subtract(const QueueDepth::Optional<T>& a, const QueueDepth::Optional<T>& b)
+ {
+ QueueDepth::Optional<T> result;
+ if (a.valid && b.valid) {
+ result.valid = true;
+ result.value = a.value - b.value;
+ }
+ return result;
+ }
+}
+QueueDepth operator-(const QueueDepth& a, const QueueDepth& b)
+{
+ QueueDepth result;
+ result.count = subtract(a.count, b.count);
+ result.size = subtract(a.size, b.size);
+ return result;
+}
+
+QueueDepth operator+(const QueueDepth& a, const QueueDepth& b)
+{
+ QueueDepth result;
+ result.count = add(a.count, b.count);
+ result.size = add(a.size, b.size);
+ return result;
+
+}
+
+std::ostream& operator<<(std::ostream& o, const QueueDepth& d)
+{
+ if (d.hasCount()) o << "count: " << d.getCount();
+ if (d.hasSize()) {
+ if (d.hasCount()) o << ", ";
+ o << "size: " << d.getSize();
+ }
+ return o;
+}
+
+QueueDepth::operator bool() const { return hasCount() || hasSize(); }
+
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/QueueDepth.h b/cpp/src/qpid/broker/QueueDepth.h
new file mode 100644
index 0000000000..d93acb2a7a
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueDepth.h
@@ -0,0 +1,74 @@
+#ifndef QPID_BROKER_QUEUEDEPTH_H
+#define QPID_BROKER_QUEUEDEPTH_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/sys/IntegerTypes.h"
+#include <ostream>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Represents a queue depth in message count and/or aggregate message
+ * size.
+ */
+class QueueDepth
+{
+ public:
+ QPID_BROKER_EXTERN QueueDepth();
+ QPID_BROKER_EXTERN QueueDepth(uint32_t count, uint64_t size);
+ QPID_BROKER_EXTERN QueueDepth& operator+=(const QueueDepth&);
+ QPID_BROKER_EXTERN QueueDepth& operator-=(const QueueDepth&);
+ QPID_BROKER_EXTERN bool operator==(const QueueDepth&) const;
+ QPID_BROKER_EXTERN bool operator!=(const QueueDepth&) const;
+ QPID_BROKER_EXTERN bool operator<(const QueueDepth& other) const;
+ QPID_BROKER_EXTERN bool operator>(const QueueDepth& other) const;
+ QPID_BROKER_EXTERN operator bool() const;
+ QPID_BROKER_EXTERN bool hasCount() const;
+ QPID_BROKER_EXTERN uint32_t getCount() const;
+ QPID_BROKER_EXTERN void setCount(uint32_t);
+ QPID_BROKER_EXTERN bool hasSize() const;
+ QPID_BROKER_EXTERN uint64_t getSize() const;
+ QPID_BROKER_EXTERN void setSize(uint64_t);
+ friend QPID_BROKER_EXTERN QueueDepth operator-(const QueueDepth&, const QueueDepth&);
+ friend QPID_BROKER_EXTERN QueueDepth operator+(const QueueDepth&, const QueueDepth&);
+ template <typename T> struct Optional
+ {
+ T value;
+ bool valid;
+
+ Optional(T v) : value(v), valid(true) {}
+ Optional() : value(0), valid(false) {}
+ };
+ private:
+ Optional<uint32_t> count;
+ Optional<uint64_t> size;
+};
+
+QPID_BROKER_EXTERN QueueDepth operator-(const QueueDepth&, const QueueDepth&);
+QPID_BROKER_EXTERN QueueDepth operator+(const QueueDepth&, const QueueDepth&);
+std::ostream& operator<<(std::ostream&, const QueueDepth&);
+
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_QUEUEDEPTH_H*/
diff --git a/cpp/src/qpid/broker/QueueEvents.cpp b/cpp/src/qpid/broker/QueueEvents.cpp
deleted file mode 100644
index b102a8554d..0000000000
--- a/cpp/src/qpid/broker/QueueEvents.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/broker/QueueEvents.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/QueueObserver.h"
-#include "qpid/Exception.h"
-#include "qpid/log/Statement.h"
-
-namespace qpid {
-namespace broker {
-
-QueueEvents::QueueEvents(const boost::shared_ptr<sys::Poller>& poller, bool isSync) :
- eventQueue(boost::bind(&QueueEvents::handle, this, _1), poller), enabled(true), sync(isSync)
-{
- if (!sync) eventQueue.start();
-}
-
-QueueEvents::~QueueEvents()
-{
- if (!sync) eventQueue.stop();
-}
-
-void QueueEvents::enqueued(const QueuedMessage& m)
-{
- if (enabled) {
- Event enq(ENQUEUE, m);
- if (sync) {
- for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++)
- j->second(enq);
- } else {
- eventQueue.push(enq);
- }
- }
-}
-
-void QueueEvents::dequeued(const QueuedMessage& m)
-{
- if (enabled) {
- Event deq(DEQUEUE, m);
- if (sync) {
- for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++)
- j->second(deq);
- } else {
- eventQueue.push(Event(DEQUEUE, m));
- }
- }
-}
-
-void QueueEvents::registerListener(const std::string& id, const EventListener& listener)
-{
- qpid::sys::Mutex::ScopedLock l(lock);
- if (listeners.find(id) == listeners.end()) {
- listeners[id] = listener;
- } else {
- throw Exception(QPID_MSG("Event listener already registered for '" << id << "'"));
- }
-}
-
-void QueueEvents::unregisterListener(const std::string& id)
-{
- qpid::sys::Mutex::ScopedLock l(lock);
- if (listeners.find(id) == listeners.end()) {
- throw Exception(QPID_MSG("No event listener registered for '" << id << "'"));
- } else {
- listeners.erase(id);
- }
-}
-
-QueueEvents::EventQueue::Batch::const_iterator
-QueueEvents::handle(const EventQueue::Batch& events) {
- qpid::sys::Mutex::ScopedLock l(lock);
- for (EventQueue::Batch::const_iterator i = events.begin(); i != events.end(); ++i) {
- for (Listeners::iterator j = listeners.begin(); j != listeners.end(); j++) {
- j->second(*i);
- }
- }
- return events.end();
-}
-
-void QueueEvents::shutdown()
-{
- if (!sync && !eventQueue.empty() && !listeners.empty()) eventQueue.shutdown();
-}
-
-void QueueEvents::enable()
-{
- enabled = true;
- QPID_LOG(debug, "Queue events enabled");
-}
-
-void QueueEvents::disable()
-{
- enabled = false;
- QPID_LOG(debug, "Queue events disabled");
-}
-
-bool QueueEvents::isSync()
-{
- return sync;
-}
-
-class EventGenerator : public QueueObserver
-{
- public:
- EventGenerator(QueueEvents& mgr, bool enqOnly) : manager(mgr), enqueueOnly(enqOnly) {}
- void enqueued(const QueuedMessage& m)
- {
- manager.enqueued(m);
- }
- void dequeued(const QueuedMessage& m)
- {
- if (!enqueueOnly) manager.dequeued(m);
- }
-
- void acquired(const QueuedMessage&) {};
- void requeued(const QueuedMessage&) {};
-
- private:
- QueueEvents& manager;
- const bool enqueueOnly;
-};
-
-void QueueEvents::observe(Queue& queue, bool enqueueOnly)
-{
- boost::shared_ptr<QueueObserver> observer(new EventGenerator(*this, enqueueOnly));
- queue.addObserver(observer);
-}
-
-
-QueueEvents::Event::Event(EventType t, const QueuedMessage& m) : type(t), msg(m) {}
-
-
-}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/QueueEvents.h b/cpp/src/qpid/broker/QueueEvents.h
deleted file mode 100644
index d0a267e6e2..0000000000
--- a/cpp/src/qpid/broker/QueueEvents.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef QPID_BROKER_QUEUEEVENTS_H
-#define QPID_BROKER_QUEUEEVENTS_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/broker/BrokerImportExport.h"
-#include "qpid/broker/QueuedMessage.h"
-#include "qpid/sys/Mutex.h"
-#include "qpid/sys/PollableQueue.h"
-#include <map>
-#include <string>
-#include <boost/function.hpp>
-
-namespace qpid {
-namespace broker {
-
-/**
- * Event manager for queue events. Allows queues to indicate when
- * events have occurred; allows listeners to register for notification
- * of this. The notification happens asynchronously, in a separate
- * thread.
- */
-class QueueEvents
-{
- public:
- enum EventType {ENQUEUE, DEQUEUE};
-
- struct Event
- {
- EventType type;
- QueuedMessage msg;
-
- QPID_BROKER_EXTERN Event(EventType, const QueuedMessage&);
- };
-
- typedef boost::function<void (Event)> EventListener;
-
- QPID_BROKER_EXTERN QueueEvents(const boost::shared_ptr<sys::Poller>& poller, bool isSync = false);
- QPID_BROKER_EXTERN ~QueueEvents();
- QPID_BROKER_EXTERN void enqueued(const QueuedMessage&);
- QPID_BROKER_EXTERN void dequeued(const QueuedMessage&);
- QPID_BROKER_EXTERN void registerListener(const std::string& id,
- const EventListener&);
- QPID_BROKER_EXTERN void unregisterListener(const std::string& id);
- void enable();
- void disable();
- void observe(Queue&, bool enqueueOnly);
- //process all outstanding events
- QPID_BROKER_EXTERN void shutdown();
- QPID_BROKER_EXTERN bool isSync();
- private:
- typedef qpid::sys::PollableQueue<Event> EventQueue;
- typedef std::map<std::string, EventListener> Listeners;
-
- EventQueue eventQueue;
- Listeners listeners;
- volatile bool enabled;
- qpid::sys::Mutex lock;//protect listeners from concurrent access
- bool sync;
-
- EventQueue::Batch::const_iterator handle(const EventQueue::Batch& e);
-
-};
-}} // namespace qpid::broker
-
-#endif /*!QPID_BROKER_QUEUEEVENTS_H*/
diff --git a/cpp/src/qpid/broker/QueueFactory.cpp b/cpp/src/qpid/broker/QueueFactory.cpp
new file mode 100644
index 0000000000..efeb9ae53b
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueFactory.cpp
@@ -0,0 +1,114 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/QueueFactory.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/QueueSettings.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/LossyQueue.h"
+#include "qpid/broker/Lvq.h"
+#include "qpid/broker/Messages.h"
+#include "qpid/broker/MessageDistributor.h"
+#include "qpid/broker/MessageGroupManager.h"
+#include "qpid/broker/Fairshare.h"
+#include "qpid/broker/MessageDeque.h"
+#include "qpid/broker/MessageMap.h"
+#include "qpid/broker/PriorityQueue.h"
+#include "qpid/broker/QueueFlowLimit.h"
+#include "qpid/broker/ThresholdAlerts.h"
+#include "qpid/broker/FifoDistributor.h"
+#include <map>
+#include <memory>
+
+namespace qpid {
+namespace broker {
+
+
+QueueFactory::QueueFactory() : broker(0), store(0), parent(0) {}
+
+boost::shared_ptr<Queue> QueueFactory::create(const std::string& name, const QueueSettings& settings)
+{
+ settings.validate();
+
+ //1. determine Queue type (i.e. whether we are subclassing Queue)
+ // -> if 'ring' policy is in use then subclass
+ boost::shared_ptr<Queue> queue;
+ if (settings.dropMessagesAtLimit) {
+ queue = boost::shared_ptr<Queue>(new LossyQueue(name, settings, settings.durable ? store : 0, parent, broker));
+ } else if (settings.lvqKey.size()) {
+ std::auto_ptr<MessageMap> map(new MessageMap(settings.lvqKey));
+ queue = boost::shared_ptr<Queue>(new Lvq(name, map, settings, settings.durable ? store : 0, parent, broker));
+ } else {
+ queue = boost::shared_ptr<Queue>(new Queue(name, settings, settings.durable ? store : 0, parent, broker));
+ }
+
+ //2. determine Messages type (i.e. structure)
+ if (settings.priorities) {
+ if (settings.defaultFairshare || settings.fairshare.size()) {
+ queue->messages = Fairshare::create(settings);
+ } else {
+ queue->messages = std::auto_ptr<Messages>(new PriorityQueue(settings.priorities));
+ }
+ } else if (settings.lvqKey.empty()) {//LVQ already handled above
+ queue->messages = std::auto_ptr<Messages>(new MessageDeque());
+ }
+
+ //3. determine MessageDistributor type
+ if (settings.groupKey.size()) {
+ boost::shared_ptr<MessageGroupManager> mgm(MessageGroupManager::create( name, *(queue->messages), settings));
+ queue->allocator = mgm;
+ queue->addObserver(mgm);
+ } else {
+ queue->allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *(queue->messages) ));
+ }
+
+
+ //4. threshold event config
+ if (broker && broker->getManagementAgent()) {
+ ThresholdAlerts::observe(*queue, *(broker->getManagementAgent()), settings, broker->getOptions().queueThresholdEventRatio);
+ }
+ //5. flow control config
+ QueueFlowLimit::observe(*queue, settings);
+
+ return queue;
+}
+
+void QueueFactory::setBroker(Broker* b)
+{
+ broker = b;
+}
+Broker* QueueFactory::getBroker()
+{
+ return broker;
+}
+void QueueFactory::setStore (MessageStore* s)
+{
+ store = s;
+}
+MessageStore* QueueFactory::getStore() const
+{
+ return store;
+}
+void QueueFactory::setParent(management::Manageable* p)
+{
+ parent = p;
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/QueueFactory.h b/cpp/src/qpid/broker/QueueFactory.h
new file mode 100644
index 0000000000..b6a79f1f1a
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueFactory.h
@@ -0,0 +1,73 @@
+#ifndef QPID_BROKER_QUEUEFACTORY_H
+#define QPID_BROKER_QUEUEFACTORY_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/types/Variant.h"
+#include <boost/shared_ptr.hpp>
+
+namespace qpid {
+namespace management {
+class Manageable;
+}
+namespace broker {
+class Broker;
+class MessageStore;
+class Queue;
+struct QueueSettings;
+
+/**
+ * Handles the creation and configuration of a Queue instance in order
+ * to meet the required settings
+ */
+class QueueFactory
+{
+ public:
+ QPID_BROKER_EXTERN QueueFactory();
+
+ QPID_BROKER_EXTERN boost::shared_ptr<Queue> create(const std::string& name, const QueueSettings& settings);
+
+ void setBroker(Broker*);
+ Broker* getBroker();
+
+ /**
+ * Set the store to use. May only be called once.
+ */
+ void setStore (MessageStore*);
+
+ /**
+ * Return the message store used.
+ */
+ MessageStore* getStore() const;
+
+ /**
+ * Register the manageable parent for declared queues
+ */
+ void setParent(management::Manageable*);
+ private:
+ Broker* broker;
+ MessageStore* store;
+ management::Manageable* parent;
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_QUEUEFACTORY_H*/
diff --git a/cpp/src/qpid/broker/QueueFlowLimit.cpp b/cpp/src/qpid/broker/QueueFlowLimit.cpp
index 14fe5f4022..11b9cbae63 100644
--- a/cpp/src/qpid/broker/QueueFlowLimit.cpp
+++ b/cpp/src/qpid/broker/QueueFlowLimit.cpp
@@ -20,7 +20,9 @@
*/
#include "qpid/broker/QueueFlowLimit.h"
#include "qpid/broker/Broker.h"
+#include "qpid/broker/Message.h"
#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueueSettings.h"
#include "qpid/Exception.h"
#include "qpid/framing/FieldValue.h"
#include "qpid/framing/reply_exceptions.h"
@@ -57,34 +59,6 @@ namespace {
<< "=" << max));
}
}
-
- /** extract a capacity value as passed in an argument map
- */
- uint64_t getCapacity(const FieldTable& settings, const std::string& key, uint64_t defaultValue)
- {
- FieldTable::ValuePtr v = settings.get(key);
-
- int64_t result = 0;
-
- if (!v) return defaultValue;
- if (v->getType() == 0x23) {
- QPID_LOG(debug, "Value for " << key << " specified as float: " << v->get<float>());
- } else if (v->getType() == 0x33) {
- QPID_LOG(debug, "Value for " << key << " specified as double: " << v->get<double>());
- } else if (v->convertsTo<int64_t>()) {
- result = v->get<int64_t>();
- QPID_LOG(debug, "Got integer value for " << key << ": " << result);
- if (result >= 0) return result;
- } else if (v->convertsTo<std::string>()) {
- std::string s(v->get<std::string>());
- QPID_LOG(debug, "Got string value for " << key << ": " << s);
- std::istringstream convert(s);
- if (convert >> result && result >= 0) return result;
- }
-
- QPID_LOG(warning, "Cannot convert " << key << " to unsigned integer, using default (" << defaultValue << ")");
- return defaultValue;
- }
}
@@ -102,10 +76,8 @@ QueueFlowLimit::QueueFlowLimit(Queue *_queue,
if (queue) {
queueName = _queue->getName();
- if (queue->getPolicy()) {
- maxSize = _queue->getPolicy()->getMaxSize();
- maxCount = _queue->getPolicy()->getMaxCount();
- }
+ if (queue->getSettings().maxDepth.hasCount()) maxCount = queue->getSettings().maxDepth.getCount();
+ if (queue->getSettings().maxDepth.hasCount()) maxSize = queue->getSettings().maxDepth.getSize();
broker = queue->getBroker();
queueMgmtObj = dynamic_cast<_qmfBroker::Queue*> (queue->GetManagementObject());
if (queueMgmtObj) {
@@ -125,23 +97,23 @@ QueueFlowLimit::~QueueFlowLimit()
sys::Mutex::ScopedLock l(indexLock);
if (!index.empty()) {
// we're gone - release all pending msgs
- for (std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> >::iterator itr = index.begin();
+ for (std::map<framing::SequenceNumber, Message >::iterator itr = index.begin();
itr != index.end(); ++itr)
if (itr->second)
try {
- itr->second->getIngressCompletion().finishCompleter();
+ itr->second.getPersistentContext()->getIngressCompletion().finishCompleter();
} catch (...) {} // ignore - not safe for a destructor to throw.
index.clear();
}
}
-void QueueFlowLimit::enqueued(const QueuedMessage& msg)
+void QueueFlowLimit::enqueued(const Message& msg)
{
sys::Mutex::ScopedLock l(indexLock);
++count;
- size += msg.payload->contentSize();
+ size += msg.getContentSize();
if (!flowStopped) {
if (flowStopCount && count > flowStopCount) {
@@ -160,13 +132,13 @@ void QueueFlowLimit::enqueued(const QueuedMessage& msg)
if (flowStopped || !index.empty()) {
// ignore flow control if we are populating the queue due to cluster replication:
if (broker && broker->isClusterUpdatee()) {
- QPID_LOG(trace, "Queue \"" << queueName << "\": ignoring flow control for msg pos=" << msg.position);
+ QPID_LOG(trace, "Queue \"" << queueName << "\": ignoring flow control for msg pos=" << msg.getSequence());
return;
}
- QPID_LOG(trace, "Queue \"" << queueName << "\": setting flow control for msg pos=" << msg.position);
- msg.payload->getIngressCompletion().startCompleter(); // don't complete until flow resumes
+ QPID_LOG(trace, "Queue \"" << queueName << "\": setting flow control for msg pos=" << msg.getSequence());
+ msg.getPersistentContext()->getIngressCompletion().startCompleter(); // don't complete until flow resumes
bool unique;
- unique = index.insert(std::pair<framing::SequenceNumber, boost::intrusive_ptr<Message> >(msg.position, msg.payload)).second;
+ unique = index.insert(std::pair<framing::SequenceNumber, Message >(msg.getSequence(), msg)).second;
// Like this to avoid tripping up unused variable warning when NDEBUG set
if (!unique) assert(unique);
}
@@ -174,7 +146,7 @@ void QueueFlowLimit::enqueued(const QueuedMessage& msg)
-void QueueFlowLimit::dequeued(const QueuedMessage& msg)
+void QueueFlowLimit::dequeued(const Message& msg)
{
sys::Mutex::ScopedLock l(indexLock);
@@ -184,7 +156,7 @@ void QueueFlowLimit::dequeued(const QueuedMessage& msg)
throw Exception(QPID_MSG("Flow limit count underflow on dequeue. Queue=" << queueName));
}
- uint64_t _size = msg.payload->contentSize();
+ uint64_t _size = msg.getContentSize();
if (_size <= size) {
size -= _size;
} else {
@@ -203,16 +175,16 @@ void QueueFlowLimit::dequeued(const QueuedMessage& msg)
if (!index.empty()) {
if (!flowStopped) {
// flow enabled - release all pending msgs
- for (std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> >::iterator itr = index.begin();
+ for (std::map<framing::SequenceNumber, Message >::iterator itr = index.begin();
itr != index.end(); ++itr)
if (itr->second)
- itr->second->getIngressCompletion().finishCompleter();
+ itr->second.getPersistentContext()->getIngressCompletion().finishCompleter();
index.clear();
} else {
// even if flow controlled, we must release this msg as it is being dequeued
- std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> >::iterator itr = index.find(msg.position);
+ std::map<framing::SequenceNumber, Message >::iterator itr = index.find(msg.getSequence());
if (itr != index.end()) { // this msg is flow controlled, release it:
- msg.payload->getIngressCompletion().finishCompleter();
+ msg.getPersistentContext()->getIngressCompletion().finishCompleter();
index.erase(itr);
}
}
@@ -279,7 +251,7 @@ void QueueFlowLimit::setDefaults(uint64_t maxQueueSize, uint flowStopRatio, uint
}
-void QueueFlowLimit::observe(Queue& queue, const qpid::framing::FieldTable& settings)
+void QueueFlowLimit::observe(Queue& queue, const QueueSettings& settings)
{
QueueFlowLimit *ptr = createLimit( &queue, settings );
if (ptr) {
@@ -289,36 +261,37 @@ void QueueFlowLimit::observe(Queue& queue, const qpid::framing::FieldTable& sett
}
/** returns ptr to a QueueFlowLimit, else 0 if no limit */
-QueueFlowLimit *QueueFlowLimit::createLimit(Queue *queue, const qpid::framing::FieldTable& settings)
+QueueFlowLimit *QueueFlowLimit::createLimit(Queue *queue, const QueueSettings& settings)
{
- std::string type(QueuePolicy::getType(settings));
-
- if (type == QueuePolicy::RING || type == QueuePolicy::RING_STRICT) {
+ if (settings.dropMessagesAtLimit) {
// The size of a RING queue is limited by design - no need for flow control.
return 0;
}
- if (settings.get(flowStopCountKey) || settings.get(flowStopSizeKey) ||
- settings.get(flowResumeCountKey) || settings.get(flowResumeSizeKey)) {
+ if (settings.flowStop.hasCount() || settings.flowStop.hasSize()) {
// user provided (some) flow settings manually...
- uint32_t flowStopCount = getCapacity(settings, flowStopCountKey, 0);
- uint32_t flowResumeCount = getCapacity(settings, flowResumeCountKey, 0);
- uint64_t flowStopSize = getCapacity(settings, flowStopSizeKey, 0);
- uint64_t flowResumeSize = getCapacity(settings, flowResumeSizeKey, 0);
- if (flowStopCount == 0 && flowStopSize == 0) { // disable flow control
+ if (settings.flowStop.getCount() || settings.flowStop.getSize()) {
+ return new QueueFlowLimit(queue,
+ settings.flowStop.getCount(),
+ settings.flowResume.getCount(),
+ settings.flowStop.getSize(),
+ settings.flowResume.getSize());
+ } else {
+ //don't have a non-zero value for either the count or the
+ //size to stop at, yet at least one of these settings was
+ //provided, i.e it was set to 0 explicitly which we treat
+ //as turning it off
return 0;
}
- return new QueueFlowLimit(queue, flowStopCount, flowResumeCount, flowStopSize, flowResumeSize);
}
if (defaultFlowStopRatio) { // broker has a default ratio setup...
- uint64_t maxByteCount = getCapacity(settings, QueuePolicy::maxSizeKey, defaultMaxSize);
+ uint64_t maxByteCount = settings.maxDepth.hasSize() ? settings.maxDepth.getSize() : defaultMaxSize;
uint64_t flowStopSize = (uint64_t)(maxByteCount * (defaultFlowStopRatio/100.0) + 0.5);
uint64_t flowResumeSize = (uint64_t)(maxByteCount * (defaultFlowResumeRatio/100.0));
- uint32_t maxMsgCount = getCapacity(settings, QueuePolicy::maxCountKey, 0); // no size by default
+ uint32_t maxMsgCount = settings.maxDepth.hasCount() ? settings.maxDepth.getCount() : 0;
uint32_t flowStopCount = (uint32_t)(maxMsgCount * (defaultFlowStopRatio/100.0) + 0.5);
uint32_t flowResumeCount = (uint32_t)(maxMsgCount * (defaultFlowResumeRatio/100.0));
-
return new QueueFlowLimit(queue, flowStopCount, flowResumeCount, flowStopSize, flowResumeSize);
}
return 0;
@@ -346,7 +319,7 @@ void QueueFlowLimit::getState(qpid::framing::FieldTable& state ) const
framing::SequenceSet ss;
if (!index.empty()) {
/* replicate the set of messages pending flow control */
- for (std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> >::const_iterator itr = index.begin();
+ for (std::map<framing::SequenceNumber, Message >::const_iterator itr = index.begin();
itr != index.end(); ++itr) {
ss.add(itr->first);
}
@@ -377,10 +350,10 @@ void QueueFlowLimit::setState(const qpid::framing::FieldTable& state)
++i;
fcmsg.add(first, last);
for (SequenceNumber seq = first; seq <= last; ++seq) {
- QueuedMessage msg;
+ Message msg;
queue->find(seq, msg); // fyi: may not be found if msg is acquired & unacked
bool unique;
- unique = index.insert(std::pair<framing::SequenceNumber, boost::intrusive_ptr<Message> >(seq, msg.payload)).second;
+ unique = index.insert(std::pair<framing::SequenceNumber, Message >(seq, msg)).second;
// Like this to avoid tripping up unused variable warning when NDEBUG set
if (!unique) assert(unique);
}
diff --git a/cpp/src/qpid/broker/QueueFlowLimit.h b/cpp/src/qpid/broker/QueueFlowLimit.h
index ad8a2720ef..1bcc388ceb 100644
--- a/cpp/src/qpid/broker/QueueFlowLimit.h
+++ b/cpp/src/qpid/broker/QueueFlowLimit.h
@@ -26,9 +26,9 @@
#include <iostream>
#include <memory>
#include "qpid/broker/BrokerImportExport.h"
-#include "qpid/broker/QueuedMessage.h"
#include "qpid/broker/StatefulQueueObserver.h"
#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/SequenceNumber.h"
#include "qpid/sys/AtomicValue.h"
#include "qpid/sys/Mutex.h"
@@ -45,6 +45,8 @@ namespace qpid {
namespace broker {
class Broker;
+class Queue;
+struct QueueSettings;
/**
* Producer flow control: when level is > flowStop*, flow control is ON.
@@ -80,13 +82,13 @@ class Broker;
QPID_BROKER_EXTERN virtual ~QueueFlowLimit();
- /** the queue has added QueuedMessage. Returns true if flow state changes */
- QPID_BROKER_EXTERN void enqueued(const QueuedMessage&);
- /** the queue has removed QueuedMessage. Returns true if flow state changes */
- QPID_BROKER_EXTERN void dequeued(const QueuedMessage&);
+ /** the queue has added QueuedMessage */
+ QPID_BROKER_EXTERN void enqueued(const Message&);
+ /** the queue has removed QueuedMessage */
+ QPID_BROKER_EXTERN void dequeued(const Message&);
/** ignored */
- QPID_BROKER_EXTERN void acquired(const QueuedMessage&) {};
- QPID_BROKER_EXTERN void requeued(const QueuedMessage&) {};
+ QPID_BROKER_EXTERN void acquired(const Message&) {};
+ QPID_BROKER_EXTERN void requeued(const Message&) {};
/** for clustering: */
QPID_BROKER_EXTERN void getState(qpid::framing::FieldTable&) const;
@@ -106,14 +108,14 @@ class Broker;
void decode(framing::Buffer& buffer);
uint32_t encodedSize() const;
- static QPID_BROKER_EXTERN void observe(Queue& queue, const qpid::framing::FieldTable& settings);
+ static QPID_BROKER_EXTERN void observe(Queue& queue, const QueueSettings& settings);
static QPID_BROKER_EXTERN void setDefaults(uint64_t defaultMaxSize, uint defaultFlowStopRatio, uint defaultFlowResumeRatio);
friend QPID_BROKER_EXTERN std::ostream& operator<<(std::ostream&, const QueueFlowLimit&);
protected:
// msgs waiting for flow to become available.
- std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> > index;
+ std::map<framing::SequenceNumber, Message > index;
mutable qpid::sys::Mutex indexLock;
_qmfBroker::Queue *queueMgmtObj;
@@ -123,7 +125,7 @@ class Broker;
QPID_BROKER_EXTERN QueueFlowLimit(Queue *queue,
uint32_t flowStopCount, uint32_t flowResumeCount,
uint64_t flowStopSize, uint64_t flowResumeSize);
- static QPID_BROKER_EXTERN QueueFlowLimit *createLimit(Queue *queue, const qpid::framing::FieldTable& settings);
+ static QPID_BROKER_EXTERN QueueFlowLimit *createLimit(Queue *queue, const QueueSettings& settings);
};
}}
diff --git a/cpp/src/qpid/broker/QueueObserver.h b/cpp/src/qpid/broker/QueueObserver.h
index b58becd2ae..29e867253e 100644
--- a/cpp/src/qpid/broker/QueueObserver.h
+++ b/cpp/src/qpid/broker/QueueObserver.h
@@ -24,8 +24,8 @@
namespace qpid {
namespace broker {
-struct QueuedMessage;
class Consumer;
+class Message;
/**
* Interface for notifying classes who want to act as 'observers' of a queue of particular
@@ -63,10 +63,10 @@ class QueueObserver
virtual ~QueueObserver() {}
// note: the Queue will hold the messageLock while calling these methods!
- virtual void enqueued(const QueuedMessage&) = 0;
- virtual void dequeued(const QueuedMessage&) = 0;
- virtual void acquired(const QueuedMessage&) = 0;
- virtual void requeued(const QueuedMessage&) = 0;
+ virtual void enqueued(const Message&) = 0;
+ virtual void dequeued(const Message&) = 0;
+ virtual void acquired(const Message&) = 0;
+ virtual void requeued(const Message&) = 0;
virtual void consumerAdded( const Consumer& ) {};
virtual void consumerRemoved( const Consumer& ) {};
private:
diff --git a/cpp/src/qpid/broker/QueuePolicy.cpp b/cpp/src/qpid/broker/QueuePolicy.cpp
deleted file mode 100644
index 3978420f4e..0000000000
--- a/cpp/src/qpid/broker/QueuePolicy.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/broker/QueuePolicy.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/PriorityQueue.h"
-#include "qpid/Exception.h"
-#include "qpid/framing/FieldValue.h"
-#include "qpid/framing/reply_exceptions.h"
-#include "qpid/log/Statement.h"
-#include <sstream>
-
-using namespace qpid::broker;
-using namespace qpid::framing;
-
-QueuePolicy::QueuePolicy(const std::string& _name, uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
- maxCount(_maxCount), maxSize(_maxSize), type(_type), count(0), size(0), policyExceeded(false), queue(0), name(_name) {
- QPID_LOG(info, "Queue \"" << name << "\": Policy created: type=" << type << "; maxCount=" << maxCount << "; maxSize=" << maxSize);
-}
-
-void QueuePolicy::enqueued(uint64_t _size)
-{
- if (maxCount) ++count;
- if (maxSize) size += _size;
-}
-
-void QueuePolicy::dequeued(uint64_t _size)
-{
- if (maxCount) {
- if (count > 0) {
- --count;
- } else {
- throw Exception(QPID_MSG("Attempted count underflow on dequeue(" << _size << "): " << *this));
- }
- }
- if (maxSize) {
- if (_size > size) {
- throw Exception(QPID_MSG("Attempted size underflow on dequeue(" << _size << "): " << *this));
- } else {
- size -= _size;
- }
- }
-}
-
-bool QueuePolicy::checkLimit(boost::intrusive_ptr<Message> m)
-{
- bool sizeExceeded = maxSize && (size + m->contentSize()) > maxSize;
- bool countExceeded = maxCount && (count + 1) > maxCount;
- bool exceeded = sizeExceeded || countExceeded;
- if (exceeded) {
- if (!policyExceeded) {
- policyExceeded = true;
- if (sizeExceeded) QPID_LOG(info, "Queue cumulative message size exceeded policy for " << name);
- if (countExceeded) QPID_LOG(info, "Queue message count exceeded policy for " << name);
- }
- } else {
- if (policyExceeded) {
- policyExceeded = false;
- QPID_LOG(info, "Queue cumulative message size and message count within policy for " << name);
- }
- }
- return !exceeded;
-}
-
-void QueuePolicy::tryEnqueue(boost::intrusive_ptr<Message> m)
-{
- if (checkLimit(m)) {
- enqueued(m->contentSize());
- } else {
- throw ResourceLimitExceededException(QPID_MSG("Policy exceeded on " << name << ", policy: " << *this));
- }
-}
-
-void QueuePolicy::recoverEnqueued(boost::intrusive_ptr<Message> m)
-{
- tryEnqueue(m);
-}
-
-void QueuePolicy::enqueueAborted(boost::intrusive_ptr<Message> m)
-{
- dequeued(m->contentSize());
-}
-
-void QueuePolicy::enqueued(const QueuedMessage&) {}
-
-void QueuePolicy::dequeued(const QueuedMessage& m)
-{
- dequeued(m.payload->contentSize());
-}
-
-bool QueuePolicy::isEnqueued(const QueuedMessage&)
-{
- return true;
-}
-
-void QueuePolicy::update(FieldTable& settings)
-{
- if (maxCount) settings.setInt(maxCountKey, maxCount);
- if (maxSize) settings.setInt(maxSizeKey, maxSize);
- settings.setString(typeKey, type);
-}
-
-template <typename T>
-T getCapacity(const FieldTable& settings, const std::string& key, T defaultValue)
-{
- FieldTable::ValuePtr v = settings.get(key);
-
- T result = 0;
-
- if (!v) return defaultValue;
- if (v->getType() == 0x23) {
- QPID_LOG(debug, "Value for " << key << " specified as float: " << v->get<float>());
- } else if (v->getType() == 0x33) {
- QPID_LOG(debug, "Value for " << key << " specified as double: " << v->get<double>());
- } else if (v->convertsTo<T>()) {
- result = v->get<T>();
- QPID_LOG(debug, "Got integer value for " << key << ": " << result);
- if (result >= 0) return result;
- } else if (v->convertsTo<std::string>()) {
- std::string s(v->get<std::string>());
- QPID_LOG(debug, "Got string value for " << key << ": " << s);
- std::istringstream convert(s);
- if (convert >> result && result >= 0 && convert.eof()) return result;
- }
-
- throw IllegalArgumentException(QPID_MSG("Cannot convert " << key << " to unsigned integer: " << *v));
-}
-
-std::string QueuePolicy::getType(const FieldTable& settings)
-{
- FieldTable::ValuePtr v = settings.get(typeKey);
- if (v && v->convertsTo<std::string>()) {
- std::string t = v->get<std::string>();
- std::transform(t.begin(), t.end(), t.begin(), tolower);
- if (t == REJECT || t == FLOW_TO_DISK || t == RING || t == RING_STRICT) return t;
- }
- return REJECT;
-}
-
-void QueuePolicy::setDefaultMaxSize(uint64_t s)
-{
- defaultMaxSize = s;
-}
-
-void QueuePolicy::getPendingDequeues(Messages&) {}
-
-
-
-
-void QueuePolicy::encode(Buffer& buffer) const
-{
- buffer.putLong(maxCount);
- buffer.putLongLong(maxSize);
- buffer.putLong(count);
- buffer.putLongLong(size);
-}
-
-void QueuePolicy::decode ( Buffer& buffer )
-{
- maxCount = buffer.getLong();
- maxSize = buffer.getLongLong();
- count = buffer.getLong();
- size = buffer.getLongLong();
-}
-
-
-uint32_t QueuePolicy::encodedSize() const {
- return sizeof(uint32_t) + // maxCount
- sizeof(uint64_t) + // maxSize
- sizeof(uint32_t) + // count
- sizeof(uint64_t); // size
-}
-
-
-
-const std::string QueuePolicy::maxCountKey("qpid.max_count");
-const std::string QueuePolicy::maxSizeKey("qpid.max_size");
-const std::string QueuePolicy::typeKey("qpid.policy_type");
-const std::string QueuePolicy::REJECT("reject");
-const std::string QueuePolicy::FLOW_TO_DISK("flow_to_disk");
-const std::string QueuePolicy::RING("ring");
-const std::string QueuePolicy::RING_STRICT("ring_strict");
-uint64_t QueuePolicy::defaultMaxSize(0);
-
-FlowToDiskPolicy::FlowToDiskPolicy(const std::string& _name, uint32_t _maxCount, uint64_t _maxSize) :
- QueuePolicy(_name, _maxCount, _maxSize, FLOW_TO_DISK) {}
-
-bool FlowToDiskPolicy::checkLimit(boost::intrusive_ptr<Message> m)
-{
- if (!QueuePolicy::checkLimit(m)) {
- m->requestContentRelease();
- if (queue)
- queue->countFlowedToDisk(m->contentSize());
- }
- return true;
-}
-
-RingQueuePolicy::RingQueuePolicy(const std::string& _name,
- uint32_t _maxCount, uint64_t _maxSize, const std::string& _type) :
- QueuePolicy(_name, _maxCount, _maxSize, _type), strict(_type == RING_STRICT) {}
-
-bool before(const QueuedMessage& a, const QueuedMessage& b)
-{
- int priorityA = PriorityQueue::getPriority(a);
- int priorityB = PriorityQueue::getPriority(b);
- if (priorityA == priorityB) return a.position < b.position;
- else return priorityA < priorityB;
-}
-
-void RingQueuePolicy::enqueued(const QueuedMessage& m)
-{
- //need to insert in correct location based on position
- queue.insert(lower_bound(queue.begin(), queue.end(), m, before), m);
-}
-
-void RingQueuePolicy::dequeued(const QueuedMessage& m)
-{
- //find and remove m from queue
- if (find(m, pendingDequeues, true) || find(m, queue, true)) {
- //now update count and size
- QueuePolicy::dequeued(m);
- }
-}
-
-bool RingQueuePolicy::isEnqueued(const QueuedMessage& m)
-{
- //for non-strict ring policy, a message can be replaced (and
- //therefore dequeued) before it is accepted or released by
- //subscriber; need to detect this
- return find(m, pendingDequeues, false) || find(m, queue, false);
-}
-
-bool RingQueuePolicy::checkLimit(boost::intrusive_ptr<Message> m)
-{
-
- // If the message is bigger than the queue size, give up
- if (getMaxSize() && m->contentSize() > getMaxSize()) {
- QPID_LOG(debug, "Message too large for ring queue " << name
- << " [" << *this << "] "
- << ": message size = " << m->contentSize() << " bytes"
- << ": max queue size = " << getMaxSize() << " bytes");
- return false;
- }
-
- // if within limits, ok to accept
- if (QueuePolicy::checkLimit(m)) return true;
-
- // At this point, we've exceeded maxSize, maxCount, or both.
- //
- // If we've exceeded maxCount, we've exceeded it by 1, so
- // replacing the first message is sufficient. If we've exceeded
- // maxSize, we need to pop enough messages to get the space we
- // need.
-
- unsigned int haveSpace = getMaxSize() - getCurrentQueueSize();
-
- do {
- QueuedMessage oldest = queue.front();
- if (oldest.queue->acquireMessageAt(oldest.position, oldest) || !strict) {
- queue.pop_front();
- pendingDequeues.push_back(oldest);
- QPID_LOG(debug, "Ring policy triggered in " << name
- << ": removed message " << oldest.position << " to make way for new message");
-
- haveSpace += oldest.payload->contentSize();
-
- } else {
- //in strict mode, if oldest message has been delivered (hence
- //cannot be acquired) but not yet acked, it should not be
- //removed and the attempted enqueue should fail
- QPID_LOG(debug, "Ring policy could not be triggered in " << name
- << ": oldest message (seq-no=" << oldest.position << ") has been delivered but not yet acknowledged or requeued");
- return false;
- }
- } while (getMaxSize() && haveSpace < m->contentSize());
-
-
- return true;
-}
-
-void RingQueuePolicy::getPendingDequeues(Messages& result)
-{
- result = pendingDequeues;
-}
-
-bool RingQueuePolicy::find(const QueuedMessage& m, Messages& q, bool remove)
-{
- for (Messages::iterator i = q.begin(); i != q.end(); i++) {
- if (i->payload == m.payload) {
- if (remove) q.erase(i);
- return true;
- }
- }
- return false;
-}
-
-std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type)
-{
- return createQueuePolicy("<unspecified>", maxCount, maxSize, type);
-}
-
-std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const qpid::framing::FieldTable& settings)
-{
- return createQueuePolicy("<unspecified>", settings);
-}
-
-std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings)
-{
- uint32_t maxCount = getCapacity<int32_t>(settings, maxCountKey, 0);
- uint64_t maxSize = getCapacity<int64_t>(settings, maxSizeKey, defaultMaxSize);
- if (maxCount || maxSize) {
- return createQueuePolicy(name, maxCount, maxSize, getType(settings));
- } else {
- return std::auto_ptr<QueuePolicy>();
- }
-}
-
-std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name,
- uint32_t maxCount, uint64_t maxSize, const std::string& type)
-{
- if (type == RING || type == RING_STRICT) {
- return std::auto_ptr<QueuePolicy>(new RingQueuePolicy(name, maxCount, maxSize, type));
- } else if (type == FLOW_TO_DISK) {
- return std::auto_ptr<QueuePolicy>(new FlowToDiskPolicy(name, maxCount, maxSize));
- } else {
- return std::auto_ptr<QueuePolicy>(new QueuePolicy(name, maxCount, maxSize, type));
- }
-
-}
-
-namespace qpid {
- namespace broker {
-
-std::ostream& operator<<(std::ostream& out, const QueuePolicy& p)
-{
- if (p.maxSize) out << "size: max=" << p.maxSize << ", current=" << p.size;
- else out << "size: unlimited";
- out << "; ";
- if (p.maxCount) out << "count: max=" << p.maxCount << ", current=" << p.count;
- else out << "count: unlimited";
- out << "; type=" << p.type;
- return out;
-}
-
- }
-}
-
diff --git a/cpp/src/qpid/broker/QueuePolicy.h b/cpp/src/qpid/broker/QueuePolicy.h
deleted file mode 100644
index f23b709f18..0000000000
--- a/cpp/src/qpid/broker/QueuePolicy.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _QueuePolicy_
-#define _QueuePolicy_
-
-#include <deque>
-#include <iostream>
-#include <memory>
-#include "qpid/broker/BrokerImportExport.h"
-#include "qpid/broker/QueuedMessage.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/sys/AtomicValue.h"
-#include "qpid/sys/Mutex.h"
-
-namespace qpid {
-namespace broker {
-
-class Queue;
-
-class QueuePolicy
-{
- static uint64_t defaultMaxSize;
-
- uint32_t maxCount;
- uint64_t maxSize;
- const std::string type;
- uint32_t count;
- uint64_t size;
- bool policyExceeded;
-
- protected:
- Queue* queue;
- uint64_t getCurrentQueueSize() const { return size; }
-
- public:
- typedef std::deque<QueuedMessage> Messages;
- static QPID_BROKER_EXTERN const std::string maxCountKey;
- static QPID_BROKER_EXTERN const std::string maxSizeKey;
- static QPID_BROKER_EXTERN const std::string typeKey;
- static QPID_BROKER_EXTERN const std::string REJECT;
- static QPID_BROKER_EXTERN const std::string FLOW_TO_DISK;
- static QPID_BROKER_EXTERN const std::string RING;
- static QPID_BROKER_EXTERN const std::string RING_STRICT;
-
- virtual ~QueuePolicy() {}
- QPID_BROKER_EXTERN void tryEnqueue(boost::intrusive_ptr<Message> msg);
- QPID_BROKER_EXTERN void recoverEnqueued(boost::intrusive_ptr<Message> msg);
- QPID_BROKER_EXTERN void enqueueAborted(boost::intrusive_ptr<Message> msg);
- virtual void enqueued(const QueuedMessage&);
- virtual void dequeued(const QueuedMessage&);
- virtual bool isEnqueued(const QueuedMessage&);
- QPID_BROKER_EXTERN void update(qpid::framing::FieldTable& settings);
- uint32_t getMaxCount() const { return maxCount; }
- uint64_t getMaxSize() const { return maxSize; }
- void encode(framing::Buffer& buffer) const;
- void decode ( framing::Buffer& buffer );
- uint32_t encodedSize() const;
- virtual void getPendingDequeues(Messages& result);
- std::string getType() const { return type; }
- void setQueue(Queue* q) { queue = q; }
-
- static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings);
- static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
- static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const qpid::framing::FieldTable& settings);
- static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
- static std::string getType(const qpid::framing::FieldTable& settings);
- static void setDefaultMaxSize(uint64_t);
- friend QPID_BROKER_EXTERN std::ostream& operator<<(std::ostream&,
- const QueuePolicy&);
- protected:
- const std::string name;
-
- QueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT);
-
- virtual bool checkLimit(boost::intrusive_ptr<Message> msg);
- void enqueued(uint64_t size);
- void dequeued(uint64_t size);
-};
-
-
-class FlowToDiskPolicy : public QueuePolicy
-{
- public:
- FlowToDiskPolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize);
- bool checkLimit(boost::intrusive_ptr<Message> msg);
-};
-
-class RingQueuePolicy : public QueuePolicy
-{
- public:
- RingQueuePolicy(const std::string& name, uint32_t maxCount, uint64_t maxSize, const std::string& type = RING);
- void enqueued(const QueuedMessage&);
- void dequeued(const QueuedMessage&);
- bool isEnqueued(const QueuedMessage&);
- bool checkLimit(boost::intrusive_ptr<Message> msg);
- void getPendingDequeues(Messages& result);
- private:
- Messages pendingDequeues;
- Messages queue;
- const bool strict;
-
- bool find(const QueuedMessage&, Messages&, bool remove);
-};
-
-}}
-
-
-#endif
diff --git a/cpp/src/qpid/broker/QueueRegistry.cpp b/cpp/src/qpid/broker/QueueRegistry.cpp
index 1401356444..3521e08325 100644
--- a/cpp/src/qpid/broker/QueueRegistry.cpp
+++ b/cpp/src/qpid/broker/QueueRegistry.cpp
@@ -21,7 +21,6 @@
#include "qpid/broker/Broker.h"
#include "qpid/broker/Queue.h"
#include "qpid/broker/QueueRegistry.h"
-#include "qpid/broker/QueueEvents.h"
#include "qpid/broker/Exchange.h"
#include "qpid/log/Statement.h"
#include "qpid/framing/reply_exceptions.h"
@@ -32,50 +31,43 @@ using namespace qpid::broker;
using namespace qpid::sys;
using std::string;
-QueueRegistry::QueueRegistry(Broker* b) :
- counter(1), store(0), events(0), parent(0), lastNode(false), broker(b) {}
+QueueRegistry::QueueRegistry(Broker* b)
+{
+ setBroker(b);
+}
QueueRegistry::~QueueRegistry(){}
std::pair<Queue::shared_ptr, bool>
-QueueRegistry::declare(const string& declareName, bool durable,
- bool autoDelete, const OwnershipToken* owner,
+QueueRegistry::declare(const string& name, const QueueSettings& settings,
boost::shared_ptr<Exchange> alternate,
- const qpid::framing::FieldTable& arguments,
bool recovering/*true if this declare is a
result of recovering queue
- definition from persistente
+ definition from persistent
record*/)
{
- Queue::shared_ptr queue;
std::pair<Queue::shared_ptr, bool> result;
{
RWlock::ScopedWlock locker(lock);
- string name = declareName.empty() ? generateName() : declareName;
- assert(!name.empty());
QueueMap::iterator i = queues.find(name);
-
if (i == queues.end()) {
- queue.reset(new Queue(name, autoDelete, durable ? store : 0, owner, parent, broker));
+ Queue::shared_ptr queue = create(name, settings);
+ //Move this to factory also?
if (alternate) {
queue->setAlternateExchange(alternate);//need to do this *before* create
alternate->incAlternateUsers();
}
if (!recovering) {
- //apply settings & create persistent record if required
- queue->create(arguments);
- } else {
- //i.e. recovering a queue for which we already have a persistent record
- queue->configure(arguments);
+ //create persistent record if required
+ queue->create();
}
queues[name] = queue;
- if (lastNode) queue->setLastNodeFailure();
result = std::pair<Queue::shared_ptr, bool>(queue, true);
} else {
result = std::pair<Queue::shared_ptr, bool>(i->second, false);
}
}
- if (broker && queue) broker->getConfigurationObservers().queueCreate(queue);
+ if (getBroker() && result.second) getBroker()->getConfigurationObservers().queueCreate(result.first);
return result;
}
@@ -85,11 +77,11 @@ void QueueRegistry::destroy(const string& name) {
qpid::sys::RWlock::ScopedWlock locker(lock);
QueueMap::iterator i = queues.find(name);
if (i != queues.end()) {
- Queue::shared_ptr q = i->second;
+ q = i->second;
queues.erase(i);
}
}
- if (broker && q) broker->getConfigurationObservers().queueDestroy(q);
+ if (getBroker() && q) getBroker()->getConfigurationObservers().queueDestroy(q);
}
Queue::shared_ptr QueueRegistry::find(const string& name){
@@ -108,36 +100,17 @@ Queue::shared_ptr QueueRegistry::get(const string& name) {
return q;
}
-string QueueRegistry::generateName(){
- string name;
- do {
- std::stringstream ss;
- ss << "tmp_" << counter++;
- name = ss.str();
- // Thread safety: Private function, only called with lock held
- // so this is OK.
- } while(queues.find(name) != queues.end());
- return name;
-}
-
void QueueRegistry::setStore (MessageStore* _store)
{
- store = _store;
+ QueueFactory::setStore(_store);
}
-MessageStore* QueueRegistry::getStore() const {
- return store;
+MessageStore* QueueRegistry::getStore() const
+{
+ return QueueFactory::getStore();
}
-void QueueRegistry::updateQueueClusterState(bool _lastNode)
+void QueueRegistry::setParent(qpid::management::Manageable* _parent)
{
- RWlock::ScopedRlock locker(lock);
- for (QueueMap::iterator i = queues.begin(); i != queues.end(); i++) {
- if (_lastNode){
- i->second->setLastNodeFailure();
- } else {
- i->second->clearLastNodeFailure();
- }
- }
- lastNode = _lastNode;
+ QueueFactory::setParent(_parent);
}
diff --git a/cpp/src/qpid/broker/QueueRegistry.h b/cpp/src/qpid/broker/QueueRegistry.h
index a354513c5f..7fce90c679 100644
--- a/cpp/src/qpid/broker/QueueRegistry.h
+++ b/cpp/src/qpid/broker/QueueRegistry.h
@@ -22,8 +22,8 @@
#define _QueueRegistry_
#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/QueueFactory.h"
#include "qpid/sys/Mutex.h"
-#include "qpid/management/Manageable.h"
#include "qpid/framing/FieldTable.h"
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
@@ -34,11 +34,8 @@ namespace qpid {
namespace broker {
class Queue;
-class QueueEvents;
class Exchange;
class OwnershipToken;
-class Broker;
-class MessageStore;
/**
* A registry of queues indexed by queue name.
@@ -47,7 +44,7 @@ class MessageStore;
* are deleted when and only when they are no longer in use.
*
*/
-class QueueRegistry {
+class QueueRegistry : QueueFactory {
public:
QPID_BROKER_EXTERN QueueRegistry(Broker* b = 0);
QPID_BROKER_EXTERN ~QueueRegistry();
@@ -60,11 +57,8 @@ class QueueRegistry {
*/
QPID_BROKER_EXTERN std::pair<boost::shared_ptr<Queue>, bool> declare(
const std::string& name,
- bool durable = false,
- bool autodelete = false,
- const OwnershipToken* owner = 0,
+ const QueueSettings& settings,
boost::shared_ptr<Exchange> alternateExchange = boost::shared_ptr<Exchange>(),
- const qpid::framing::FieldTable& args = framing::FieldTable(),
bool recovering = false);
/**
@@ -101,11 +95,6 @@ class QueueRegistry {
QPID_BROKER_EXTERN boost::shared_ptr<Queue> get(const std::string& name);
/**
- * Generate unique queue name.
- */
- std::string generateName();
-
- /**
* Set the store to use. May only be called once.
*/
void setStore (MessageStore*);
@@ -118,7 +107,7 @@ class QueueRegistry {
/**
* Register the manageable parent for declared queues
*/
- void setParent (management::Manageable* _parent) { parent = _parent; }
+ void setParent (management::Manageable*);
/** Call f for each queue in the registry. */
template <class F> void eachQueue(F f) const {
@@ -127,22 +116,10 @@ class QueueRegistry {
f(i->second);
}
- /**
- * Change queue mode when cluster size drops to 1 node, expands again
- * in practice allows flow queue to disk when last name to be exectuted
- */
- void updateQueueClusterState(bool lastNode);
-
private:
typedef std::map<std::string, boost::shared_ptr<Queue> > QueueMap;
QueueMap queues;
mutable qpid::sys::RWlock lock;
- int counter;
- MessageStore* store;
- QueueEvents* events;
- management::Manageable* parent;
- bool lastNode; //used to set mode on queue declare
- Broker* broker;
};
diff --git a/cpp/src/qpid/broker/QueueSettings.cpp b/cpp/src/qpid/broker/QueueSettings.cpp
new file mode 100644
index 0000000000..91616636f1
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueSettings.cpp
@@ -0,0 +1,228 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "QueueSettings.h"
+#include "QueueFlowLimit.h"
+#include "MessageGroupManager.h"
+#include "qpid/types/Variant.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
+#include "qpid/amqp_0_10/Codecs.h"
+
+
+namespace qpid {
+namespace broker {
+
+namespace {
+const std::string MAX_COUNT("qpid.max_count");
+const std::string MAX_SIZE("qpid.max_size");
+const std::string POLICY_TYPE("qpid.policy_type");
+const std::string POLICY_TYPE_REJECT("reject");
+const std::string POLICY_TYPE_RING("ring");
+const std::string NO_LOCAL("no-local");
+const std::string TRACE_ID("qpid.trace.id");
+const std::string TRACE_EXCLUDES("qpid.trace.exclude");
+const std::string LVQ_KEY("qpid.last_value_queue_key");
+const std::string AUTO_DELETE_TIMEOUT("qpid.auto_delete_timeout");
+const std::string ALERT_REPEAT_GAP("qpid.alert_repeat_gap");
+const std::string ALERT_COUNT("qpid.alert_count");
+const std::string ALERT_SIZE("qpid.alert_size");
+const std::string PRIORITIES("qpid.priorities");
+const std::string FAIRSHARE("qpid.fairshare");
+const std::string FAIRSHARE_ALIAS("x-qpid-fairshare");
+
+const std::string LVQ_LEGACY("qpid.last_value_queue");
+const std::string LVQ_LEGACY_KEY("qpid.LVQ_key");
+const std::string LVQ_LEGACY_NOBROWSE("qpid.last_value_queue_no_browse");
+
+
+bool handleFairshareSetting(const std::string& basename, const std::string& key, const qpid::types::Variant& value, QueueSettings& settings)
+{
+ if (key.find(basename) == 0) {
+ qpid::types::Variant index(key.substr(basename.size()+1));
+ settings.fairshare[index] = value;
+ return true;
+ } else {
+ return false;
+ }
+}
+bool isFairshareSetting(const std::string& key, const qpid::types::Variant& value, QueueSettings& settings)
+{
+ return handleFairshareSetting(FAIRSHARE, key, value, settings) || handleFairshareSetting(FAIRSHARE_ALIAS, key, value, settings);
+}
+}
+
+const QueueSettings::Aliases QueueSettings::aliases;
+
+QueueSettings::QueueSettings(bool d, bool a) :
+ durable(d),
+ autodelete(a),
+ priorities(0),
+ defaultFairshare(0),
+ shareGroups(false),
+ addTimestamp(false),
+ dropMessagesAtLimit(false),
+ noLocal(false),
+ autoDeleteDelay(0),
+ alertRepeatInterval(60)
+{}
+
+bool QueueSettings::handle(const std::string& key, const qpid::types::Variant& value)
+{
+ if (key == MAX_COUNT && value.asUint32() > 0) {
+ maxDepth.setCount(value);
+ return true;
+ } else if (key == MAX_SIZE && value.asUint64() > 0) {
+ maxDepth.setSize(value);
+ return true;
+ } else if (key == POLICY_TYPE) {
+ if (value.getString() == POLICY_TYPE_RING) {
+ dropMessagesAtLimit = true;
+ return true;
+ } else if (value.getString() == POLICY_TYPE_REJECT) {
+ //do nothing, thats the default
+ return true;
+ } else {
+ QPID_LOG(warning, "Unrecognised policy option: " << value);
+ return false;
+ }
+ } else if (key == NO_LOCAL) {
+ noLocal = value;
+ return true;
+ } else if (key == TRACE_ID) {
+ traceId = value.asString();
+ return true;
+ } else if (key == TRACE_EXCLUDES) {
+ traceExcludes = value.asString();
+ return true;
+ } else if (key == PRIORITIES) {
+ priorities = value;
+ return true;
+ } else if (key == FAIRSHARE) {
+ defaultFairshare = value;
+ return true;
+ } else if (isFairshareSetting(key, value, *this)) {
+ return true;
+ } else if (key == MessageGroupManager::qpidMessageGroupKey) {
+ groupKey = value.asString();
+ return true;
+ } else if (key == MessageGroupManager::qpidSharedGroup) {
+ shareGroups = value;
+ return true;
+ } else if (key == MessageGroupManager::qpidMessageGroupTimestamp) {
+ addTimestamp = value;
+ return true;
+ } else if (key == LVQ_KEY) {
+ lvqKey = value.asString();
+ return true;
+ } else if (key == LVQ_LEGACY) {
+ if (lvqKey.empty()) lvqKey = LVQ_LEGACY_KEY;
+ return true;
+ } else if (key == LVQ_LEGACY_NOBROWSE) {
+ QPID_LOG(warning, "Ignoring 'no-browse' directive for LVQ; it is no longer necessary");
+ if (lvqKey.empty()) lvqKey = LVQ_LEGACY_KEY;
+ return true;
+ } else if (key == AUTO_DELETE_TIMEOUT) {
+ autoDeleteDelay = value;
+ return true;
+ } else if (key == QueueFlowLimit::flowStopCountKey) {
+ flowStop.setCount(value);
+ return true;
+ } else if (key == QueueFlowLimit::flowResumeCountKey) {
+ flowResume.setCount(value);
+ return true;
+ } else if (key == QueueFlowLimit::flowStopSizeKey) {
+ flowStop.setSize(value);
+ return true;
+ } else if (key == QueueFlowLimit::flowResumeSizeKey) {
+ flowResume.setSize(value);
+ return true;
+ } else if (key == ALERT_REPEAT_GAP) {
+ alertRepeatInterval = value;
+ return true;
+ } else if (key == ALERT_COUNT) {
+ alertThreshold.setCount(value);
+ return true;
+ } else if (key == ALERT_SIZE) {
+ alertThreshold.setSize(value);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void QueueSettings::validate() const
+{
+ if (lvqKey.size() && priorities > 0)
+ throw qpid::framing::InvalidArgumentException(QPID_MSG("Cannot specify " << LVQ_KEY << " and " << PRIORITIES << " for the same queue"));
+ if ((fairshare.size() || defaultFairshare) && priorities == 0)
+ throw qpid::framing::InvalidArgumentException(QPID_MSG("Cannot specify fairshare settings when queue is not enabled for priorities"));
+ if (fairshare.size() > priorities)
+ throw qpid::framing::InvalidArgumentException(QPID_MSG("Cannot have fairshare set for priority levels greater than " << priorities));
+ if (groupKey.size() && lvqKey.size())
+ throw qpid::framing::InvalidArgumentException(QPID_MSG("Cannot specify " << LVQ_KEY << " and " << MessageGroupManager::qpidMessageGroupKey << " for the same queue"));
+ if (groupKey.size() && priorities)
+ throw qpid::framing::InvalidArgumentException(QPID_MSG("Cannot specify " << PRIORITIES << " and " << MessageGroupManager::qpidMessageGroupKey << " for the same queue"));
+ if (shareGroups && groupKey.empty()) {
+ throw qpid::framing::InvalidArgumentException(QPID_MSG("Can only specify " << MessageGroupManager::qpidSharedGroup
+ << " if " << MessageGroupManager::qpidMessageGroupKey << " is set"));
+ }
+ if (addTimestamp && groupKey.empty()) {
+ throw qpid::framing::InvalidArgumentException(QPID_MSG("Can only specify " << MessageGroupManager::qpidMessageGroupTimestamp
+ << " if " << MessageGroupManager::qpidMessageGroupKey << " is set"));
+ }
+
+ // @todo: remove once "sticky" consumers are supported - see QPID-3347
+ if (!shareGroups && groupKey.size()) {
+ throw qpid::framing::InvalidArgumentException(QPID_MSG("Only shared groups are supported at present; " << MessageGroupManager::qpidSharedGroup
+ << " is required if " << MessageGroupManager::qpidMessageGroupKey << " is set"));
+ }
+}
+
+void QueueSettings::populate(const std::map<std::string, qpid::types::Variant>& inputs, std::map<std::string, qpid::types::Variant>& unused)
+{
+ original = inputs;
+ for (qpid::types::Variant::Map::const_iterator i = inputs.begin(); i != inputs.end(); ++i) {
+ Aliases::const_iterator a = aliases.find(i->first);
+ if (!handle((a != aliases.end() ? a->second : i->first), i->second)) unused.insert(*i);
+ }
+}
+void QueueSettings::populate(const qpid::framing::FieldTable& inputs, qpid::framing::FieldTable& unused)
+{
+ qpid::types::Variant::Map o;
+ qpid::amqp_0_10::translate(inputs, original);
+ populate(original, o);
+ qpid::amqp_0_10::translate(o, unused);
+}
+std::map<std::string, qpid::types::Variant> QueueSettings::asMap() const
+{
+ return original;
+}
+
+QueueSettings::Aliases::Aliases()
+{
+ insert(value_type("x-qpid-priorities", "qpid.priorities"));
+ insert(value_type("x-qpid-fairshare", "qpid.fairshare"));
+ insert(value_type("x-qpid-minimum-alert-repeat-gap", "qpid.alert_repeat_gap"));
+ insert(value_type("x-qpid-maximum-message-count", "qpid.alert_count"));
+ insert(value_type("x-qpid-maximum-message-size", "qpid.alert_size"));
+}
+
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/QueueSettings.h b/cpp/src/qpid/broker/QueueSettings.h
new file mode 100644
index 0000000000..2443624615
--- /dev/null
+++ b/cpp/src/qpid/broker/QueueSettings.h
@@ -0,0 +1,92 @@
+#ifndef QPID_BROKER_QUEUESETTINGS_H
+#define QPID_BROKER_QUEUESETTINGS_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/broker/QueueDepth.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/framing/FieldTable.h"
+#include <string>
+#include <map>
+
+namespace qpid {
+namespace types {
+class Variant;
+}
+namespace broker {
+
+/**
+ * Defines the various queue configuration settings that can be specified
+ */
+struct QueueSettings
+{
+ QPID_BROKER_EXTERN QueueSettings(bool durable=false, bool autodelete=false);
+
+ bool durable;
+ bool autodelete;
+
+ //basic queue types:
+ std::string lvqKey;
+ uint32_t priorities;
+ uint32_t defaultFairshare;
+ std::map<uint32_t,uint32_t> fairshare;
+
+ //message groups:
+ std::string groupKey;
+ bool shareGroups;
+ bool addTimestamp;//not actually used; always on at present?
+
+ QueueDepth maxDepth;
+ bool dropMessagesAtLimit;//aka ring queue policy
+
+ bool noLocal;
+ std::string traceId;
+ std::string traceExcludes;
+ uint64_t autoDeleteDelay;//queueTtl?
+
+ //flow control:
+ QueueDepth flowStop;
+ QueueDepth flowResume;
+
+ //threshold events:
+ QueueDepth alertThreshold;
+ int64_t alertRepeatInterval;
+
+ //yuck, yuck
+ qpid::framing::FieldTable storeSettings;
+ std::map<std::string, qpid::types::Variant> original;
+
+ bool handle(const std::string& key, const qpid::types::Variant& value);
+ void validate() const;
+ QPID_BROKER_EXTERN void populate(const std::map<std::string, qpid::types::Variant>& inputs, std::map<std::string, qpid::types::Variant>& unused);
+ QPID_BROKER_EXTERN void populate(const qpid::framing::FieldTable& inputs, qpid::framing::FieldTable& unused);
+ std::map<std::string, qpid::types::Variant> asMap() const;
+
+ struct Aliases : std::map<std::string, std::string>
+ {
+ Aliases();
+ };
+ static const Aliases aliases;
+};
+}} // namespace qpid::broker
+
+#endif /*!QPID_BROKER_QUEUESETTINGS_H*/
diff --git a/cpp/src/qpid/broker/QueuedMessage.h b/cpp/src/qpid/broker/QueuedMessage.h
index 9d008193a0..c80fff900a 100644
--- a/cpp/src/qpid/broker/QueuedMessage.h
+++ b/cpp/src/qpid/broker/QueuedMessage.h
@@ -22,8 +22,8 @@
#define _QueuedMessage_
#include "qpid/broker/Message.h"
-#include "BrokerImportExport.h"
-#include <iosfwd>
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/broker/BrokerImportExport.h"
namespace qpid {
namespace broker {
@@ -32,20 +32,19 @@ class Queue;
struct QueuedMessage
{
- boost::intrusive_ptr<Message> payload;
+ Message message;
framing::SequenceNumber position;
- typedef enum { AVAILABLE, ACQUIRED, DELETED, REMOVED } Status;
- Status status;
+ enum {AVAILABLE, ACQUIRED, DELETED, REMOVED} status;
Queue* queue;
- QueuedMessage(Queue* q=0,
- boost::intrusive_ptr<Message> msg=0,
- framing::SequenceNumber sn=0,
- Status st=AVAILABLE
- ) : payload(msg), position(sn), status(st), queue(q) {}
+ QueuedMessage() : queue(0) {}
+ QueuedMessage(Queue* q, Message msg, framing::SequenceNumber sn) :
+ message(msg), position(sn), queue(q) {}
+ QueuedMessage(Queue* q) : queue(q) {}
};
-inline bool operator<(const QueuedMessage& a, const QueuedMessage& b) {
+inline bool operator<(const QueuedMessage& a, const QueuedMessage& b)
+{
return a.position < b.position;
}
diff --git a/cpp/src/qpid/broker/RecoveredDequeue.cpp b/cpp/src/qpid/broker/RecoveredDequeue.cpp
index cd6735328f..6e21a5bc21 100644
--- a/cpp/src/qpid/broker/RecoveredDequeue.cpp
+++ b/cpp/src/qpid/broker/RecoveredDequeue.cpp
@@ -22,10 +22,9 @@
#include "qpid/broker/Queue.h"
#include "qpid/broker/RecoveredDequeue.h"
-using boost::intrusive_ptr;
using namespace qpid::broker;
-RecoveredDequeue::RecoveredDequeue(Queue::shared_ptr _queue, intrusive_ptr<Message> _msg) : queue(_queue), msg(_msg)
+RecoveredDequeue::RecoveredDequeue(Queue::shared_ptr _queue, Message _msg) : queue(_queue), msg(_msg)
{
queue->recoverPrepared(msg);
}
@@ -38,11 +37,11 @@ bool RecoveredDequeue::prepare(TransactionContext*) throw()
void RecoveredDequeue::commit() throw()
{
- queue->enqueueAborted(msg);
+ queue->dequeueCommited(msg);
}
void RecoveredDequeue::rollback() throw()
{
- queue->process(msg);
+ queue->dequeueAborted(msg);
}
diff --git a/cpp/src/qpid/broker/RecoveredDequeue.h b/cpp/src/qpid/broker/RecoveredDequeue.h
index 66e66f1d5f..87f768eefd 100644
--- a/cpp/src/qpid/broker/RecoveredDequeue.h
+++ b/cpp/src/qpid/broker/RecoveredDequeue.h
@@ -26,8 +26,6 @@
#include "qpid/broker/MessageStore.h"
#include "qpid/broker/TxOp.h"
-#include <boost/intrusive_ptr.hpp>
-
#include <algorithm>
#include <functional>
#include <list>
@@ -36,18 +34,17 @@ namespace qpid {
namespace broker {
class RecoveredDequeue : public TxOp{
boost::shared_ptr<Queue> queue;
- boost::intrusive_ptr<Message> msg;
+ Message msg;
public:
- RecoveredDequeue(boost::shared_ptr<Queue> queue, boost::intrusive_ptr<Message> msg);
+ RecoveredDequeue(boost::shared_ptr<Queue> queue, Message msg);
virtual bool prepare(TransactionContext* ctxt) throw();
virtual void commit() throw();
virtual void rollback() throw();
virtual ~RecoveredDequeue(){}
- virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
boost::shared_ptr<Queue> getQueue() const { return queue; }
- boost::intrusive_ptr<Message> getMessage() const { return msg; }
+ Message getMessage() const { return msg; }
};
}
}
diff --git a/cpp/src/qpid/broker/RecoveredEnqueue.cpp b/cpp/src/qpid/broker/RecoveredEnqueue.cpp
index 6d2eaee6c4..296d5194c0 100644
--- a/cpp/src/qpid/broker/RecoveredEnqueue.cpp
+++ b/cpp/src/qpid/broker/RecoveredEnqueue.cpp
@@ -22,10 +22,9 @@
#include "qpid/broker/Queue.h"
#include "qpid/broker/RecoveredEnqueue.h"
-using boost::intrusive_ptr;
using namespace qpid::broker;
-RecoveredEnqueue::RecoveredEnqueue(Queue::shared_ptr _queue, intrusive_ptr<Message> _msg) : queue(_queue), msg(_msg)
+RecoveredEnqueue::RecoveredEnqueue(Queue::shared_ptr _queue, Message _msg) : queue(_queue), msg(_msg)
{
queue->recoverPrepared(msg);
}
@@ -36,7 +35,7 @@ bool RecoveredEnqueue::prepare(TransactionContext*) throw(){
}
void RecoveredEnqueue::commit() throw(){
- queue->process(msg);
+ queue->enqueueCommited(msg);
}
void RecoveredEnqueue::rollback() throw(){
diff --git a/cpp/src/qpid/broker/RecoveredEnqueue.h b/cpp/src/qpid/broker/RecoveredEnqueue.h
index 5f718001d5..d1f8e1106c 100644
--- a/cpp/src/qpid/broker/RecoveredEnqueue.h
+++ b/cpp/src/qpid/broker/RecoveredEnqueue.h
@@ -26,8 +26,6 @@
#include "qpid/broker/MessageStore.h"
#include "qpid/broker/TxOp.h"
-#include <boost/intrusive_ptr.hpp>
-
#include <algorithm>
#include <functional>
#include <list>
@@ -36,19 +34,17 @@ namespace qpid {
namespace broker {
class RecoveredEnqueue : public TxOp{
boost::shared_ptr<Queue> queue;
- boost::intrusive_ptr<Message> msg;
+ Message msg;
public:
- RecoveredEnqueue(boost::shared_ptr<Queue> queue, boost::intrusive_ptr<Message> msg);
+ RecoveredEnqueue(boost::shared_ptr<Queue> queue, Message msg);
virtual bool prepare(TransactionContext* ctxt) throw();
virtual void commit() throw();
virtual void rollback() throw();
virtual ~RecoveredEnqueue(){}
- virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
boost::shared_ptr<Queue> getQueue() const { return queue; }
- boost::intrusive_ptr<Message> getMessage() const { return msg; }
-
+ Message getMessage() const { return msg; }
};
}
}
diff --git a/cpp/src/qpid/broker/RecoveryManagerImpl.cpp b/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
index 858535637a..7deeba5e65 100644
--- a/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
+++ b/cpp/src/qpid/broker/RecoveryManagerImpl.cpp
@@ -21,11 +21,13 @@
#include "qpid/broker/RecoveryManagerImpl.h"
#include "qpid/broker/Message.h"
+#include "qpid/broker/PersistableMessage.h"
#include "qpid/broker/Queue.h"
#include "qpid/broker/Link.h"
#include "qpid/broker/Bridge.h"
#include "qpid/broker/RecoveredEnqueue.h"
#include "qpid/broker/RecoveredDequeue.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/framing/reply_exceptions.h"
using boost::dynamic_pointer_cast;
@@ -43,9 +45,9 @@ RecoveryManagerImpl::~RecoveryManagerImpl() {}
class RecoverableMessageImpl : public RecoverableMessage
{
- intrusive_ptr<Message> msg;
+ Message msg;
public:
- RecoverableMessageImpl(const intrusive_ptr<Message>& _msg);
+ RecoverableMessageImpl(const Message& _msg);
~RecoverableMessageImpl() {};
void setPersistenceId(uint64_t id);
void setRedelivered();
@@ -128,9 +130,10 @@ RecoverableQueue::shared_ptr RecoveryManagerImpl::recoverQueue(framing::Buffer&
RecoverableMessage::shared_ptr RecoveryManagerImpl::recoverMessage(framing::Buffer& buffer)
{
- boost::intrusive_ptr<Message> message(new Message());
- message->decodeHeader(buffer);
- return RecoverableMessage::shared_ptr(new RecoverableMessageImpl(message));
+ //TODO: determine encoding/version actually used
+ boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> transfer(new qpid::broker::amqp_0_10::MessageTransfer());
+ transfer->decodeHeader(buffer);
+ return RecoverableMessage::shared_ptr(new RecoverableMessageImpl(Message(transfer, transfer)));
}
RecoverableTransaction::shared_ptr RecoveryManagerImpl::recoverTransaction(const std::string& xid,
@@ -163,12 +166,7 @@ void RecoveryManagerImpl::recoveryComplete()
exchanges.eachExchange(boost::bind(&Exchange::recoveryComplete, _1, boost::ref(exchanges)));
}
-RecoverableMessageImpl:: RecoverableMessageImpl(const intrusive_ptr<Message>& _msg) : msg(_msg)
-{
- if (!msg->isPersistent()) {
- msg->forcePersistent(); // set so that message will get dequeued from store.
- }
-}
+RecoverableMessageImpl:: RecoverableMessageImpl(const Message& _msg) : msg(_msg) {}
bool RecoverableMessageImpl::loadContent(uint64_t /*available*/)
{
@@ -177,7 +175,7 @@ bool RecoverableMessageImpl::loadContent(uint64_t /*available*/)
void RecoverableMessageImpl::decodeContent(framing::Buffer& buffer)
{
- msg->decodeContent(buffer);
+ msg.getPersistentContext()->decodeContent(buffer);
}
void RecoverableMessageImpl::recover(Queue::shared_ptr queue)
@@ -187,12 +185,12 @@ void RecoverableMessageImpl::recover(Queue::shared_ptr queue)
void RecoverableMessageImpl::setPersistenceId(uint64_t id)
{
- msg->setPersistenceId(id);
+ msg.getPersistentContext()->setPersistenceId(id);
}
void RecoverableMessageImpl::setRedelivered()
{
- msg->redeliver();
+ msg.deliver();//increment delivery count (but at present that isn't recorded durably)
}
void RecoverableQueueImpl::recover(RecoverableMessage::shared_ptr msg)
@@ -204,7 +202,7 @@ void RecoverableQueueImpl::setPersistenceId(uint64_t id)
{
queue->setPersistenceId(id);
}
-
+
uint64_t RecoverableQueueImpl::getPersistenceId() const
{
return queue->getPersistenceId();
diff --git a/cpp/src/qpid/broker/SemanticState.cpp b/cpp/src/qpid/broker/SemanticState.cpp
index 9a84db547c..5d96467bbf 100644
--- a/cpp/src/qpid/broker/SemanticState.cpp
+++ b/cpp/src/qpid/broker/SemanticState.cpp
@@ -29,7 +29,7 @@
#include "qpid/broker/SessionContext.h"
#include "qpid/broker/SessionOutputException.h"
#include "qpid/broker/TxAccept.h"
-#include "qpid/broker/TxPublish.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/SequenceSet.h"
@@ -65,9 +65,8 @@ using qpid::management::Manageable;
using qpid::management::Args;
namespace _qmf = qmf::org::apache::qpid::broker;
-SemanticState::SemanticState(DeliveryAdapter& da, SessionContext& ss)
+SemanticState::SemanticState(SessionState& ss)
: session(ss),
- deliveryAdapter(da),
tagGenerator("sgen"),
dtxSelected(false),
authMsg(getSession().getBroker().getOptions().auth && !getSession().getConnection().isUserProxyAuth()),
@@ -89,7 +88,7 @@ void SemanticState::closed() {
if (dtxBuffer.get()) {
dtxBuffer->fail();
}
- recover(true);
+ requeue();
//now unsubscribe, which may trigger queue deletion and thus
//needs to occur after the requeueing of unacked messages
@@ -124,7 +123,7 @@ void SemanticState::consume(const string& tag,
resumeId, resumeTtl, arguments);
if (!c) // Create plain consumer
c = ConsumerImpl::shared_ptr(
- new ConsumerImpl(this, name, queue, ackRequired, acquire, exclusive, tag,
+ new ConsumerImpl(this, name, queue, ackRequired, acquire ? CONSUMER : BROWSER, exclusive, tag,
resumeId, resumeTtl, arguments));
queue->consume(c, exclusive);//may throw exception
consumers[tag] = c;
@@ -281,7 +280,7 @@ SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
const string& _name,
Queue::shared_ptr _queue,
bool ack,
- bool _acquire,
+ SubscriptionType type,
bool _exclusive,
const string& _tag,
const string& _resumeId,
@@ -289,11 +288,11 @@ SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent,
const framing::FieldTable& _arguments
) :
- Consumer(_name, _acquire),
+Consumer(_name, type),
parent(_parent),
queue(_queue),
ackExpected(ack),
- acquire(_acquire),
+ acquire(type == CONSUMER),
blocked(true),
exclusive(_exclusive),
resumeId(_resumeId),
@@ -340,32 +339,42 @@ OwnershipToken* SemanticState::ConsumerImpl::getSession()
return &(parent->session);
}
-bool SemanticState::ConsumerImpl::deliver(QueuedMessage& msg)
+bool SemanticState::ConsumerImpl::deliver(const QueueCursor& cursor, const Message& msg)
+{
+ return deliver(cursor, msg, shared_from_this());
+}
+bool SemanticState::ConsumerImpl::deliver(const QueueCursor& cursor, const Message& msg, boost::shared_ptr<Consumer> consumer)
{
assertClusterSafe();
- allocateCredit(msg.payload);
- DeliveryRecord record(msg, msg.queue->shared_from_this(), getTag(),
- shared_from_this(), acquire, !ackExpected, credit.isWindowMode(), 0);
+ allocateCredit(msg);
+ DeliveryRecord record(cursor, msg.getSequence(), queue, getTag(),
+ consumer, acquire, !ackExpected, credit.isWindowMode(), amqp_0_10::MessageTransfer::getRequiredCredit(msg));
bool sync = syncFrequency && ++deliveryCount >= syncFrequency;
if (sync) deliveryCount = 0;//reset
- parent->deliver(record, sync);
+ const amqp_0_10::MessageTransfer* transfer = dynamic_cast<const amqp_0_10::MessageTransfer*>(&msg.getEncoding());
+
+ record.setId(parent->session.deliver(*transfer, getTag(), msg.isRedelivered(), msg.getTtl(), msg.getTimestamp(),
+ ackExpected ? message::ACCEPT_MODE_EXPLICIT : message::ACCEPT_MODE_NONE,
+ acquire ? message::ACQUIRE_MODE_PRE_ACQUIRED : message::ACQUIRE_MODE_NOT_ACQUIRED,
+ msg.getAnnotations(),
+ sync));
if (credit.isWindowMode() || ackExpected || !acquire) {
parent->record(record);
}
if (acquire && !ackExpected) { // auto acquire && auto accept
- msg.queue->dequeue(0, msg);
+ queue->dequeue(0 /*ctxt*/, cursor);
record.setEnded();
}
if (mgmtObject) { mgmtObject->inc_delivered(); }
return true;
}
-bool SemanticState::ConsumerImpl::filter(intrusive_ptr<Message>)
+bool SemanticState::ConsumerImpl::filter(const Message&)
{
return true;
}
-bool SemanticState::ConsumerImpl::accept(intrusive_ptr<Message> msg)
+bool SemanticState::ConsumerImpl::accept(const Message& msg)
{
assertClusterSafe();
// TODO aconway 2009-06-08: if we have byte & message credit but
@@ -389,21 +398,21 @@ ostream& operator<<(ostream& o, const ConsumerName& pc) {
}
}
-void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg)
+void SemanticState::ConsumerImpl::allocateCredit(const Message& msg)
{
assertClusterSafe();
Credit original = credit;
- credit.consume(1, msg->getRequiredCredit());
+ credit.consume(1, qpid::broker::amqp_0_10::MessageTransfer::getRequiredCredit(msg));
QPID_LOG(debug, "Credit allocated for " << ConsumerName(*this)
<< ", was " << original << " now " << credit);
}
-bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg)
+bool SemanticState::ConsumerImpl::checkCredit(const Message& msg)
{
- bool enoughCredit = credit.check(1, msg->getRequiredCredit());
+ bool enoughCredit = credit.check(1, qpid::broker::amqp_0_10::MessageTransfer::getRequiredCredit(msg));
QPID_LOG(debug, "Subscription " << ConsumerName(*this) << " has " << (enoughCredit ? "sufficient " : "insufficient")
- << " credit for message of " << msg->getRequiredCredit() << " bytes: "
+ << " credit for message of " << qpid::broker::amqp_0_10::MessageTransfer::getRequiredCredit(msg) << " bytes: "
<< credit);
return enoughCredit;
}
@@ -421,7 +430,6 @@ void SemanticState::disable(ConsumerImpl::shared_ptr c)
session.getConnection().outputTasks.removeOutputTask(c.get());
}
-
void SemanticState::cancel(ConsumerImpl::shared_ptr c)
{
disable(c);
@@ -435,49 +443,20 @@ void SemanticState::cancel(ConsumerImpl::shared_ptr c)
c->cancel();
}
-void SemanticState::handle(intrusive_ptr<Message> msg) {
- if (txBuffer.get()) {
- TxPublish* deliverable(new TxPublish(msg));
- TxOp::shared_ptr op(deliverable);
- route(msg, *deliverable);
- txBuffer->enlist(op);
- } else {
- DeliverableMessage deliverable(msg);
- route(msg, deliverable);
- if (msg->isContentReleaseRequested()) {
- // NOTE: The log messages in this section are used for flow-to-disk testing (which checks the log for the
- // presence of these messages). Do not change these without also checking these tests.
- if (msg->isContentReleaseBlocked()) {
- QPID_LOG(debug, "Message id=\"" << msg->getProperties<MessageProperties>()->getMessageId() << "\"; pid=0x" <<
- std::hex << msg->getPersistenceId() << std::dec << ": Content release blocked");
- } else {
- msg->releaseContent();
- QPID_LOG(debug, "Message id=\"" << msg->getProperties<MessageProperties>()->getMessageId() << "\"; pid=0x" <<
- std::hex << msg->getPersistenceId() << std::dec << ": Content released");
- }
- }
- }
-}
-
-namespace
+TxBuffer* SemanticState::getTxBuffer()
{
-const std::string nullstring;
+ return txBuffer.get();
}
-void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
- msg->computeExpiration(getSession().getBroker().getExpiryPolicy());
+void SemanticState::route(Message& msg, Deliverable& strategy) {
+ msg.computeExpiration(getSession().getBroker().getExpiryPolicy());
- std::string exchangeName = msg->getExchangeName();
- if (!cacheExchange || cacheExchange->getName() != exchangeName
- || cacheExchange->isDestroyed())
- {
+ std::string exchangeName = qpid::broker::amqp_0_10::MessageTransfer::get(msg).getExchangeName();
+ if (!cacheExchange || cacheExchange->getName() != exchangeName || cacheExchange->isDestroyed())
cacheExchange = session.getBroker().getExchanges().get(exchangeName);
- }
- cacheExchange->setProperties(msg);
/* verify the userid if specified: */
- std::string id =
- msg->hasProperties<MessageProperties>() ? msg->getProperties<MessageProperties>()->getUserId() : nullstring;
+ std::string id = msg.getUserId();
if (authMsg && !id.empty() && !session.getConnection().isAuthenticatedUser(id))
{
QPID_LOG(debug, "authorised user id : " << userID << " but user id in message declared as " << id);
@@ -487,9 +466,9 @@ void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
AclModule* acl = getSession().getBroker().getAcl();
if (acl && acl->doTransferAcl())
{
- if (!acl->authorise(getSession().getConnection().getUserId(),acl::ACT_PUBLISH,acl::OBJ_EXCHANGE,exchangeName, msg->getRoutingKey() ))
+ if (!acl->authorise(getSession().getConnection().getUserId(),acl::ACT_PUBLISH,acl::OBJ_EXCHANGE,exchangeName, msg.getRoutingKey() ))
throw UnauthorizedAccessException(QPID_MSG(userID << " cannot publish to " <<
- exchangeName << " with routing-key " << msg->getRoutingKey()));
+ exchangeName << " with routing-key " << msg.getRoutingKey()));
}
cacheExchange->route(strategy);
@@ -501,9 +480,6 @@ void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
if (cacheExchange->getAlternate()) {
cacheExchange->getAlternate()->route(strategy);
}
- if (!strategy.delivered) {
- msg->destroy();
- }
}
}
@@ -543,28 +519,20 @@ void SemanticState::ConsumerImpl::complete(DeliveryRecord& delivery)
}
}
-void SemanticState::recover(bool requeue)
+void SemanticState::requeue()
{
- if(requeue){
- //take copy and clear unacked as requeue may result in redelivery to this session
- //which will in turn result in additions to unacked
- DeliveryRecords copy = unacked;
- unacked.clear();
- for_each(copy.rbegin(), copy.rend(), mem_fun_ref(&DeliveryRecord::requeue));
- }else{
- for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::redeliver, _1, this));
- //unconfirmed messages re redelivered and therefore have their
- //id adjusted, confirmed messages are not and so the ordering
- //w.r.t id is lost
- sort(unacked.begin(), unacked.end());
- }
+ //take copy and clear unacked as requeue may result in redelivery to this session
+ //which will in turn result in additions to unacked
+ DeliveryRecords copy = unacked;
+ unacked.clear();
+ for_each(copy.rbegin(), copy.rend(), mem_fun_ref(&DeliveryRecord::requeue));
getSession().setUnackedCount(unacked.size());
}
-void SemanticState::deliver(DeliveryRecord& msg, bool sync)
-{
- return deliveryAdapter.deliver(msg, sync);
-}
+
+SessionContext& SemanticState::getSession() { return session; }
+const SessionContext& SemanticState::getSession() const { return session; }
+
const SemanticState::ConsumerImpl::shared_ptr SemanticState::find(const std::string& destination) const
{
diff --git a/cpp/src/qpid/broker/SemanticState.h b/cpp/src/qpid/broker/SemanticState.h
index 15928ce599..67cfe808d0 100644
--- a/cpp/src/qpid/broker/SemanticState.h
+++ b/cpp/src/qpid/broker/SemanticState.h
@@ -26,7 +26,6 @@
#include "qpid/broker/Consumer.h"
#include "qpid/broker/Credit.h"
#include "qpid/broker/Deliverable.h"
-#include "qpid/broker/DeliveryAdapter.h"
#include "qpid/broker/DeliveryRecord.h"
#include "qpid/broker/DtxBuffer.h"
#include "qpid/broker/DtxManager.h"
@@ -34,12 +33,15 @@
#include "qpid/broker/QueueObserver.h"
#include "qpid/broker/TxBuffer.h"
+#include "qpid/framing/FieldTable.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/SequenceSet.h"
#include "qpid/framing/Uuid.h"
#include "qpid/sys/AggregateOutput.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/AtomicValue.h"
+#include "qpid/broker/AclModule.h"
+#include "qpid/management/Manageable.h"
#include "qmf/org/apache/qpid/broker/Subscription.h"
#include <list>
@@ -47,13 +49,15 @@
#include <vector>
#include <boost/enable_shared_from_this.hpp>
-#include <boost/intrusive_ptr.hpp>
#include <boost/cast.hpp>
namespace qpid {
namespace broker {
+class Exchange;
+class MessageStore;
class SessionContext;
+class SessionState;
/**
*
@@ -94,28 +98,28 @@ class SemanticState : private boost::noncopyable {
int deliveryCount;
qmf::org::apache::qpid::broker::Subscription* mgmtObject;
- bool checkCredit(boost::intrusive_ptr<Message>& msg);
- void allocateCredit(boost::intrusive_ptr<Message>& msg);
+ bool checkCredit(const Message& msg);
+ void allocateCredit(const Message& msg);
bool haveCredit();
protected:
QPID_BROKER_EXTERN virtual bool doDispatch();
size_t unacked() { return parent->unacked.size(); }
+ QPID_BROKER_EXTERN bool deliver(const QueueCursor&, const Message&, boost::shared_ptr<Consumer>);
public:
typedef boost::shared_ptr<ConsumerImpl> shared_ptr;
- QPID_BROKER_EXTERN ConsumerImpl(
- SemanticState* parent,
- const std::string& name, boost::shared_ptr<Queue> queue,
- bool ack, bool acquire, bool exclusive,
- const std::string& tag, const std::string& resumeId, uint64_t resumeTtl,
- const framing::FieldTable& arguments);
- QPID_BROKER_EXTERN virtual ~ConsumerImpl();
+ QPID_BROKER_EXTERN ConsumerImpl(SemanticState* parent,
+ const std::string& name, boost::shared_ptr<Queue> queue,
+ bool ack, SubscriptionType type, bool exclusive,
+ const std::string& tag, const std::string& resumeId,
+ uint64_t resumeTtl, const framing::FieldTable& arguments);
+ QPID_BROKER_EXTERN ~ConsumerImpl();
QPID_BROKER_EXTERN OwnershipToken* getSession();
- QPID_BROKER_EXTERN virtual bool deliver(QueuedMessage& msg);
- QPID_BROKER_EXTERN bool filter(boost::intrusive_ptr<Message> msg);
- QPID_BROKER_EXTERN bool accept(boost::intrusive_ptr<Message> msg);
+ QPID_BROKER_EXTERN bool deliver(const QueueCursor&, const Message&);
+ QPID_BROKER_EXTERN bool filter(const Message&);
+ QPID_BROKER_EXTERN bool accept(const Message&);
QPID_BROKER_EXTERN void cancel() {}
QPID_BROKER_EXTERN void disableNotify();
@@ -153,7 +157,7 @@ class SemanticState : private boost::noncopyable {
SemanticState& getParent() { return *parent; }
const SemanticState& getParent() const { return *parent; }
- void acknowledged(const broker::QueuedMessage&) {}
+ void acknowledged(const DeliveryRecord&) {}
// manageable entry points
QPID_BROKER_EXTERN management::ManagementObject*
@@ -168,8 +172,7 @@ class SemanticState : private boost::noncopyable {
private:
typedef std::map<std::string, ConsumerImpl::shared_ptr> ConsumerImplMap;
- SessionContext& session;
- DeliveryAdapter& deliveryAdapter;
+ SessionState& session;
ConsumerImplMap consumers;
NameGenerator tagGenerator;
DeliveryRecords unacked;
@@ -185,7 +188,6 @@ class SemanticState : private boost::noncopyable {
//needed for queue delete events in auto-delete:
const std::string connectionId;
- void route(boost::intrusive_ptr<Message> msg, Deliverable& strategy);
void checkDtxTimeout();
bool complete(DeliveryRecord&);
@@ -196,11 +198,11 @@ class SemanticState : private boost::noncopyable {
public:
- SemanticState(DeliveryAdapter&, SessionContext&);
+ SemanticState(SessionState&);
~SemanticState();
- SessionContext& getSession() { return session; }
- const SessionContext& getSession() const { return session; }
+ SessionContext& getSession();
+ const SessionContext& getSession() const;
const ConsumerImpl::shared_ptr find(const std::string& destination) const;
bool find(const std::string& destination, ConsumerImpl::shared_ptr&) const;
@@ -239,12 +241,12 @@ class SemanticState : private boost::noncopyable {
void endDtx(const std::string& xid, bool fail);
void suspendDtx(const std::string& xid);
void resumeDtx(const std::string& xid);
- void recover(bool requeue);
- void deliver(DeliveryRecord& message, bool sync);
+ TxBuffer* getTxBuffer();
+ void requeue();
void acquire(DeliveryId first, DeliveryId last, DeliveryIds& acquired);
void release(DeliveryId first, DeliveryId last, bool setRedelivered);
void reject(DeliveryId first, DeliveryId last);
- void handle(boost::intrusive_ptr<Message> msg);
+ void route(Message& msg, Deliverable& strategy);
void completed(const framing::SequenceSet& commands);
void accepted(const framing::SequenceSet& commands);
diff --git a/cpp/src/qpid/broker/SessionAdapter.cpp b/cpp/src/qpid/broker/SessionAdapter.cpp
index ae994a6bd5..c973098020 100644
--- a/cpp/src/qpid/broker/SessionAdapter.cpp
+++ b/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -264,7 +264,7 @@ QueueQueryResult SessionAdapter::QueueHandlerImpl::query(const string& name)
queue->isDurable(),
queue->hasExclusiveOwner(),
queue->isAutoDelete(),
- queue->getSettings(),
+ queue->getEncodableSettings(),
queue->getMessageCount(),
queue->getConsumerCount());
} else {
@@ -294,19 +294,24 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string&
queue = getQueue(name);
//TODO: check alternate-exchange is as expected
} else {
+ QueueSettings settings(durable, autoDelete);
+ try {
+ settings.populate(arguments, settings.storeSettings);
+ } catch (const qpid::types::Exception& e) {
+ throw InvalidArgumentException(e.what());
+ }
+
std::pair<Queue::shared_ptr, bool> queue_created =
- getBroker().createQueue(name, durable,
- autoDelete,
+ getBroker().createQueue(name, settings,
exclusive ? &session : 0,
alternateExchange,
- arguments,
getConnection().getUserId(),
getConnection().getUrl());
queue = queue_created.first;
assert(queue);
if (queue_created.second) { // This is a new queue
//handle automatic cleanup:
- if (exclusive) {
+ if (exclusive && queue->setExclusiveOwner(&session)) {
exclusiveQueues.push_back(queue);
}
} else {
diff --git a/cpp/src/qpid/broker/SessionHandler.cpp b/cpp/src/qpid/broker/SessionHandler.cpp
index 23fa2ee0ca..9888d12be2 100644
--- a/cpp/src/qpid/broker/SessionHandler.cpp
+++ b/cpp/src/qpid/broker/SessionHandler.cpp
@@ -32,7 +32,7 @@ using namespace std;
using namespace qpid::sys;
SessionHandler::SessionHandler(Connection& c, ChannelId ch)
- : amqp_0_10::SessionHandler(&c.getOutput(), ch),
+ : qpid::amqp_0_10::SessionHandler(&c.getOutput(), ch),
connection(c),
proxy(out),
clusterOrderProxy(c.getClusterOrderOutput() ?
@@ -75,7 +75,7 @@ ConnectionState& SessionHandler::getConnection() { return connection; }
const ConnectionState& SessionHandler::getConnection() const { return connection; }
void SessionHandler::handleDetach() {
- amqp_0_10::SessionHandler::handleDetach();
+ qpid::amqp_0_10::SessionHandler::handleDetach();
assert(&connection.getChannel(channel.get()) == this);
if (session.get())
connection.getBroker().getSessionManager().detach(session);
@@ -125,7 +125,7 @@ void SessionHandler::attached(const std::string& name)
{
if (session.get()) {
session->addManagementObject(); // Delayed from attachAs()
- amqp_0_10::SessionHandler::attached(name);
+ qpid::amqp_0_10::SessionHandler::attached(name);
} else {
SessionId id(connection.getUserId(), name);
SessionState::Configuration config = connection.broker.getSessionManager().getSessionConfig();
diff --git a/cpp/src/qpid/broker/SessionHandler.h b/cpp/src/qpid/broker/SessionHandler.h
index ab87cf41a4..21c736fa37 100644
--- a/cpp/src/qpid/broker/SessionHandler.h
+++ b/cpp/src/qpid/broker/SessionHandler.h
@@ -41,7 +41,7 @@ class SessionState;
* receives incoming frames, handles session controls and manages the
* association between the channel and a session.
*/
-class SessionHandler : public amqp_0_10::SessionHandler {
+class SessionHandler : public qpid::amqp_0_10::SessionHandler {
public:
class ErrorListener {
public:
diff --git a/cpp/src/qpid/broker/SessionState.cpp b/cpp/src/qpid/broker/SessionState.cpp
index cc02d9ec94..88cdf7e03a 100644
--- a/cpp/src/qpid/broker/SessionState.cpp
+++ b/cpp/src/qpid/broker/SessionState.cpp
@@ -21,6 +21,7 @@
#include "qpid/broker/SessionState.h"
#include "qpid/broker/Broker.h"
#include "qpid/broker/ConnectionState.h"
+#include "qpid/broker/DeliverableMessage.h"
#include "qpid/broker/DeliveryRecord.h"
#include "qpid/broker/SessionManager.h"
#include "qpid/broker/SessionHandler.h"
@@ -28,6 +29,7 @@
#include "qpid/framing/AMQContentBody.h"
#include "qpid/framing/AMQHeaderBody.h"
#include "qpid/framing/AMQMethodBody.h"
+#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/ServerInvoker.h"
#include "qpid/log/Statement.h"
@@ -55,9 +57,8 @@ SessionState::SessionState(
const SessionState::Configuration& config, bool delayManagement)
: qpid::SessionState(id, config),
broker(b), handler(&h),
- semanticState(*this, *this),
+ semanticState(*this),
adapter(semanticState),
- msgBuilder(&broker.getStore()),
mgmtObject(0),
asyncCommandCompleter(new AsyncCommandCompleter(this))
{
@@ -208,7 +209,7 @@ void SessionState::handleContent(AMQFrame& frame, const SequenceNumber& id)
{
if (frame.getBof() && frame.getBos()) //start of frameset
msgBuilder.start(id);
- intrusive_ptr<Message> msg(msgBuilder.getMessage());
+ intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> msg(msgBuilder.getMessage());
msgBuilder.handle(frame);
if (frame.getEof() && frame.getEos()) {//end of frameset
if (frame.getBof()) {
@@ -218,13 +219,16 @@ void SessionState::handleContent(AMQFrame& frame, const SequenceNumber& id)
header.setEof(false);
msg->getFrames().append(header);
}
+ DeliverableMessage deliverable(Message(msg, msg), semanticState.getTxBuffer());
if (broker.isTimestamping())
- msg->setTimestamp();
- msg->setPublisher(&getConnection());
+ deliverable.getMessage().setTimestamp();
+ deliverable.getMessage().setPublisher(&getConnection());
+
+
+ IncompleteIngressMsgXfer xfer(this, msg);
msg->getIngressCompletion().begin();
- semanticState.handle(msg);
+ semanticState.route(deliverable.getMessage(), deliverable);
msgBuilder.end();
- IncompleteIngressMsgXfer xfer(this, msg);
msg->getIngressCompletion().end(xfer); // allows msg to complete xfer
}
}
@@ -294,18 +298,28 @@ void SessionState::handleOut(AMQFrame& frame) {
handler->out(frame);
}
-void SessionState::deliver(DeliveryRecord& msg, bool sync)
+DeliveryId SessionState::deliver(const qpid::broker::amqp_0_10::MessageTransfer& message,
+ const std::string& destination, bool isRedelivered, uint64_t ttl, uint64_t timestamp,
+ qpid::framing::message::AcceptMode acceptMode, qpid::framing::message::AcquireMode acquireMode,
+ const qpid::types::Variant::Map& annotations, bool sync)
{
uint32_t maxFrameSize = getConnection().getFrameMax();
assert(senderGetCommandPoint().offset == 0);
SequenceNumber commandId = senderGetCommandPoint().command;
- msg.deliver(getProxy().getHandler(), commandId, maxFrameSize);
+
+ framing::AMQFrame method((framing::MessageTransferBody(framing::ProtocolVersion(), destination, acceptMode, acquireMode)));
+ method.setEof(false);
+ getProxy().getHandler().handle(method);
+ message.sendHeader(getProxy().getHandler(), maxFrameSize, isRedelivered, ttl, timestamp, annotations);
+ message.sendContent(getProxy().getHandler(), maxFrameSize);
+
assert(senderGetCommandPoint() == SessionPoint(commandId+1, 0)); // Delivery has moved sendPoint.
if (sync) {
AMQP_ClientProxy::Execution& p(getProxy().getExecution());
Proxy::ScopedSync s(p);
p.sync();
}
+ return commandId;
}
void SessionState::sendCompletion() {
@@ -349,7 +363,6 @@ void SessionState::addPendingExecutionSync()
}
}
-
/** factory for creating a reference-counted IncompleteIngressMsgXfer object
* which will be attached to a message that will be completed asynchronously.
*/
@@ -408,10 +421,10 @@ void SessionState::AsyncCommandCompleter::schedule(boost::intrusive_ptr<AsyncCom
/** Track an ingress message that is pending completion */
-void SessionState::AsyncCommandCompleter::addPendingMessage(boost::intrusive_ptr<Message> msg)
+void SessionState::AsyncCommandCompleter::addPendingMessage(boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> msg)
{
qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock);
- std::pair<SequenceNumber, boost::intrusive_ptr<Message> > item(msg->getCommandId(), msg);
+ std::pair<SequenceNumber, boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> > item(msg->getCommandId(), msg);
bool unique = pendingMsgs.insert(item).second;
if (!unique) {
assert(false);
@@ -430,13 +443,13 @@ void SessionState::AsyncCommandCompleter::deletePendingMessage(SequenceNumber id
/** done when an execution.sync arrives */
void SessionState::AsyncCommandCompleter::flushPendingMessages()
{
- std::map<SequenceNumber, boost::intrusive_ptr<Message> > copy;
+ std::map<SequenceNumber, boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> > copy;
{
qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock);
pendingMsgs.swap(copy); // we've only tracked these in case a flush is needed, so nuke 'em now.
}
// drop lock, so it is safe to call "flush()"
- for (std::map<SequenceNumber, boost::intrusive_ptr<Message> >::iterator i = copy.begin();
+ for (std::map<SequenceNumber, boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> >::iterator i = copy.begin();
i != copy.end(); ++i) {
i->second->flush();
}
diff --git a/cpp/src/qpid/broker/SessionState.h b/cpp/src/qpid/broker/SessionState.h
index a8ff7feff9..5e3a77d7ed 100644
--- a/cpp/src/qpid/broker/SessionState.h
+++ b/cpp/src/qpid/broker/SessionState.h
@@ -23,17 +23,18 @@
*/
#include "qpid/SessionState.h"
+#include "qpid/framing/enum.h"
#include "qpid/framing/FrameHandler.h"
#include "qpid/framing/SequenceSet.h"
#include "qpid/sys/Time.h"
#include "qpid/management/Manageable.h"
#include "qmf/org/apache/qpid/broker/Session.h"
#include "qpid/broker/SessionAdapter.h"
-#include "qpid/broker/DeliveryAdapter.h"
#include "qpid/broker/AsyncCompletion.h"
#include "qpid/broker/MessageBuilder.h"
#include "qpid/broker/SessionContext.h"
#include "qpid/broker/SemanticState.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/sys/Monitor.h"
#include <boost/noncopyable.hpp>
@@ -58,7 +59,6 @@ namespace broker {
class Broker;
class ConnectionState;
-class Message;
class SessionHandler;
class SessionManager;
@@ -68,7 +68,6 @@ class SessionManager;
*/
class SessionState : public qpid::SessionState,
public SessionContext,
- public DeliveryAdapter,
public management::Manageable,
public framing::FrameHandler::InOutHandler
{
@@ -105,8 +104,10 @@ class SessionState : public qpid::SessionState,
void sendCompletion();
- //delivery adapter methods:
- void deliver(DeliveryRecord&, bool sync);
+ DeliveryId deliver(const qpid::broker::amqp_0_10::MessageTransfer& message,
+ const std::string& destination, bool isRedelivered, uint64_t ttl, uint64_t timestamp,
+ qpid::framing::message::AcceptMode, qpid::framing::message::AcquireMode,
+ const qpid::types::Variant::Map& annotations, bool sync);
// Manageable entry points
management::ManagementObject* GetManagementObject (void) const;
@@ -117,7 +118,7 @@ class SessionState : public qpid::SessionState,
// Used by cluster to create replica sessions.
SemanticState& getSemanticState() { return semanticState; }
- boost::intrusive_ptr<Message> getMessageInProgress() { return msgBuilder.getMessage(); }
+ boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> getMessageInProgress() { return msgBuilder.getMessage(); }
SessionAdapter& getSessionAdapter() { return adapter; }
const SessionId& getSessionId() const { return getId(); }
@@ -199,7 +200,7 @@ class SessionState : public qpid::SessionState,
// If an ingress message does not require a Sync, we need to
// hold a reference to it in case an Execution.Sync command is received and we
// have to manually flush the message.
- std::map<SequenceNumber, boost::intrusive_ptr<Message> > pendingMsgs;
+ std::map<SequenceNumber, boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> > pendingMsgs;
/** complete all pending commands, runs in IO thread */
void completeCommands();
@@ -212,7 +213,7 @@ class SessionState : public qpid::SessionState,
~AsyncCommandCompleter() {};
/** track a message pending ingress completion */
- void addPendingMessage(boost::intrusive_ptr<Message> m);
+ void addPendingMessage(boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> m);
void deletePendingMessage(SequenceNumber id);
void flushPendingMessages();
/** schedule the processing of a completed ingress message.transfer command */
@@ -246,29 +247,29 @@ class SessionState : public qpid::SessionState,
{
public:
IncompleteIngressMsgXfer( SessionState *ss,
- boost::intrusive_ptr<Message> m )
+ boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> m)
: AsyncCommandContext(ss, m->getCommandId()),
- session(ss),
- msg(m),
- requiresAccept(m->requiresAccept()),
- requiresSync(m->getFrames().getMethod()->isSync()),
- pending(false) {}
+ session(ss),
+ msg(m),
+ requiresAccept(m->requiresAccept()),
+ requiresSync(m->getFrames().getMethod()->isSync()),
+ pending(false) {}
IncompleteIngressMsgXfer( const IncompleteIngressMsgXfer& x )
: AsyncCommandContext(x.session, x.msg->getCommandId()),
- session(x.session),
- msg(x.msg),
- requiresAccept(x.requiresAccept),
- requiresSync(x.requiresSync),
- pending(x.pending) {}
+ session(x.session),
+ msg(x.msg),
+ requiresAccept(x.requiresAccept),
+ requiresSync(x.requiresSync),
+ pending(x.pending) {}
- virtual ~IncompleteIngressMsgXfer() {};
+ virtual ~IncompleteIngressMsgXfer() {};
virtual void completed(bool);
virtual boost::intrusive_ptr<AsyncCompletion::Callback> clone();
private:
SessionState *session; // only valid if sync flag in callback is true
- boost::intrusive_ptr<Message> msg;
+ boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> msg;
bool requiresAccept;
bool requiresSync;
bool pending; // true if msg saved on pending list...
diff --git a/cpp/src/qpid/broker/SimpleMessage.cpp b/cpp/src/qpid/broker/SimpleMessage.cpp
index 1239533edf..3a85ca9ae4 100644
--- a/cpp/src/qpid/broker/SimpleMessage.cpp
+++ b/cpp/src/qpid/broker/SimpleMessage.cpp
@@ -28,6 +28,17 @@
namespace qpid {
namespace broker {
+SimpleMessage::SimpleMessage() {}
+
+SimpleMessage::SimpleMessage(const char* msgData,
+ const uint32_t msgSize,
+ boost::intrusive_ptr<PersistableMessage> persistentContext) :
+ m_msg(msgData, static_cast<size_t>(msgSize)),
+ m_persistentContext(persistentContext)
+{}
+
+
+/*
SimpleMessage::SimpleMessage(const char* msgData,
const uint32_t msgSize) :
m_persistenceId(0ULL),
@@ -44,24 +55,28 @@ SimpleMessage::SimpleMessage(const char* msgData,
m_store(store),
m_msgHandle(store ? store->createMessageHandle(this) : MessageHandle())
{}
+*/
SimpleMessage::~SimpleMessage() {}
+/*
const MessageHandle&
SimpleMessage::getHandle() const {
- return m_msgHandle;
+ return m_persistentContext.getHandle();
}
MessageHandle&
SimpleMessage::getHandle() {
- return m_msgHandle;
+ return m_persistentContext.getHandle();
}
+*/
uint64_t
SimpleMessage::contentSize() const {
return static_cast<uint64_t>(m_msg.size());
}
+/*
void
SimpleMessage::setPersistenceId(uint64_t id) const {
m_persistenceId = id;
@@ -89,12 +104,18 @@ uint32_t
SimpleMessage::encodedHeaderSize() const {
return 0;
}
-
+*/
bool
SimpleMessage::isPersistent() const {
- return m_store != 0;
+ return m_persistentContext.get() != 0;
}
+boost::intrusive_ptr<PersistableMessage>
+SimpleMessage::getPersistentContext() const {
+ return m_persistentContext;
+}
+
+
uint64_t
SimpleMessage::getSize() {
return m_msg.size();
diff --git a/cpp/src/qpid/broker/SimpleMessage.h b/cpp/src/qpid/broker/SimpleMessage.h
index edfaa8d13b..72ede431e0 100644
--- a/cpp/src/qpid/broker/SimpleMessage.h
+++ b/cpp/src/qpid/broker/SimpleMessage.h
@@ -25,47 +25,51 @@
#define qpid_broker_SimpleMessage_h_
#include "AsyncStore.h" // DataSource
-#include "MessageHandle.h"
+//#include "MessageHandle.h"
#include "PersistableMessage.h"
namespace qpid {
namespace broker {
-class SimpleMessage: public PersistableMessage,
- public DataSource
+class SimpleMessage: /*public PersistableMessage,*/
+ public DataSource,
+ public RefCounted
{
public:
- SimpleMessage(const char* msgData,
- const uint32_t msgSize);
+ SimpleMessage();
SimpleMessage(const char* msgData,
const uint32_t msgSize,
- AsyncStore* store);
+ boost::intrusive_ptr<PersistableMessage> persistentContext);
virtual ~SimpleMessage();
- const MessageHandle& getHandle() const;
- MessageHandle& getHandle();
+// const MessageHandle& getHandle() const;
+// MessageHandle& getHandle();
uint64_t contentSize() const;
- // --- Interface Persistable ---
- virtual void setPersistenceId(uint64_t id) const;
- virtual uint64_t getPersistenceId() const;
- virtual void encode(qpid::framing::Buffer& buffer) const;
- virtual uint32_t encodedSize() const;
+// // --- Interface Persistable ---
+// virtual void setPersistenceId(uint64_t id) const;
+// virtual uint64_t getPersistenceId() const;
+// virtual void encode(qpid::framing::Buffer& buffer) const;
+// virtual uint32_t encodedSize() const;
+//
+// // --- Interface PersistableMessage ---
+// virtual void allDequeuesComplete();
+// virtual uint32_t encodedHeaderSize() const;
- // --- Interface PersistableMessage ---
- virtual void allDequeuesComplete();
- virtual uint32_t encodedHeaderSize() const;
- virtual bool isPersistent() const;
+ // Persistent operations
+ bool isPersistent() const;
+ boost::intrusive_ptr<PersistableMessage> getPersistentContext() const;
// --- Interface DataSource ---
virtual uint64_t getSize(); // <- same as encodedSize()?
virtual void write(char* target);
private:
- mutable uint64_t m_persistenceId;
+// mutable uint64_t m_persistenceId;
const std::string m_msg;
- AsyncStore* m_store;
+ boost::intrusive_ptr<PersistableMessage> m_persistentContext;
+// AsyncStore* m_store;
- MessageHandle m_msgHandle;
+// MessageHandle m_msgHandle;
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SimpleQueue.cpp b/cpp/src/qpid/broker/SimpleQueue.cpp
index 5cd8841f94..e20edc1f92 100644
--- a/cpp/src/qpid/broker/SimpleQueue.cpp
+++ b/cpp/src/qpid/broker/SimpleQueue.cpp
@@ -171,7 +171,7 @@ SimpleQueue::enqueue(SimpleTxnBuffer* tb,
return false;
}
if (qm->payload()->isPersistent() && m_store) {
- qm->payload()->enqueueAsync(shared_from_this(), m_store);
+ qm->payload()->getPersistentContext()->enqueueAsync(shared_from_this(), m_store);
return asyncEnqueue(tb, qm);
}
return false;
@@ -190,7 +190,7 @@ SimpleQueue::dequeue(SimpleTxnBuffer* tb,
return false;
}
if (qm->payload()->isPersistent() && m_store) {
- qm->payload()->dequeueAsync(shared_from_this(), m_store);
+ qm->payload()->getPersistentContext()->dequeueAsync(shared_from_this(), m_store);
return asyncDequeue(tb, qm);
}
return true;
@@ -316,7 +316,7 @@ SimpleQueue::asyncEnqueue(SimpleTxnBuffer* tb,
boost::shared_ptr<SimpleQueuedMessage> qm) {
assert(qm.get());
boost::shared_ptr<QueueAsyncContext> qac(new QueueAsyncContext(shared_from_this(),
- qm->payload(),
+ /*qm->payload(),*/
tb,
&handleAsyncEnqueueResult,
&m_resultQueue));
@@ -353,7 +353,7 @@ SimpleQueue::asyncDequeue(SimpleTxnBuffer* tb,
boost::shared_ptr<SimpleQueuedMessage> qm) {
assert(qm.get());
boost::shared_ptr<QueueAsyncContext> qac(new QueueAsyncContext(shared_from_this(),
- qm->payload(),
+ /*qm->payload(),*/
tb,
&handleAsyncDequeueResult,
&m_resultQueue));
diff --git a/cpp/src/qpid/broker/SimpleQueuedMessage.cpp b/cpp/src/qpid/broker/SimpleQueuedMessage.cpp
index 35ac799ecc..f5135902a4 100644
--- a/cpp/src/qpid/broker/SimpleQueuedMessage.cpp
+++ b/cpp/src/qpid/broker/SimpleQueuedMessage.cpp
@@ -40,7 +40,7 @@ SimpleQueuedMessage::SimpleQueuedMessage(SimpleQueue* q,
m_msg(msg)
{
if (m_queue->getStore()) {
- m_enqHandle = q->getStore()->createEnqueueHandle(msg->getHandle(), q->getHandle());
+ m_enqHandle = q->getStore()->createEnqueueHandle(msg->getPersistentContext()->getMessageHandle(), q->getHandle());
}
}
diff --git a/cpp/src/qpid/broker/ThresholdAlerts.cpp b/cpp/src/qpid/broker/ThresholdAlerts.cpp
index 3c9e210d4d..9b4e948e4f 100644
--- a/cpp/src/qpid/broker/ThresholdAlerts.cpp
+++ b/cpp/src/qpid/broker/ThresholdAlerts.cpp
@@ -20,7 +20,8 @@
*/
#include "qpid/broker/ThresholdAlerts.h"
#include "qpid/broker/Queue.h"
-#include "qpid/broker/QueuedMessage.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/amqp_0_10/Codecs.h"
#include "qpid/log/Statement.h"
#include "qpid/management/ManagementAgent.h"
@@ -30,21 +31,20 @@ namespace qpid {
namespace broker {
namespace {
const qmf::org::apache::qpid::broker::EventQueueThresholdExceeded EVENT("dummy", 0, 0);
-bool isQMFv2(const boost::intrusive_ptr<Message> message)
+bool isQMFv2(const Message& message)
{
- const qpid::framing::MessageProperties* props = message->getProperties<qpid::framing::MessageProperties>();
+ const qpid::framing::MessageProperties* props = qpid::broker::amqp_0_10::MessageTransfer::get(message).getProperties<qpid::framing::MessageProperties>();
return props && props->getAppId() == "qmf2";
}
-bool isThresholdEvent(const boost::intrusive_ptr<Message> message)
+bool isThresholdEvent(const Message& message)
{
- if (message->getIsManagementMessage()) {
+ if (message.getIsManagementMessage()) {
//is this a qmf event? if so is it a threshold event?
if (isQMFv2(message)) {
- const qpid::framing::FieldTable* headers = message->getApplicationHeaders();
- if (headers && headers->getAsString("qmf.content") == "_event") {
+ if (message.getPropertyAsString("qmf.content") == "_event") {
//decode as list
- std::string content = message->getFrames().getContent();
+ std::string content = qpid::broker::amqp_0_10::MessageTransfer::get(message).getFrames().getContent();
qpid::types::Variant::List list;
qpid::amqp_0_10::ListCodec::decode(content, list);
if (list.empty() || list.front().getType() != qpid::types::VAR_MAP) return false;
@@ -57,7 +57,7 @@ bool isThresholdEvent(const boost::intrusive_ptr<Message> message)
}
}
} else {
- std::string content = message->getFrames().getContent();
+ std::string content = qpid::broker::amqp_0_10::MessageTransfer::get(message).getFrames().getContent();
qpid::framing::Buffer buffer(const_cast<char*>(content.data()), content.size());
if (buffer.getOctet() == 'A' && buffer.getOctet() == 'M' && buffer.getOctet() == '2' && buffer.getOctet() == 'e') {
buffer.getLong();//sequence
@@ -83,9 +83,9 @@ ThresholdAlerts::ThresholdAlerts(const std::string& n,
repeatInterval(repeat ? repeat*qpid::sys::TIME_SEC : 0),
count(0), size(0), lastAlert(qpid::sys::EPOCH) {}
-void ThresholdAlerts::enqueued(const QueuedMessage& m)
+void ThresholdAlerts::enqueued(const Message& m)
{
- size += m.payload->contentSize();
+ size += m.getContentSize();
++count;
if ((countThreshold && count >= countThreshold) || (sizeThreshold && size >= sizeThreshold)) {
if ((repeatInterval == 0 && lastAlert == qpid::sys::EPOCH)
@@ -94,7 +94,7 @@ void ThresholdAlerts::enqueued(const QueuedMessage& m)
//enqueued on queues; it may even be that this event
//causes a message to be enqueued on the queue we are
//tracking, and so we need to avoid recursing
- if (isThresholdEvent(m.payload)) return;
+ if (isThresholdEvent(m)) return;
lastAlert = qpid::sys::now();
agent.raiseEvent(qmf::org::apache::qpid::broker::EventQueueThresholdExceeded(name, count, size));
QPID_LOG(info, "Threshold event triggered for " << name << ", count=" << count << ", size=" << size);
@@ -102,9 +102,9 @@ void ThresholdAlerts::enqueued(const QueuedMessage& m)
}
}
-void ThresholdAlerts::dequeued(const QueuedMessage& m)
+void ThresholdAlerts::dequeued(const Message& m)
{
- size -= m.payload->contentSize();
+ size -= m.getContentSize();
--count;
if ((countThreshold && count < countThreshold) || (sizeThreshold && size < sizeThreshold)) {
lastAlert = qpid::sys::EPOCH;
@@ -127,65 +127,14 @@ void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& a
}
void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& agent,
- const qpid::framing::FieldTable& settings, uint16_t limitRatio)
-
-{
- qpid::types::Variant::Map map;
- qpid::amqp_0_10::translate(settings, map);
- observe(queue, agent, map, limitRatio);
-}
-
-template <class T>
-class Option
-{
- public:
- Option(const std::string& name, T d) : defaultValue(d) { names.push_back(name); }
- void addAlias(const std::string& name) { names.push_back(name); }
- T get(const qpid::types::Variant::Map& settings) const
- {
- T value(defaultValue);
- for (std::vector<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
- if (get(settings, *i, value)) break;
- }
- return value;
- }
- private:
- std::vector<std::string> names;
- T defaultValue;
-
- bool get(const qpid::types::Variant::Map& settings, const std::string& name, T& value) const
- {
- qpid::types::Variant::Map::const_iterator i = settings.find(name);
- if (i != settings.end()) {
- try {
- value = (T) i->second;
- } catch (const qpid::types::InvalidConversion&) {
- QPID_LOG(warning, "Bad value for" << name << ": " << i->second);
- }
- return true;
- } else {
- return false;
- }
- }
-};
-
-void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& agent,
- const qpid::types::Variant::Map& settings, uint16_t limitRatio)
-
+ const QueueSettings& settings, uint16_t limitRatio)
{
- //Note: aliases are keys defined by java broker
- Option<int64_t> repeatInterval("qpid.alert_repeat_gap", 60);
- repeatInterval.addAlias("x-qpid-minimum-alert-repeat-gap");
-
//If no explicit threshold settings were given use specified
//percentage of any limit from the policy.
- const QueuePolicy* policy = queue.getPolicy();
- Option<uint32_t> countThreshold("qpid.alert_count", (uint32_t) (policy && limitRatio ? (policy->getMaxCount()*limitRatio/100) : 0));
- countThreshold.addAlias("x-qpid-maximum-message-count");
- Option<uint64_t> sizeThreshold("qpid.alert_size", (uint64_t) (policy && limitRatio ? (policy->getMaxSize()*limitRatio/100) : 0));
- sizeThreshold.addAlias("x-qpid-maximum-message-size");
+ uint32_t countThreshold = settings.alertThreshold.hasCount() ? settings.alertThreshold.getCount() : (settings.maxDepth.getCount()*limitRatio/100);
+ uint32_t sizeThreshold = settings.alertThreshold.hasSize() ? settings.alertThreshold.getSize() : (settings.maxDepth.getSize()*limitRatio/100);
- observe(queue, agent, countThreshold.get(settings), sizeThreshold.get(settings), repeatInterval.get(settings));
+ observe(queue, agent, countThreshold, sizeThreshold, settings.alertRepeatInterval);
}
}}
diff --git a/cpp/src/qpid/broker/ThresholdAlerts.h b/cpp/src/qpid/broker/ThresholdAlerts.h
index 2b4a46b736..4f985522e2 100644
--- a/cpp/src/qpid/broker/ThresholdAlerts.h
+++ b/cpp/src/qpid/broker/ThresholdAlerts.h
@@ -27,15 +27,13 @@
#include <string>
namespace qpid {
-namespace framing {
-class FieldTable;
-}
namespace management {
class ManagementAgent;
}
namespace broker {
class Queue;
+struct QueueSettings;
/**
* Class to manage generation of QMF alerts when particular thresholds
* are breached on a queue.
@@ -48,19 +46,17 @@ class ThresholdAlerts : public QueueObserver
const uint32_t countThreshold,
const uint64_t sizeThreshold,
const long repeatInterval);
- void enqueued(const QueuedMessage&);
- void dequeued(const QueuedMessage&);
- void acquired(const QueuedMessage&) {};
- void requeued(const QueuedMessage&) {};
+ void enqueued(const Message&);
+ void dequeued(const Message&);
+ void acquired(const Message&) {};
+ void requeued(const Message&) {};
static void observe(Queue& queue, qpid::management::ManagementAgent& agent,
const uint64_t countThreshold,
const uint64_t sizeThreshold,
const long repeatInterval);
static void observe(Queue& queue, qpid::management::ManagementAgent& agent,
- const qpid::framing::FieldTable& settings, uint16_t limitRatio);
- static void observe(Queue& queue, qpid::management::ManagementAgent& agent,
- const qpid::types::Variant::Map& settings, uint16_t limitRatio);
+ const QueueSettings& settings, uint16_t limitRatio);
private:
const std::string name;
qpid::management::ManagementAgent& agent;
diff --git a/cpp/src/qpid/broker/TxAccept.h b/cpp/src/qpid/broker/TxAccept.h
index 314a150176..a59e69a85f 100644
--- a/cpp/src/qpid/broker/TxAccept.h
+++ b/cpp/src/qpid/broker/TxAccept.h
@@ -71,7 +71,6 @@ namespace qpid {
virtual void commit() throw();
virtual void rollback() throw();
virtual ~TxAccept(){}
- virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
// Used by cluster replication.
const framing::SequenceSet& getAcked() const { return acked; }
diff --git a/cpp/src/qpid/broker/TxBuffer.cpp b/cpp/src/qpid/broker/TxBuffer.cpp
index d92e6ace48..7663cc525f 100644
--- a/cpp/src/qpid/broker/TxBuffer.cpp
+++ b/cpp/src/qpid/broker/TxBuffer.cpp
@@ -28,7 +28,7 @@ using namespace qpid::broker;
bool TxBuffer::prepare(TransactionContext* const ctxt)
{
- for(op_iterator i = ops.begin(); i < ops.end(); i++){
+ for(op_iterator i = ops.begin(); i != ops.end(); i++){
if(!(*i)->prepare(ctxt)){
return false;
}
@@ -74,7 +74,3 @@ bool TxBuffer::commitLocal(TransactionalStore* const store)
}
return false;
}
-
-void TxBuffer::accept(TxOpConstVisitor& v) const {
- std::for_each(ops.begin(), ops.end(), boost::bind(&TxOp::accept, _1, boost::ref(v)));
-}
diff --git a/cpp/src/qpid/broker/TxBuffer.h b/cpp/src/qpid/broker/TxBuffer.h
index d49c8ba16a..22e2f06be1 100644
--- a/cpp/src/qpid/broker/TxBuffer.h
+++ b/cpp/src/qpid/broker/TxBuffer.h
@@ -108,9 +108,6 @@ namespace qpid {
* commit
*/
QPID_BROKER_EXTERN bool commitLocal(TransactionalStore* const store);
-
- // Used by cluster to replicate transaction status.
- void accept(TxOpConstVisitor& v) const;
};
}
}
diff --git a/cpp/src/qpid/broker/TxOp.h b/cpp/src/qpid/broker/TxOp.h
index a8fa1c2621..775efc92f7 100644
--- a/cpp/src/qpid/broker/TxOp.h
+++ b/cpp/src/qpid/broker/TxOp.h
@@ -21,7 +21,6 @@
#ifndef _TxOp_
#define _TxOp_
-#include "qpid/broker/TxOpVisitor.h"
#include "qpid/broker/TransactionalStore.h"
#include <boost/shared_ptr.hpp>
@@ -36,8 +35,6 @@ namespace qpid {
virtual void commit() throw() = 0;
virtual void rollback() throw() = 0;
virtual ~TxOp(){}
-
- virtual void accept(TxOpConstVisitor&) const = 0;
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/TxOpVisitor.h b/cpp/src/qpid/broker/TxOpVisitor.h
index ceb894896e..e69de29bb2 100644
--- a/cpp/src/qpid/broker/TxOpVisitor.h
+++ b/cpp/src/qpid/broker/TxOpVisitor.h
@@ -1,97 +0,0 @@
-#ifndef QPID_BROKER_TXOPVISITOR_H
-#define QPID_BROKER_TXOPVISITOR_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-namespace qpid {
-namespace broker {
-
-class DtxAck;
-class RecoveredDequeue;
-class RecoveredEnqueue;
-class TxAccept;
-class TxPublish;
-
-/**
- * Visitor for TxOp familly of classes.
- */
-struct TxOpConstVisitor
-{
- virtual ~TxOpConstVisitor() {}
- virtual void operator()(const DtxAck&) = 0;
- virtual void operator()(const RecoveredDequeue&) = 0;
- virtual void operator()(const RecoveredEnqueue&) = 0;
- virtual void operator()(const TxAccept&) = 0;
- virtual void operator()(const TxPublish&) = 0;
-};
-
-}} // namespace qpid::broker
-
-#endif /*!QPID_BROKER_TXOPVISITOR_H*/
-#ifndef QPID_BROKER_TXOPVISITOR_H
-#define QPID_BROKER_TXOPVISITOR_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-namespace qpid {
-namespace broker {
-
-class DtxAck;
-class RecoveredDequeue;
-class RecoveredEnqueue;
-class TxAccept;
-class TxPublish;
-
-/**
- * Visitor for TxOp familly of classes.
- */
-struct TxOpConstVisitor
-{
- virtual ~TxOpConstVisitor() {}
- virtual void operator()(const DtxAck&) = 0;
- virtual void operator()(const RecoveredDequeue&) = 0;
- virtual void operator()(const RecoveredEnqueue&) = 0;
- virtual void operator()(const TxAccept&) = 0;
- virtual void operator()(const TxPublish&) = 0;
-};
-
-}} // namespace qpid::broker
-
-#endif /*!QPID_BROKER_TXOPVISITOR_H*/
diff --git a/cpp/src/qpid/broker/TxPublish.cpp b/cpp/src/qpid/broker/TxPublish.cpp
index 9c2cf4a467..e69de29bb2 100644
--- a/cpp/src/qpid/broker/TxPublish.cpp
+++ b/cpp/src/qpid/broker/TxPublish.cpp
@@ -1,111 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/log/Statement.h"
-#include "qpid/broker/TxPublish.h"
-#include "qpid/broker/Queue.h"
-
-using boost::intrusive_ptr;
-using namespace qpid::broker;
-
-TxPublish::TxPublish(intrusive_ptr<Message> _msg) : msg(_msg) {}
-
-bool TxPublish::prepare(TransactionContext* ctxt) throw()
-{
- try{
- while (!queues.empty()) {
- prepare(ctxt, queues.front());
- prepared.push_back(queues.front());
- queues.pop_front();
- }
- return true;
- }catch(const std::exception& e){
- QPID_LOG(error, "Failed to prepare: " << e.what());
- }catch(...){
- QPID_LOG(error, "Failed to prepare (unknown error)");
- }
- return false;
-}
-
-void TxPublish::commit() throw()
-{
- try {
- for_each(prepared.begin(), prepared.end(), Commit(msg));
- if (msg->isContentReleaseRequested()) {
- // NOTE: The log messages in this section are used for flow-to-disk testing (which checks the log for the
- // presence of these messages). Do not change these without also checking these tests.
- if (msg->isContentReleaseBlocked()) {
- QPID_LOG(debug, "Message id=\"" << msg->getProperties<qpid::framing::MessageProperties>()->getMessageId() << "\"; pid=0x" <<
- std::hex << msg->getPersistenceId() << std::dec << ": Content release blocked on commit");
- } else {
- msg->releaseContent();
- QPID_LOG(debug, "Message id=\"" << msg->getProperties<qpid::framing::MessageProperties>()->getMessageId() << "\"; pid=0x" <<
- std::hex << msg->getPersistenceId() << std::dec << ": Content released on commit");
- }
- }
- } catch (const std::exception& e) {
- QPID_LOG(error, "Failed to commit: " << e.what());
- } catch(...) {
- QPID_LOG(error, "Failed to commit (unknown error)");
- }
-}
-
-void TxPublish::rollback() throw()
-{
- try {
- for_each(prepared.begin(), prepared.end(), Rollback(msg));
- } catch (const std::exception& e) {
- QPID_LOG(error, "Failed to complete rollback: " << e.what());
- } catch(...) {
- QPID_LOG(error, "Failed to complete rollback (unknown error)");
- }
-
-}
-
-void TxPublish::deliverTo(const boost::shared_ptr<Queue>& queue){
- if (!queue->isLocal(msg)) {
- queues.push_back(queue);
- delivered = true;
- } else {
- QPID_LOG(debug, "Won't enqueue local message for " << queue->getName());
- }
-}
-
-void TxPublish::prepare(TransactionContext* ctxt, const boost::shared_ptr<Queue> queue)
-{
- queue->enqueue(ctxt, msg);
-}
-
-TxPublish::Commit::Commit(intrusive_ptr<Message>& _msg) : msg(_msg){}
-
-void TxPublish::Commit::operator()(const boost::shared_ptr<Queue>& queue){
- queue->process(msg);
-}
-
-TxPublish::Rollback::Rollback(intrusive_ptr<Message>& _msg) : msg(_msg){}
-
-void TxPublish::Rollback::operator()(const boost::shared_ptr<Queue>& queue){
- queue->enqueueAborted(msg);
-}
-
-uint64_t TxPublish::contentSize ()
-{
- return msg->contentSize ();
-}
diff --git a/cpp/src/qpid/broker/TxPublish.h b/cpp/src/qpid/broker/TxPublish.h
index dba7878af2..e69de29bb2 100644
--- a/cpp/src/qpid/broker/TxPublish.h
+++ b/cpp/src/qpid/broker/TxPublish.h
@@ -1,92 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#ifndef _TxPublish_
-#define _TxPublish_
-
-#include "qpid/broker/BrokerImportExport.h"
-#include "qpid/broker/Deliverable.h"
-#include "qpid/broker/Message.h"
-#include "qpid/broker/MessageStore.h"
-#include "qpid/broker/TxOp.h"
-
-#include <algorithm>
-#include <functional>
-#include <list>
-
-#include <boost/intrusive_ptr.hpp>
-
-namespace qpid {
-namespace broker {
-/**
- * Defines the behaviour for publish operations on a
- * transactional channel. Messages are routed through
- * exchanges when received but are not at that stage delivered
- * to the matching queues, rather the queues are held in an
- * instance of this class. On prepare() the message is marked
- * enqueued to the relevant queues in the MessagesStore. On
- * commit() the messages will be passed to the queue for
- * dispatch or to be added to the in-memory queue.
- */
-class QPID_BROKER_CLASS_EXTERN TxPublish : public TxOp, public Deliverable{
-
- class Commit{
- boost::intrusive_ptr<Message>& msg;
- public:
- Commit(boost::intrusive_ptr<Message>& msg);
- void operator()(const boost::shared_ptr<Queue>& queue);
- };
- class Rollback{
- boost::intrusive_ptr<Message>& msg;
- public:
- Rollback(boost::intrusive_ptr<Message>& msg);
- void operator()(const boost::shared_ptr<Queue>& queue);
- };
-
- boost::intrusive_ptr<Message> msg;
- std::list<boost::shared_ptr<Queue> > queues;
- std::list<boost::shared_ptr<Queue> > prepared;
-
- void prepare(TransactionContext* ctxt, boost::shared_ptr<Queue>);
-
- public:
- QPID_BROKER_EXTERN TxPublish(boost::intrusive_ptr<Message> msg);
- QPID_BROKER_EXTERN virtual bool prepare(TransactionContext* ctxt) throw();
- QPID_BROKER_EXTERN virtual void commit() throw();
- QPID_BROKER_EXTERN virtual void rollback() throw();
-
- virtual Message& getMessage() { return *msg; };
-
- QPID_BROKER_EXTERN virtual void deliverTo(const boost::shared_ptr<Queue>& queue);
-
- virtual ~TxPublish(){}
- virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); }
-
- QPID_BROKER_EXTERN uint64_t contentSize();
-
- boost::intrusive_ptr<Message> getMessage() const { return msg; }
- const std::list<boost::shared_ptr<Queue> >& getQueues() const { return queues; }
- const std::list<boost::shared_ptr<Queue> >& getPrepared() const { return prepared; }
-};
-}
-}
-
-
-#endif
diff --git a/cpp/src/qpid/broker/amqp_0_10/MessageTransfer.cpp b/cpp/src/qpid/broker/amqp_0_10/MessageTransfer.cpp
new file mode 100644
index 0000000000..cac4434c48
--- /dev/null
+++ b/cpp/src/qpid/broker/amqp_0_10/MessageTransfer.cpp
@@ -0,0 +1,373 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "MessageTransfer.h"
+#include "qpid/broker/MapHandler.h"
+#include "qpid/broker/Message.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/MessageProperties.h"
+#include "qpid/framing/DeliveryProperties.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/frame_functors.h"
+#include "qpid/framing/TypeFilter.h"
+#include "qpid/framing/SendContent.h"
+#include "qpid/log/Statement.h"
+
+using namespace qpid::framing;
+
+namespace qpid {
+namespace broker {
+namespace amqp_0_10 {
+namespace {
+const std::string QMF2("qmf2");
+const std::string PARTIAL("partial");
+}
+MessageTransfer::MessageTransfer() : frames(framing::SequenceNumber()), requiredCredit(0), cachedRequiredCredit(false) {}
+MessageTransfer::MessageTransfer(const framing::SequenceNumber& id) : frames(id), requiredCredit(0), cachedRequiredCredit(false) {}
+
+uint64_t MessageTransfer::getContentSize() const
+{
+ return frames.getContentSize();
+}
+
+std::string MessageTransfer::getAnnotationAsString(const std::string& key) const
+{
+ const qpid::framing::MessageProperties* mp = getProperties<qpid::framing::MessageProperties>();
+ if (mp && mp->hasApplicationHeaders()) {
+ return mp->getApplicationHeaders().getAsString(key);
+ } else {
+ return std::string();
+ }
+}
+std::string MessageTransfer::getPropertyAsString(const std::string& key) const { return getAnnotationAsString(key); }
+
+bool MessageTransfer::getTtl(uint64_t& result) const
+{
+ const qpid::framing::DeliveryProperties* dp = getProperties<qpid::framing::DeliveryProperties>();
+ if (dp && dp->hasTtl()) {
+ result = dp->getTtl();
+ return true;
+ } else {
+ return false;
+ }
+}
+bool MessageTransfer::hasExpiration() const
+{
+ const qpid::framing::DeliveryProperties* dp = getProperties<qpid::framing::DeliveryProperties>();
+ if (dp && dp->hasExpiration()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+uint8_t MessageTransfer::getPriority() const
+{
+ const qpid::framing::DeliveryProperties* dp = getProperties<qpid::framing::DeliveryProperties>();
+ if (dp && dp->hasPriority()) {
+ return dp->getPriority();
+ } else {
+ return 0;
+ }
+}
+
+std::string MessageTransfer::getExchangeName() const
+{
+ return getFrames().as<framing::MessageTransferBody>()->getDestination();
+}
+
+bool MessageTransfer::requiresAccept() const
+{
+ const framing::MessageTransferBody* b = getFrames().as<framing::MessageTransferBody>();
+ return b && b->getAcceptMode() == 0/*EXPLICIT == 0*/;
+}
+uint32_t MessageTransfer::getRequiredCredit() const
+{
+ if (cachedRequiredCredit) {
+ return requiredCredit;
+ } else {
+ qpid::framing::SumBodySize sum;
+ frames.map_if(sum, qpid::framing::TypeFilter2<qpid::framing::HEADER_BODY, qpid::framing::CONTENT_BODY>());
+ return sum.getSize();
+ }
+}
+void MessageTransfer::computeRequiredCredit()
+{
+ //add up payload for all header and content frames in the frameset
+ qpid::framing::SumBodySize sum;
+ frames.map_if(sum, qpid::framing::TypeFilter2<qpid::framing::HEADER_BODY, qpid::framing::CONTENT_BODY>());
+ requiredCredit = sum.getSize();
+ cachedRequiredCredit = true;
+}
+uint32_t MessageTransfer::getRequiredCredit(const qpid::broker::Message& msg)
+{
+ //TODO: may need to reflect annotations and other modifications in this also
+ return get(msg).getRequiredCredit();
+}
+
+qpid::framing::FrameSet& MessageTransfer::getFrames()
+{
+ return frames;
+}
+const qpid::framing::FrameSet& MessageTransfer::getFrames() const
+{
+ return frames;
+}
+void MessageTransfer::sendContent(framing::FrameHandler& out, uint16_t maxFrameSize) const
+{
+ qpid::framing::Count c;
+ frames.map_if(c, qpid::framing::TypeFilter<qpid::framing::CONTENT_BODY>());
+
+ qpid::framing::SendContent f(out, maxFrameSize, c.getCount());
+ frames.map_if(f, qpid::framing::TypeFilter<qpid::framing::CONTENT_BODY>());
+}
+
+class SendHeader
+{
+ public:
+ SendHeader(FrameHandler& h, bool r, uint64_t t, uint64_t ts, const qpid::types::Variant::Map& a) : handler(h), redelivered(r), ttl(t), timestamp(ts), annotations(a) {}
+ void operator()(const AMQFrame& f)
+ {
+ AMQFrame copy = f;
+ if (redelivered || ttl || timestamp || annotations.size()) {
+ copy.cloneBody();
+ if (annotations.size()) {
+ MessageProperties* props =
+ copy.castBody<AMQHeaderBody>()->get<MessageProperties>(true);
+ for (qpid::types::Variant::Map::const_iterator i = annotations.begin();
+ i != annotations.end(); ++i) {
+ props->getApplicationHeaders().setString(i->first, i->second.asString());
+ }
+ }
+ if (redelivered || ttl || timestamp) {
+ DeliveryProperties* dp =
+ copy.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true);
+ if (ttl) dp->setTtl(ttl);
+ if (redelivered) dp->setRedelivered(redelivered);
+ if (timestamp) dp->setTimestamp(timestamp);
+ }
+ }
+ handler.handle(copy);
+ }
+ private:
+ FrameHandler& handler;
+ bool redelivered;
+ uint64_t ttl;
+ uint64_t timestamp;
+ const qpid::types::Variant::Map& annotations;
+};
+
+void MessageTransfer::sendHeader(framing::FrameHandler& out, uint16_t /*maxFrameSize*/,
+ bool redelivered, uint64_t ttl, uint64_t timestamp,
+ const qpid::types::Variant::Map& annotations) const
+{
+ SendHeader f(out, redelivered, ttl, timestamp, annotations);
+ frames.map_if(f, TypeFilter<HEADER_BODY>());
+}
+bool MessageTransfer::isImmediateDeliveryRequired(const qpid::broker::Message& /*message*/)
+{
+ return false;//TODO
+}
+
+const framing::SequenceNumber& MessageTransfer::getCommandId() const { return frames.getId(); }
+
+std::string MessageTransfer::getRoutingKey() const
+{
+ const qpid::framing::DeliveryProperties* dp = getProperties<qpid::framing::DeliveryProperties>();
+ if (dp && dp->hasRoutingKey()) {
+ return dp->getRoutingKey();
+ } else {
+ return std::string();
+ }
+}
+bool MessageTransfer::isPersistent() const
+{
+ const qpid::framing::DeliveryProperties* dp = getProperties<qpid::framing::DeliveryProperties>();
+ if (dp && dp->hasDeliveryMode()) {
+ return dp->getDeliveryMode() == 2;
+ } else {
+ return false;
+ }
+}
+
+std::string MessageTransfer::getContent() const
+{
+ return frames.getContent();
+}
+
+void MessageTransfer::decodeHeader(framing::Buffer& buffer)
+{
+ AMQFrame method;
+ method.decode(buffer);
+ frames.append(method);
+
+ AMQFrame header;
+ header.decode(buffer);
+ frames.append(header);
+}
+void MessageTransfer::decodeContent(framing::Buffer& buffer)
+{
+ if (buffer.available()) {
+ //get the data as a string and set that as the content
+ //body on a frame then add that frame to the frameset
+ AMQFrame frame((AMQContentBody()));
+ frame.castBody<AMQContentBody>()->decode(buffer, buffer.available());
+ frame.setFirstSegment(false);
+ frames.append(frame);
+ } else {
+ //adjust header flags
+ MarkLastSegment f;
+ frames.map_if(f, TypeFilter<HEADER_BODY>());
+ }
+}
+
+void MessageTransfer::encode(framing::Buffer& buffer) const
+{
+ //encode method and header frames
+ EncodeFrame f1(buffer);
+ frames.map_if(f1, TypeFilter2<METHOD_BODY, HEADER_BODY>());
+
+ //then encode the payload of each content frame
+ framing::EncodeBody f2(buffer);
+ frames.map_if(f2, TypeFilter<CONTENT_BODY>());
+}
+
+void MessageTransfer::encodeContent(framing::Buffer& buffer) const
+{
+ //encode the payload of each content frame
+ EncodeBody f2(buffer);
+ frames.map_if(f2, TypeFilter<CONTENT_BODY>());
+}
+
+uint32_t MessageTransfer::encodedSize() const
+{
+ return encodedHeaderSize() + encodedContentSize();
+}
+
+uint32_t MessageTransfer::encodedContentSize() const
+{
+ return frames.getContentSize();
+}
+
+uint32_t MessageTransfer::encodedHeaderSize() const
+{
+ //add up the size for all method and header frames in the frameset
+ SumFrameSize sum;
+ frames.map_if(sum, TypeFilter2<METHOD_BODY, HEADER_BODY>());
+ return sum.getSize();
+}
+
+bool MessageTransfer::isQMFv2() const
+{
+ const framing::MessageProperties* props = getProperties<framing::MessageProperties>();
+ return props && props->getAppId() == QMF2 && props->hasApplicationHeaders();
+}
+
+bool MessageTransfer::isQMFv2(const qpid::broker::Message& message)
+{
+ const MessageTransfer* transfer = dynamic_cast<const MessageTransfer*>(&message.getEncoding());
+ return transfer && transfer->isQMFv2();
+}
+
+bool MessageTransfer::isLastQMFResponse(const std::string correlation) const
+{
+ const framing::MessageProperties* props = getProperties<framing::MessageProperties>();
+ return props && props->getCorrelationId() == correlation
+ && props->hasApplicationHeaders() && !props->getApplicationHeaders().isSet(PARTIAL);
+}
+
+bool MessageTransfer::isLastQMFResponse(const qpid::broker::Message& message, const std::string correlation)
+{
+ const MessageTransfer* transfer = dynamic_cast<const MessageTransfer*>(&message.getEncoding());
+ return transfer && transfer->isLastQMFResponse(correlation);
+}
+
+
+void MessageTransfer::processProperties(qpid::broker::MapHandler& handler) const
+{
+ const qpid::framing::MessageProperties* mp = getProperties<qpid::framing::MessageProperties>();
+ if (mp && mp->hasApplicationHeaders()) {
+ const FieldTable ft = mp->getApplicationHeaders();
+ for (FieldTable::const_iterator i = ft.begin(); i != ft.end(); ++i) {
+ qpid::broker::MapHandler::CharSequence key;
+ key.data = i->first.data();
+ key.size = i->first.size();
+ FieldTable::ValuePtr v = i->second;
+ //TODO: something more sophisticated...
+ if (v->empty()) {
+ handler.handleVoid(key);
+ } else if (v->convertsTo<uint64_t>()) {
+ handler.handleUint64(key, v->get<uint64_t>());
+ } else if (v->convertsTo<int64_t>()) {
+ handler.handleInt64(key, v->get<int64_t>());
+ } else if (v->convertsTo<std::string>()) {
+ std::string s = v->get<std::string>();
+ qpid::broker::MapHandler::CharSequence value;
+ value.data = s.data();
+ value.size = s.size();
+ qpid::broker::MapHandler::CharSequence encoding; encoding.size = 0; encoding.data = 0;
+ handler.handleString(key, value, encoding);
+ } else {
+ QPID_LOG(debug, "Unhandled key!" << *v);
+ }
+ }
+ }
+}
+
+std::string MessageTransfer::getUserId() const
+{
+ const qpid::framing::MessageProperties* mp = getProperties<qpid::framing::MessageProperties>();
+ if (mp && mp->hasUserId()) return mp->getUserId();
+ else return std::string();
+
+}
+MessageTransfer::MessageTransfer(const qpid::framing::FrameSet& f) : frames(f), requiredCredit(0) {}
+
+boost::intrusive_ptr<PersistableMessage> MessageTransfer::merge(const std::map<std::string, qpid::types::Variant>& annotations) const
+{
+ boost::intrusive_ptr<MessageTransfer> clone(new MessageTransfer(this->frames));
+ qpid::framing::MessageProperties* mp = clone->frames.getHeaders()->get<qpid::framing::MessageProperties>(true);
+ for (qpid::types::Variant::Map::const_iterator i = annotations.begin(); i != annotations.end(); ++i) {
+ mp->getApplicationHeaders().setString(i->first, i->second);
+ }
+ return clone;
+}
+}
+// qpid::broker namespace, TODO: move these elsewhere!
+void encode(const Message& in, std::string& out)
+{
+ const amqp_0_10::MessageTransfer& transfer = amqp_0_10::MessageTransfer::get(in);
+ uint32_t size = transfer.encodedSize();
+ std::vector<char> data(size);
+ qpid::framing::Buffer buffer(&(data[0]), size);
+ transfer.encode(buffer);
+ buffer.reset();
+ buffer.getRawData(out, size);
+}
+void decode(const std::string& in, Message& out)
+{
+ boost::intrusive_ptr<amqp_0_10::MessageTransfer> transfer(new amqp_0_10::MessageTransfer);
+ qpid::framing::Buffer buffer(const_cast<char*>(in.data()), in.size());
+ transfer->decodeHeader(buffer);
+ transfer->decodeContent(buffer);
+ out = Message(transfer, transfer);
+}
+
+}} // namespace qpid::broker::amqp_0_10
diff --git a/cpp/src/qpid/broker/amqp_0_10/MessageTransfer.h b/cpp/src/qpid/broker/amqp_0_10/MessageTransfer.h
new file mode 100644
index 0000000000..590e389518
--- /dev/null
+++ b/cpp/src/qpid/broker/amqp_0_10/MessageTransfer.h
@@ -0,0 +1,133 @@
+#ifndef QPID_BROKER_AMQP_0_10_MESSAGETRANSFER_H
+#define QPID_BROKER_AMQP_0_10_MESSAGETRANSFER_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#include "qpid/broker/BrokerImportExport.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/broker/Message.h"
+#include "qpid/broker/PersistableMessage.h"
+#include "qpid/types/Variant.h"
+
+namespace qpid {
+namespace broker {
+class Queue;
+namespace amqp_0_10 {
+
+/**
+ *
+ */
+class MessageTransfer : public qpid::broker::Message::Encoding, public qpid::broker::PersistableMessage
+{
+ public:
+ QPID_BROKER_EXTERN MessageTransfer();
+ QPID_BROKER_EXTERN MessageTransfer(const qpid::framing::SequenceNumber&);
+
+ std::string getRoutingKey() const;
+ bool isPersistent() const;
+ uint8_t getPriority() const;
+ uint64_t getContentSize() const;
+ std::string getPropertyAsString(const std::string& key) const;
+ std::string getAnnotationAsString(const std::string& key) const;
+ bool getTtl(uint64_t&) const;
+ bool hasExpiration() const;
+ std::string getExchangeName() const;
+ void processProperties(MapHandler&) const;
+ std::string getUserId() const;
+
+ bool requiresAccept() const;
+ const qpid::framing::SequenceNumber& getCommandId() const;
+ QPID_BROKER_EXTERN qpid::framing::FrameSet& getFrames();
+ QPID_BROKER_EXTERN const qpid::framing::FrameSet& getFrames() const;
+
+ template <class T> const T* getProperties() const {
+ const qpid::framing::AMQHeaderBody* p = frames.getHeaders();
+ return p->get<T>();
+ }
+
+ template <class T> const T* hasProperties() const {
+ const qpid::framing::AMQHeaderBody* p = frames.getHeaders();
+ return p->get<T>();
+ }
+ template <class T> const T* getMethod() const {
+ return frames.as<T>();
+ }
+
+ template <class T> T* getMethod() {
+ return frames.as<T>();
+ }
+
+ template <class T> bool isA() const {
+ return frames.isA<T>();
+ }
+
+ template <class T> void eraseProperties() {
+ qpid::framing::AMQHeaderBody* p = frames.getHeaders();
+ p->erase<T>();
+ }
+ std::string getContent() const;
+ uint32_t getRequiredCredit() const;
+ void computeRequiredCredit();
+
+ void clearApplicationHeadersFlag();
+ void sendContent(framing::FrameHandler& out, uint16_t maxFrameSize) const;
+ void sendHeader(framing::FrameHandler& out, uint16_t maxFrameSize, bool redelivered, uint64_t ttl, uint64_t timestamp, const qpid::types::Variant::Map& annotations) const;
+
+ void decodeHeader(framing::Buffer& buffer);
+ void decodeContent(framing::Buffer& buffer);
+
+ void encode(framing::Buffer& buffer) const;
+ uint32_t encodedSize() const;
+
+ /**
+ * @returns the size of the buffer needed to encode the
+ * 'header' of this message (not just the header frame,
+ * but other meta data e.g.routing key and exchange)
+ */
+ uint32_t encodedHeaderSize() const;
+ boost::intrusive_ptr<PersistableMessage> merge(const std::map<std::string, qpid::types::Variant>& annotations) const;
+
+ QPID_BROKER_EXTERN bool isQMFv2() const;
+ QPID_BROKER_EXTERN bool isLastQMFResponse(const std::string correlation) const;
+
+ static bool isImmediateDeliveryRequired(const qpid::broker::Message& message);
+ static uint32_t getRequiredCredit(const qpid::broker::Message&);
+ static MessageTransfer& get(qpid::broker::Message& message) {
+ return *dynamic_cast<MessageTransfer*>(&message.getEncoding());
+ }
+ static const MessageTransfer& get(const qpid::broker::Message& message) {
+ return *dynamic_cast<const MessageTransfer*>(&message.getEncoding());
+ }
+ QPID_BROKER_EXTERN static bool isQMFv2(const qpid::broker::Message& message);
+ QPID_BROKER_EXTERN static bool isLastQMFResponse(const qpid::broker::Message& message, const std::string correlation);
+ private:
+ qpid::framing::FrameSet frames;
+ uint32_t requiredCredit;
+ bool cachedRequiredCredit;
+
+ MessageTransfer(const qpid::framing::FrameSet&);
+ void encodeHeader(framing::Buffer& buffer) const;
+ uint32_t encodedContentSize() const;
+ void encodeContent(framing::Buffer& buffer) const;
+};
+}}} // namespace qpid::broker::amqp_0_10
+
+#endif /*!QPID_BROKER_AMQP_0_10_MESSAGETRANSFER_H*/
diff --git a/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp b/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp
index fb59d058f8..420e04e832 100644
--- a/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp
+++ b/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp
@@ -281,7 +281,7 @@ void SslProtocolFactory::established(sys::Poller::shared_ptr poller,
boost::bind(&AsynchIOHandler::idle, async, _1));
}
- async->init(aio, brokerTimer, maxNegotiateTime, 4);
+ async->init(aio, brokerTimer, maxNegotiateTime);
aio->start(poller);
}
diff --git a/cpp/src/qpid/client/SslConnector.cpp b/cpp/src/qpid/client/SslConnector.cpp
index 4c6fadd28a..c2081a88f2 100644
--- a/cpp/src/qpid/client/SslConnector.cpp
+++ b/cpp/src/qpid/client/SslConnector.cpp
@@ -38,7 +38,6 @@
#include "qpid/Msg.h"
#include <iostream>
-#include <map>
#include <boost/bind.hpp>
#include <boost/format.hpp>
@@ -54,53 +53,29 @@ using boost::str;
class SslConnector : public Connector
{
- struct Buff;
-
- /** Batch up frames for writing to aio. */
- class Writer : public framing::FrameHandler {
- typedef sys::ssl::SslIOBufferBase BufferBase;
- typedef std::vector<framing::AMQFrame> Frames;
-
- const uint16_t maxFrameSize;
- sys::Mutex lock;
- sys::ssl::SslIO* aio;
- BufferBase* buffer;
- Frames frames;
- size_t lastEof; // Position after last EOF in frames
- framing::Buffer encode;
- size_t framesEncoded;
- std::string identifier;
- Bounds* bounds;
-
- void writeOne();
- void newBuffer();
-
- public:
-
- Writer(uint16_t maxFrameSize, Bounds*);
- ~Writer();
- void init(std::string id, sys::ssl::SslIO*);
- void handle(framing::AMQFrame&);
- void write(sys::ssl::SslIO&);
- };
+ typedef std::deque<framing::AMQFrame> Frames;
const uint16_t maxFrameSize;
+
+ sys::Mutex lock;
+ Frames frames;
+ size_t lastEof; // Position after last EOF in frames
+ uint64_t currentSize;
+ Bounds* bounds;
+
framing::ProtocolVersion version;
bool initiated;
- SecuritySettings securitySettings;
-
- sys::Mutex closedLock;
bool closed;
sys::ShutdownHandler* shutdownHandler;
framing::InputHandler* input;
- Writer writer;
-
sys::ssl::SslSocket socket;
sys::ssl::SslIO* aio;
+ std::string identifier;
Poller::shared_ptr poller;
+ SecuritySettings securitySettings;
~SslConnector();
@@ -110,10 +85,7 @@ class SslConnector : public Connector
void eof(qpid::sys::ssl::SslIO&);
void disconnected(qpid::sys::ssl::SslIO&);
- std::string identifier;
-
void connect(const std::string& host, const std::string& port);
- void init();
void close();
void send(framing::AMQFrame& frame);
void abort() {} // TODO: Need to fix for heartbeat timeouts to work
@@ -126,17 +98,16 @@ class SslConnector : public Connector
const SecuritySettings* getSecuritySettings();
void socketClosed(qpid::sys::ssl::SslIO&, const qpid::sys::ssl::SslSocket&);
+ size_t decode(const char* buffer, size_t size);
+ size_t encode(const char* buffer, size_t size);
+ bool canEncode();
+
public:
SslConnector(Poller::shared_ptr p, framing::ProtocolVersion pVersion,
const ConnectionSettings&,
ConnectionImpl*);
};
-struct SslConnector::Buff : public SslIO::BufferBase {
- Buff(size_t size) : SslIO::BufferBase(new char[size], size) {}
- ~Buff() { delete [] bytes;}
-};
-
// Static constructor which registers connector here
namespace {
Connector* create(Poller::shared_ptr p, framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) {
@@ -170,12 +141,14 @@ SslConnector::SslConnector(Poller::shared_ptr p,
const ConnectionSettings& settings,
ConnectionImpl* cimpl)
: maxFrameSize(settings.maxFrameSize),
+ lastEof(0),
+ currentSize(0),
+ bounds(cimpl),
version(ver),
initiated(false),
closed(true),
shutdownHandler(0),
input(0),
- writer(maxFrameSize, cimpl),
aio(0),
poller(p)
{
@@ -192,7 +165,7 @@ SslConnector::~SslConnector() {
}
void SslConnector::connect(const std::string& host, const std::string& port){
- Mutex::ScopedLock l(closedLock);
+ Mutex::ScopedLock l(lock);
assert(closed);
try {
socket.connect(host, port);
@@ -201,7 +174,6 @@ void SslConnector::connect(const std::string& host, const std::string& port){
throw TransportFailure(e.what());
}
- identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
closed = false;
aio = new SslIO(socket,
boost::bind(&SslConnector::readbuff, this, _1, _2),
@@ -210,21 +182,16 @@ void SslConnector::connect(const std::string& host, const std::string& port){
boost::bind(&SslConnector::socketClosed, this, _1, _2),
0, // nobuffs
boost::bind(&SslConnector::writebuff, this, _1));
- writer.init(identifier, aio);
-}
-void SslConnector::init(){
- Mutex::ScopedLock l(closedLock);
+ aio->createBuffers(maxFrameSize);
+ identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress());
ProtocolInitiation init(version);
writeDataBlock(init);
- for (int i = 0; i < 32; i++) {
- aio->queueReadBuffer(new Buff(maxFrameSize));
- }
aio->start(poller);
}
void SslConnector::close() {
- Mutex::ScopedLock l(closedLock);
+ Mutex::ScopedLock l(lock);
if (!closed) {
closed = true;
if (aio)
@@ -260,76 +227,110 @@ const std::string& SslConnector::getIdentifier() const {
}
void SslConnector::send(AMQFrame& frame) {
- writer.handle(frame);
-}
-
-SslConnector::Writer::Writer(uint16_t s, Bounds* b) : maxFrameSize(s), aio(0), buffer(0), lastEof(0), bounds(b)
-{
-}
-
-SslConnector::Writer::~Writer() { delete buffer; }
-
-void SslConnector::Writer::init(std::string id, sys::ssl::SslIO* a) {
- Mutex::ScopedLock l(lock);
- identifier = id;
- aio = a;
- newBuffer();
-}
-void SslConnector::Writer::handle(framing::AMQFrame& frame) {
+ bool notifyWrite = false;
+ {
Mutex::ScopedLock l(lock);
frames.push_back(frame);
- if (frame.getEof() || (bounds && bounds->getCurrentSize() >= maxFrameSize)) {
+ //only ask to write if this is the end of a frameset or if we
+ //already have a buffers worth of data
+ currentSize += frame.encodedSize();
+ if (frame.getEof()) {
lastEof = frames.size();
- aio->notifyPendingWrite();
+ notifyWrite = true;
+ } else {
+ notifyWrite = (currentSize >= maxFrameSize);
+ }
+ /*
+ NOTE: Moving the following line into this mutex block
+ is a workaround for BZ 570168, in which the test
+ testConcurrentSenders causes a hang about 1.5%
+ of the time. ( To see the hang much more frequently
+ leave this line out of the mutex block, and put a
+ small usleep just before it.)
+
+ TODO mgoulish - fix the underlying cause and then
+ move this call back outside the mutex.
+ */
+ if (notifyWrite && !closed) aio->notifyPendingWrite();
}
- QPID_LOG(trace, "SENT [" << identifier << "]: " << frame);
}
-void SslConnector::Writer::writeOne() {
- assert(buffer);
- framesEncoded = 0;
+void SslConnector::writebuff(SslIO& /*aio*/)
+{
+ // It's possible to be disconnected and be writable
+ if (closed)
+ return;
- buffer->dataStart = 0;
- buffer->dataCount = encode.getPosition();
- aio->queueWrite(buffer);
- newBuffer();
-}
+ if (!canEncode()) {
+ return;
+ }
-void SslConnector::Writer::newBuffer() {
- buffer = aio->getQueuedBuffer();
- if (!buffer) buffer = new Buff(maxFrameSize);
- encode = framing::Buffer(buffer->bytes, buffer->byteCount);
- framesEncoded = 0;
+ SslIO::BufferBase* buffer = aio->getQueuedBuffer();
+ if (buffer) {
+
+ size_t encoded = encode(buffer->bytes, buffer->byteCount);
+
+ buffer->dataStart = 0;
+ buffer->dataCount = encoded;
+ aio->queueWrite(buffer);
+ }
}
// Called in IO thread.
-void SslConnector::Writer::write(sys::ssl::SslIO&) {
+bool SslConnector::canEncode()
+{
Mutex::ScopedLock l(lock);
- assert(buffer);
+ //have at least one full frameset or a whole buffers worth of data
+ return lastEof || currentSize >= maxFrameSize;
+}
+
+// Called in IO thread.
+size_t SslConnector::encode(const char* buffer, size_t size)
+{
+ framing::Buffer out(const_cast<char*>(buffer), size);
size_t bytesWritten(0);
- for (size_t i = 0; i < lastEof; ++i) {
- AMQFrame& frame = frames[i];
- uint32_t size = frame.encodedSize();
- if (size > encode.available()) writeOne();
- assert(size <= encode.available());
- frame.encode(encode);
- ++framesEncoded;
- bytesWritten += size;
+ {
+ Mutex::ScopedLock l(lock);
+ while (!frames.empty() && out.available() >= frames.front().encodedSize() ) {
+ frames.front().encode(out);
+ QPID_LOG(trace, "SENT [" << identifier << "]: " << frames.front());
+ frames.pop_front();
+ if (lastEof) --lastEof;
+ }
+ bytesWritten = size - out.available();
+ currentSize -= bytesWritten;
}
- frames.erase(frames.begin(), frames.begin()+lastEof);
- lastEof = 0;
if (bounds) bounds->reduce(bytesWritten);
- if (encode.getPosition() > 0) writeOne();
+ return bytesWritten;
}
-void SslConnector::readbuff(SslIO& aio, SslIO::BufferBase* buff) {
- framing::Buffer in(buff->bytes+buff->dataStart, buff->dataCount);
+void SslConnector::readbuff(SslIO& aio, SslIO::BufferBase* buff)
+{
+ int32_t decoded = decode(buff->bytes+buff->dataStart, buff->dataCount);
+ // TODO: unreading needs to go away, and when we can cope
+ // with multiple sub-buffers in the general buffer scheme, it will
+ if (decoded < buff->dataCount) {
+ // Adjust buffer for used bytes and then "unread them"
+ buff->dataStart += decoded;
+ buff->dataCount -= decoded;
+ aio.unread(buff);
+ } else {
+ // Give whole buffer back to aio subsystem
+ aio.queueReadBuffer(buff);
+ }
+}
+size_t SslConnector::decode(const char* buffer, size_t size)
+{
+ framing::Buffer in(const_cast<char*>(buffer), size);
if (!initiated) {
framing::ProtocolInitiation protocolInit;
if (protocolInit.decode(in)) {
- //TODO: check the version is correct
QPID_LOG(debug, "RECV [" << identifier << "]: INIT(" << protocolInit << ")");
+ if(!(protocolInit==version)){
+ throw Exception(QPID_MSG("Unsupported version: " << protocolInit
+ << " supported version " << version));
+ }
}
initiated = true;
}
@@ -338,25 +339,12 @@ void SslConnector::readbuff(SslIO& aio, SslIO::BufferBase* buff) {
QPID_LOG(trace, "RECV [" << identifier << "]: " << frame);
input->received(frame);
}
- // TODO: unreading needs to go away, and when we can cope
- // with multiple sub-buffers in the general buffer scheme, it will
- if (in.available() != 0) {
- // Adjust buffer for used bytes and then "unread them"
- buff->dataStart += buff->dataCount-in.available();
- buff->dataCount = in.available();
- aio.unread(buff);
- } else {
- // Give whole buffer back to aio subsystem
- aio.queueReadBuffer(buff);
- }
-}
-
-void SslConnector::writebuff(SslIO& aio_) {
- writer.write(aio_);
+ return size - in.available();
}
void SslConnector::writeDataBlock(const AMQDataBlock& data) {
- SslIO::BufferBase* buff = new Buff(maxFrameSize);
+ SslIO::BufferBase* buff = aio->getQueuedBuffer();
+ assert(buff);
framing::Buffer out(buff->bytes, buff->byteCount);
data.encode(out);
buff->dataCount = data.encodedSize();
diff --git a/cpp/src/qpid/client/SubscriptionManagerImpl.cpp b/cpp/src/qpid/client/SubscriptionManagerImpl.cpp
index 7dead112e5..44f81776c0 100644
--- a/cpp/src/qpid/client/SubscriptionManagerImpl.cpp
+++ b/cpp/src/qpid/client/SubscriptionManagerImpl.cpp
@@ -28,6 +28,7 @@
#include <qpid/client/Session.h>
#include <qpid/client/MessageListener.h>
#include <qpid/framing/Uuid.h>
+#include <qpid/log/Statement.h>
#include <set>
#include <sstream>
@@ -167,6 +168,15 @@ void SubscriptionManagerImpl::setFlowControl(const std::string& name, uint32_t m
setFlowControl(name, FlowControl(messages, bytes, window));
}
+AutoCancel::AutoCancel(SubscriptionManager& sm_, const std::string& tag_) : sm(sm_), tag(tag_) {}
+AutoCancel::~AutoCancel() {
+ try {
+ sm.cancel(tag);
+ } catch (const qpid::Exception& e) {
+ QPID_LOG(info, "Exception in AutoCancel destructor: " << e.what());
+ }
+}
+
}} // namespace qpid::client
diff --git a/cpp/src/qpid/client/TCPConnector.cpp b/cpp/src/qpid/client/TCPConnector.cpp
index 1dd951d339..a5c6465bad 100644
--- a/cpp/src/qpid/client/TCPConnector.cpp
+++ b/cpp/src/qpid/client/TCPConnector.cpp
@@ -46,11 +46,6 @@ using namespace qpid::framing;
using boost::format;
using boost::str;
-struct TCPConnector::Buff : public AsynchIO::BufferBase {
- Buff(size_t size) : AsynchIO::BufferBase(new char[size], size) {}
- ~Buff() { delete [] bytes;}
-};
-
// Static constructor which registers connector here
namespace {
Connector* create(Poller::shared_ptr p, framing::ProtocolVersion v, const ConnectionSettings& s, ConnectionImpl* c) {
@@ -118,9 +113,8 @@ void TCPConnector::connected(const Socket&) {
void TCPConnector::start(sys::AsynchIO* aio_) {
aio = aio_;
- for (int i = 0; i < 4; i++) {
- aio->queueReadBuffer(new Buff(maxFrameSize));
- }
+
+ aio->createBuffers(maxFrameSize);
identifier = str(format("[%1%]") % socket.getFullAddress());
}
@@ -226,15 +220,19 @@ void TCPConnector::writebuff(AsynchIO& /*aio*/)
return;
Codec* codec = securityLayer.get() ? (Codec*) securityLayer.get() : (Codec*) this;
- if (codec->canEncode()) {
- std::auto_ptr<AsynchIO::BufferBase> buffer = std::auto_ptr<AsynchIO::BufferBase>(aio->getQueuedBuffer());
- if (!buffer.get()) buffer = std::auto_ptr<AsynchIO::BufferBase>(new Buff(maxFrameSize));
+
+ if (!codec->canEncode()) {
+ return;
+ }
+
+ AsynchIO::BufferBase* buffer = aio->getQueuedBuffer();
+ if (buffer) {
size_t encoded = codec->encode(buffer->bytes, buffer->byteCount);
buffer->dataStart = 0;
buffer->dataCount = encoded;
- aio->queueWrite(buffer.release());
+ aio->queueWrite(buffer);
}
}
@@ -307,6 +305,7 @@ size_t TCPConnector::decode(const char* buffer, size_t size)
void TCPConnector::writeDataBlock(const AMQDataBlock& data) {
AsynchIO::BufferBase* buff = aio->getQueuedBuffer();
+ assert(buff);
framing::Buffer out(buff->bytes, buff->byteCount);
data.encode(out);
buff->dataCount = data.encodedSize();
diff --git a/cpp/src/qpid/client/TCPConnector.h b/cpp/src/qpid/client/TCPConnector.h
index c87d544816..c0bc26028d 100644
--- a/cpp/src/qpid/client/TCPConnector.h
+++ b/cpp/src/qpid/client/TCPConnector.h
@@ -50,7 +50,6 @@ namespace client {
class TCPConnector : public Connector, public sys::Codec
{
typedef std::deque<framing::AMQFrame> Frames;
- struct Buff;
const uint16_t maxFrameSize;
diff --git a/cpp/src/qpid/cluster/Cluster.cpp b/cpp/src/qpid/cluster/Cluster.cpp
deleted file mode 100644
index 34aaf3d341..0000000000
--- a/cpp/src/qpid/cluster/Cluster.cpp
+++ /dev/null
@@ -1,1294 +0,0 @@
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/**
- * <h1>CLUSTER IMPLEMENTATION OVERVIEW</h1>
- *
- * The cluster works on the principle that if all members of the
- * cluster receive identical input, they will all produce identical
- * results. cluster::Connections intercept data received from clients
- * and multicast it via CPG. The data is processed (passed to the
- * broker::Connection) only when it is received from CPG in cluster
- * order. Each cluster member has Connection objects for directly
- * connected clients and "shadow" Connection objects for connections
- * to other members.
- *
- * This assumes that all broker actions occur deterministically in
- * response to data arriving on client connections. There are two
- * situations where this assumption fails:
- * - sending data in response to polling local connections for writabiliy.
- * - taking actions based on a timer or timestamp comparison.
- *
- * IMPORTANT NOTE: any time code is added to the broker that uses timers,
- * the cluster may need to be updated to take account of this.
- *
- *
- * USE OF TIMESTAMPS IN THE BROKER
- *
- * The following are the current areas where broker uses timers or timestamps:
- *
- * - Producer flow control: broker::SemanticState uses
- * connection::getClusterOrderOutput. a FrameHandler that sends
- * frames to the client via the cluster. Used by broker::SessionState
- *
- * - QueueCleaner, Message TTL: uses ExpiryPolicy, which is
- * implemented by cluster::ExpiryPolicy.
- *
- * - Connection heartbeat: sends connection controls, not part of
- * session command counting so OK to ignore.
- *
- * - LinkRegistry: only cluster elder is ever active for links.
- *
- * - management::ManagementBroker: uses MessageHandler supplied by cluster
- * to send messages to the broker via the cluster.
- *
- * cluster::ExpiryPolicy uses cluster time.
- *
- * ClusterTimer implements periodic timed events in the cluster context.
- * Used for:
- * - periodic management events.
- * - DTX transaction timeouts.
- *
- * <h1>CLUSTER PROTOCOL OVERVIEW</h1>
- *
- * Messages sent to/from CPG are called Events.
- *
- * An Event carries a ConnectionId, which includes a MemberId and a
- * connection number.
- *
- * Events are either
- * - Connection events: non-0 connection number and are associated with a connection.
- * - Cluster Events: 0 connection number, are not associated with a connection.
- *
- * Events are further categorized as:
- * - Control: carries method frame(s) that affect cluster behavior.
- * - Data: carries raw data received from a client connection.
- *
- * The cluster defines extensions to the AMQP command set in ../../../xml/cluster.xml
- * which defines two classes:
- * - cluster: cluster control information.
- * - cluster.connection: control information for a specific connection.
- *
- * The following combinations are legal:
- * - Data frames carrying connection data.
- * - Cluster control events carrying cluster commands.
- * - Connection control events carrying cluster.connection commands.
- * - Connection control events carrying non-cluster frames: frames sent to the client.
- * e.g. flow-control frames generated on a timer.
- *
- * <h1>CLUSTER INITIALIZATION OVERVIEW</h1>
- *
- * @see InitialStatusMap
- *
- * When a new member joins the CPG group, all members (including the
- * new one) multicast their "initial status." The new member is in
- * PRE_INIT mode until it gets a complete set of initial status
- * messages from all cluster members. In a newly-forming cluster is
- * then in INIT mode until the configured cluster-size members have
- * joined.
- *
- * The newcomer uses initial status to determine
- * - The cluster UUID
- * - Am I speaking the correct version of the cluster protocol?
- * - Do I need to get an update from an existing active member?
- * - Can I recover from my own store?
- *
- * Pre-initialization happens in the Cluster constructor (plugin
- * early-init phase) because it needs to set the recovery flag before
- * the store initializes. This phase lasts until inital-status is
- * received for all active members. The PollableQueues and Multicaster
- * are in "bypass" mode during this phase since the poller has not
- * started so there are no threads to serve pollable queues.
- *
- * The remaining initialization happens in Cluster::initialize() or,
- * if cluster-size=N is specified, in the deliver thread when an
- * initial-status control is delivered that brings the total to N.
- */
-#include "qpid/Exception.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/sys/ClusterSafe.h"
-#include "qpid/cluster/ClusterSettings.h"
-#include "qpid/cluster/Connection.h"
-#include "qpid/cluster/UpdateClient.h"
-#include "qpid/cluster/RetractClient.h"
-#include "qpid/cluster/FailoverExchange.h"
-#include "qpid/cluster/UpdateDataExchange.h"
-#include "qpid/cluster/UpdateExchange.h"
-#include "qpid/cluster/ClusterTimer.h"
-#include "qpid/cluster/CredentialsExchange.h"
-#include "qpid/cluster/UpdateClient.h"
-
-#include "qpid/assert.h"
-#include "qmf/org/apache/qpid/cluster/ArgsClusterStopClusterNode.h"
-#include "qmf/org/apache/qpid/cluster/Package.h"
-#include "qpid/broker/Broker.h"
-#include "qpid/broker/Connection.h"
-#include "qpid/broker/NullMessageStore.h"
-#include "qpid/broker/QueueRegistry.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/Message.h"
-#include "qpid/broker/SessionState.h"
-#include "qpid/broker/SignalHandler.h"
-#include "qpid/framing/AMQFrame.h"
-#include "qpid/framing/AMQP_AllOperations.h"
-#include "qpid/framing/AllInvoker.h"
-#include "qpid/framing/ClusterConfigChangeBody.h"
-#include "qpid/framing/ClusterClockBody.h"
-#include "qpid/framing/ClusterConnectionDeliverCloseBody.h"
-#include "qpid/framing/ClusterConnectionAbortBody.h"
-#include "qpid/framing/ClusterRetractOfferBody.h"
-#include "qpid/framing/ClusterConnectionDeliverDoOutputBody.h"
-#include "qpid/framing/ClusterReadyBody.h"
-#include "qpid/framing/ClusterShutdownBody.h"
-#include "qpid/framing/ClusterUpdateOfferBody.h"
-#include "qpid/framing/ClusterUpdateRequestBody.h"
-#include "qpid/framing/ClusterConnectionAnnounceBody.h"
-#include "qpid/framing/ClusterErrorCheckBody.h"
-#include "qpid/framing/ClusterTimerWakeupBody.h"
-#include "qpid/framing/ClusterDeliverToQueueBody.h"
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/log/Helpers.h"
-#include "qpid/log/Statement.h"
-#include "qpid/UrlArray.h"
-#include "qpid/management/ManagementAgent.h"
-#include "qpid/memory.h"
-#include "qpid/sys/Thread.h"
-
-#include <boost/shared_ptr.hpp>
-#include <boost/bind.hpp>
-#include <boost/cast.hpp>
-#include <boost/current_function.hpp>
-#include <algorithm>
-#include <iterator>
-#include <map>
-#include <ostream>
-
-
-namespace qpid {
-namespace cluster {
-using namespace qpid;
-using namespace qpid::framing;
-using namespace qpid::sys;
-using namespace qpid::cluster;
-using namespace framing::cluster;
-using namespace std;
-using management::ManagementAgent;
-using management::ManagementObject;
-using management::Manageable;
-using management::Args;
-namespace _qmf = ::qmf::org::apache::qpid::cluster;
-namespace arg=client::arg;
-
-/**
- * NOTE: must increment this number whenever any incompatible changes in
- * cluster protocol/behavior are made. It allows early detection and
- * sensible reporting of an attempt to mix different versions in a
- * cluster.
- *
- * Currently use SVN revision to avoid clashes with versions from
- * different branches.
- */
-const uint32_t Cluster::CLUSTER_VERSION = 1332342;
-
-struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler {
- qpid::cluster::Cluster& cluster;
- MemberId member;
- Cluster::Lock& l;
- ClusterDispatcher(Cluster& c, const MemberId& id, Cluster::Lock& l_) : cluster(c), member(id), l(l_) {}
-
- void updateRequest(const std::string& url) { cluster.updateRequest(member, url, l); }
-
- void initialStatus(uint32_t version, bool active, const Uuid& clusterId,
- uint8_t storeState, const Uuid& shutdownId,
- const std::string& firstConfig, const framing::Array& urls)
- {
- cluster.initialStatus(
- member, version, active, clusterId,
- framing::cluster::StoreState(storeState), shutdownId,
- firstConfig, urls, l);
- }
- void ready(const std::string& url) {
- cluster.ready(member, url, l);
- }
- void configChange(const std::string& members,
- const std::string& left,
- const std::string& joined)
- {
- cluster.configChange(member, members, left, joined, l);
- }
- void updateOffer(uint64_t updatee) {
- cluster.updateOffer(member, updatee, l);
- }
- void retractOffer(uint64_t updatee) { cluster.retractOffer(member, updatee, l); }
- void errorCheck(uint8_t type, const framing::SequenceNumber& frameSeq) {
- cluster.errorCheck(member, type, frameSeq, l);
- }
- void timerWakeup(const std::string& name) { cluster.timerWakeup(member, name, l); }
- void timerDrop(const std::string& name) { cluster.timerDrop(member, name, l); }
- void shutdown(const Uuid& id) { cluster.shutdown(member, id, l); }
- void deliverToQueue(const std::string& queue, const std::string& message) {
- cluster.deliverToQueue(queue, message, l);
- }
- void clock(uint64_t time) { cluster.clock(time, l); }
- bool invoke(AMQBody& body) { return framing::invoke(*this, body).wasHandled(); }
-};
-
-Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) :
- settings(set),
- broker(b),
- mgmtObject(0),
- poller(b.getPoller()),
- cpg(*this),
- name(settings.name),
- self(cpg.self()),
- clusterId(true),
- mAgent(0),
- expiryPolicy(new ExpiryPolicy(*this)),
- mcast(cpg, poller, boost::bind(&Cluster::leave, this)),
- dispatcher(cpg, poller, boost::bind(&Cluster::leave, this)),
- deliverEventQueue(boost::bind(&Cluster::deliveredEvent, this, _1),
- boost::bind(&Cluster::leave, this),
- "Error decoding events, may indicate a broker version mismatch",
- poller),
- deliverFrameQueue(boost::bind(&Cluster::deliveredFrame, this, _1),
- boost::bind(&Cluster::leave, this),
- "Error delivering frames",
- poller),
- failoverExchange(new FailoverExchange(broker.GetVhostObject(), &broker)),
- credentialsExchange(new CredentialsExchange(*this)),
- quorum(boost::bind(&Cluster::leave, this)),
- decoder(boost::bind(&Cluster::deliverFrame, this, _1)),
- discarding(true),
- state(PRE_INIT),
- initMap(self, settings.size),
- store(broker.getDataDir().getPath()),
- elder(false),
- lastAliveCount(0),
- lastBroker(false),
- updateRetracted(false),
- updateClosed(false),
- error(*this),
- acl(0)
-{
- broker.setInCluster(true);
-
- // We give ownership of the timer to the broker and keep a plain pointer.
- // This is OK as it means the timer has the same lifetime as the broker.
- timer = new ClusterTimer(*this);
- broker.setClusterTimer(std::auto_ptr<sys::Timer>(timer));
-
- // Failover exchange provides membership updates to clients.
- broker.getExchanges().registerExchange(failoverExchange);
-
- // CredentialsExchange is used to authenticate new cluster members
- broker.getExchanges().registerExchange(credentialsExchange);
-
- // Load my store status before we go into initialization
- if (! broker::NullMessageStore::isNullStore(&broker.getStore())) {
- store.load();
- clusterId = store.getClusterId();
- QPID_LOG(notice, "Cluster store state: " << store)
- }
- cpg.join(name);
- // pump the CPG dispatch manually till we get past PRE_INIT.
- while (state == PRE_INIT)
- cpg.dispatchOne();
-}
-
-Cluster::~Cluster() {
- broker.setClusterTimer(std::auto_ptr<sys::Timer>(0)); // Delete cluster timer
- if (updateThread) updateThread.join(); // Join the previous updatethread.
-}
-
-void Cluster::initialize() {
- if (settings.quorum) quorum.start(poller);
- if (settings.url.empty())
- myUrl = Url::getIpAddressesUrl(broker.getPort(broker::Broker::TCP_TRANSPORT));
- else
- myUrl = settings.url;
- broker.getKnownBrokers = boost::bind(&Cluster::getUrls, this);
- broker.deferDelivery = boost::bind(&Cluster::deferDeliveryImpl, this, _1, _2);
- broker.setExpiryPolicy(expiryPolicy);
- deliverEventQueue.bypassOff();
- deliverEventQueue.start();
- deliverFrameQueue.bypassOff();
- deliverFrameQueue.start();
- mcast.start();
-
- /// Create management object
- mAgent = broker.getManagementAgent();
- if (mAgent != 0){
- _qmf::Package packageInit(mAgent);
- mgmtObject = new _qmf::Cluster (mAgent, this, &broker,name,myUrl.str());
- mAgent->addObject (mgmtObject);
- }
-
- // Run initMapCompleted immediately to process the initial configuration
- // that allowed us to transition out of PRE_INIT
- assert(state == INIT);
- initMapCompleted(*(Mutex::ScopedLock*)0); // Fake lock, single-threaded context.
-
- // Add finalizer last for exception safety.
- broker.addFinalizer(boost::bind(&Cluster::brokerShutdown, this));
-
- // Start dispatching CPG events.
- dispatcher.start();
-}
-
-// Called in connection thread to insert a client connection.
-void Cluster::addLocalConnection(const boost::intrusive_ptr<Connection>& c) {
- assert(c->getId().getMember() == self);
- localConnections.insert(c);
-}
-
-// Called in connection thread to insert an updated shadow connection.
-void Cluster::addShadowConnection(const boost::intrusive_ptr<Connection>& c) {
- QPID_LOG(debug, *this << " new shadow connection " << c->getId());
- // Safe to use connections here because we're pre-catchup, stalled
- // and discarding, so deliveredFrame is not processing any
- // connection events.
- assert(discarding);
- pair<ConnectionMap::iterator, bool> ib
- = connections.insert(ConnectionMap::value_type(c->getId(), c));
- // Like this to avoid tripping up unused variable warning when NDEBUG set
- if (!ib.second) assert(ib.second);
-}
-
-void Cluster::erase(const ConnectionId& id) {
- Lock l(lock);
- erase(id,l);
-}
-
-void Cluster::eraseLocal(const ConnectionId& id) {
- Lock l(lock);
- eraseLocal(id,l);
-}
-
-// Called by Connection::deliverClose() in deliverFrameQueue thread.
-void Cluster::erase(const ConnectionId& id, Lock&) {
- connections.erase(id);
- decoder.erase(id);
-}
-
-void Cluster::eraseLocal(const ConnectionId& id, Lock&) {
- localConnections.getErase(id);
-}
-
-std::vector<string> Cluster::getIds() const {
- Lock l(lock);
- return getIds(l);
-}
-
-std::vector<string> Cluster::getIds(Lock&) const {
- return map.memberIds();
-}
-
-std::vector<Url> Cluster::getUrls() const {
- Lock l(lock);
- return getUrls(l);
-}
-
-std::vector<Url> Cluster::getUrls(Lock&) const {
- return map.memberUrls();
-}
-
-void Cluster::leave() {
- Lock l(lock);
- leave(l);
-}
-
-#define LEAVE_TRY(STMT) try { STMT; } \
- catch (const std::exception& e) { \
- QPID_LOG(warning, *this << " error leaving cluster: " << e.what()); \
- } do {} while(0)
-
-void Cluster::leave(Lock&) {
- if (state != LEFT) {
- state = LEFT;
- QPID_LOG(notice, *this << " leaving cluster " << name);
- // Finalize connections now now to avoid problems later in destructor.
- ClusterSafeScope css; // Don't trigger cluster-safe assertions.
- LEAVE_TRY(localConnections.clear());
- LEAVE_TRY(connections.clear());
- LEAVE_TRY(broker::SignalHandler::shutdown());
- }
-}
-
-// Deliver CPG message.
-void Cluster::deliver(
- cpg_handle_t /*handle*/,
- const cpg_name* /*group*/,
- uint32_t nodeid,
- uint32_t pid,
- void* msg,
- int msg_len)
-{
- MemberId from(nodeid, pid);
- framing::Buffer buf(static_cast<char*>(msg), msg_len);
- Event e(Event::decodeCopy(from, buf));
- deliverEvent(e);
-}
-
-void Cluster::deliverEvent(const Event& e) { deliverEventQueue.push(e); }
-
-void Cluster::deliverFrame(const EventFrame& e) { deliverFrameQueue.push(e); }
-
-const ClusterUpdateOfferBody* castUpdateOffer(const framing::AMQBody* body) {
- return (body && body->getMethod() &&
- body->getMethod()->isA<ClusterUpdateOfferBody>()) ?
- static_cast<const ClusterUpdateOfferBody*>(body) : 0;
-}
-
-const ClusterConnectionAnnounceBody* castAnnounce( const framing::AMQBody *body) {
- return (body && body->getMethod() &&
- body->getMethod()->isA<ClusterConnectionAnnounceBody>()) ?
- static_cast<const ClusterConnectionAnnounceBody*>(body) : 0;
-}
-
-// Handler for deliverEventQueue.
-// This thread decodes frames from events.
-void Cluster::deliveredEvent(const Event& e) {
- if (e.isCluster()) {
- EventFrame ef(e, e.getFrame());
- // Stop the deliverEventQueue on update offers.
- // This preserves the connection decoder fragments for an update.
- // Only do this for the two brokers that are directly involved in this
- // offer: the one making the offer, or the one receiving it.
- const ClusterUpdateOfferBody* offer = castUpdateOffer(ef.frame.getBody());
- if (offer && ( e.getMemberId() == self || MemberId(offer->getUpdatee()) == self) ) {
- QPID_LOG(info, *this << " stall for update offer from " << e.getMemberId()
- << " to " << MemberId(offer->getUpdatee()));
- deliverEventQueue.stop();
- }
- deliverFrame(ef);
- }
- else if(!discarding) {
- if (e.isControl())
- deliverFrame(EventFrame(e, e.getFrame()));
- else {
- try { decoder.decode(e, e.getData()); }
- catch (const Exception& ex) {
- // Close a connection that is sending us invalid data.
- QPID_LOG(error, *this << " aborting connection "
- << e.getConnectionId() << ": " << ex.what());
- framing::AMQFrame abort((ClusterConnectionAbortBody()));
- deliverFrame(EventFrame(EventHeader(CONTROL, e.getConnectionId()), abort));
- }
- }
- }
-}
-
-void Cluster::flagError(
- Connection& connection, ErrorCheck::ErrorType type, const std::string& msg)
-{
- Mutex::ScopedLock l(lock);
- if (connection.isCatchUp()) {
- QPID_LOG(critical, *this << " error on update connection " << connection
- << ": " << msg);
- leave(l);
- }
- error.error(connection, type, map.getFrameSeq(), map.getMembers(), msg);
-}
-
-// Handler for deliverFrameQueue.
-// This thread executes the main logic.
-void Cluster::deliveredFrame(const EventFrame& efConst) {
- Mutex::ScopedLock l(lock);
- sys::ClusterSafeScope css; // Don't trigger cluster-safe asserts.
- if (state == LEFT) return;
- EventFrame e(efConst);
- const ClusterUpdateOfferBody* offer = castUpdateOffer(e.frame.getBody());
- if (offer && error.isUnresolved()) {
- // We can't honour an update offer that is delivered while an
- // error is in progress so replace it with a retractOffer and re-start
- // the event queue.
- e.frame = AMQFrame(
- ClusterRetractOfferBody(ProtocolVersion(), offer->getUpdatee()));
- deliverEventQueue.start();
- }
- // Process each frame through the error checker.
- if (error.isUnresolved()) {
- error.delivered(e);
- while (error.canProcess()) // There is a frame ready to process.
- processFrame(error.getNext(), l);
- }
- else
- processFrame(e, l);
-}
-
-
-void Cluster::processFrame(const EventFrame& e, Lock& l) {
- if (e.isCluster()) {
- QPID_LOG_IF(trace, loggable(e.frame), *this << " DLVR: " << e);
- ClusterDispatcher dispatch(*this, e.connectionId.getMember(), l);
- if (!framing::invoke(dispatch, *e.frame.getBody()).wasHandled())
- throw Exception(QPID_MSG("Invalid cluster control"));
- }
- else if (state >= CATCHUP) {
- map.incrementFrameSeq();
- ConnectionPtr connection = getConnection(e, l);
- if (connection) {
- QPID_LOG_IF(trace, loggable(e.frame),
- *this << " DLVR " << map.getFrameSeq() << ": " << e);
- connection->deliveredFrame(e);
- }
- else
- throw Exception(QPID_MSG("Unknown connection: " << e));
- }
- else // Drop connection frames while state < CATCHUP
- QPID_LOG_IF(trace, loggable(e.frame), *this << " DROP (joining): " << e);
-}
-
-// Called in deliverFrameQueue thread
-ConnectionPtr Cluster::getConnection(const EventFrame& e, Lock&) {
- ConnectionId id = e.connectionId;
- ConnectionMap::iterator i = connections.find(id);
- if (i != connections.end()) return i->second;
- ConnectionPtr cp;
- // If the frame is an announcement for a new connection, add it.
- const ClusterConnectionAnnounceBody *announce = castAnnounce(e.frame.getBody());
- if (e.frame.getBody() && e.frame.getMethod() && announce)
- {
- if (id.getMember() == self) { // Announces one of my own
- cp = localConnections.getErase(id);
- assert(cp);
- }
- else { // New remote connection, create a shadow.
- qpid::sys::SecuritySettings secSettings;
- if (announce) {
- secSettings.ssf = announce->getSsf();
- secSettings.authid = announce->getAuthid();
- secSettings.nodict = announce->getNodict();
- }
- cp = new Connection(*this, shadowOut, announce->getManagementId(), id, secSettings);
- }
- connections.insert(ConnectionMap::value_type(id, cp));
- }
- return cp;
-}
-
-Cluster::ConnectionVector Cluster::getConnections(Lock&) {
- ConnectionVector result(connections.size());
- std::transform(connections.begin(), connections.end(), result.begin(),
- boost::bind(&ConnectionMap::value_type::second, _1));
- return result;
-}
-
-// CPG config-change callback.
-void Cluster::configChange (
- cpg_handle_t /*handle*/,
- const cpg_name */*group*/,
- const cpg_address *members, int nMembers,
- const cpg_address *left, int nLeft,
- const cpg_address *joined, int nJoined)
-{
- Mutex::ScopedLock l(lock);
- string membersStr, leftStr, joinedStr;
- // Encode members and enqueue as an event so the config change can
- // be executed in the correct thread.
- for (const cpg_address* p = members; p < members+nMembers; ++p)
- membersStr.append(MemberId(*p).str());
- for (const cpg_address* p = left; p < left+nLeft; ++p)
- leftStr.append(MemberId(*p).str());
- for (const cpg_address* p = joined; p < joined+nJoined; ++p)
- joinedStr.append(MemberId(*p).str());
- deliverEvent(Event::control(ClusterConfigChangeBody(
- ProtocolVersion(), membersStr, leftStr, joinedStr),
- self));
-}
-
-void Cluster::setReady(Lock&) {
- state = READY;
- mcast.setReady();
- broker.getQueueEvents().enable();
- enableClusterSafe(); // Enable cluster-safe assertions.
-}
-
-// Set the management status from the Cluster::state.
-//
-// NOTE: Management updates are sent based on property changes. In
-// order to keep consistency across the cluster, we touch the local
-// management status property even if it is locally unchanged for any
-// event that could have cause a cluster property change on any cluster member.
-void Cluster::setMgmtStatus(Lock&) {
- if (mgmtObject)
- mgmtObject->set_status(state >= CATCHUP ? "ACTIVE" : "JOINING");
-}
-
-void Cluster::initMapCompleted(Lock& l) {
- // Called on completion of the initial status map.
- QPID_LOG(debug, *this << " initial status map complete. ");
- setMgmtStatus(l);
- if (state == PRE_INIT) {
- // PRE_INIT means we're still in the earlyInitialize phase, in the constructor.
- // We decide here whether we want to recover from our store.
- // We won't recover if we are joining an active cluster or our store is dirty.
- if (store.hasStore() &&
- store.getState() != STORE_STATE_EMPTY_STORE &&
- (initMap.isActive() || store.getState() == STORE_STATE_DIRTY_STORE))
- broker.setRecovery(false); // Ditch my current store.
- state = INIT;
- }
- else if (state == INIT) {
- // INIT means we are past Cluster::initialize().
-
- // If we're forming an initial cluster (no active members)
- // then we wait to reach the configured cluster-size
- if (!initMap.isActive() && initMap.getActualSize() < initMap.getRequiredSize()) {
- QPID_LOG(info, *this << initMap.getActualSize()
- << " members, waiting for at least " << initMap.getRequiredSize());
- return;
- }
-
- initMap.checkConsistent();
- elders = initMap.getElders();
- QPID_LOG(debug, *this << " elders: " << elders);
- if (elders.empty())
- becomeElder(l);
- else {
- broker.getLinks().setPassive(true);
- broker.getQueueEvents().disable();
- QPID_LOG(info, *this << " not active for links.");
- }
- setClusterId(initMap.getClusterId(), l);
-
- if (initMap.isUpdateNeeded()) { // Joining established cluster.
- authenticate();
- broker.setRecovery(false); // Ditch my current store.
- broker.setClusterUpdatee(true);
-
- // Update exchange is used during updates to replicate messages
- // without modifying delivery-properties.exchange.
- broker.getExchanges().registerExchange(
- boost::shared_ptr<broker::Exchange>(new UpdateExchange(this)));
-
- // Update-data exchange is used during update for passing data that
- // may be too large for single control frame.
- updateDataExchange.reset(new UpdateDataExchange(*this));
- broker.getExchanges().registerExchange(updateDataExchange);
-
- if (mAgent) mAgent->suppress(true); // Suppress mgmt output during update.
- state = JOINER;
- mcast.mcastControl(ClusterUpdateRequestBody(ProtocolVersion(), myUrl.str()), self);
- QPID_LOG(notice, *this << " joining cluster " << name);
- }
- else { // I can go ready.
- discarding = false;
- setReady(l);
- // Must be called *before* memberUpdate so first update will be generated.
- failoverExchange->setReady();
- memberUpdate(l);
- updateMgmtMembership(l);
- mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), self);
- QPID_LOG(notice, *this << " joined cluster " << name);
- }
- }
-}
-
-void Cluster::configChange(const MemberId&,
- const std::string& membersStr,
- const std::string& leftStr,
- const std::string& joinedStr,
- Lock& l)
-{
- if (state == LEFT) return;
- MemberSet members = decodeMemberSet(membersStr);
- MemberSet left = decodeMemberSet(leftStr);
- MemberSet joined = decodeMemberSet(joinedStr);
- QPID_LOG(notice, *this << " configuration change: " << members);
- QPID_LOG_IF(notice, !left.empty(), *this << " Members left: " << left);
- QPID_LOG_IF(notice, !joined.empty(), *this << " Members joined: " << joined);
-
- // If we are still joining, make sure there is someone to give us an update.
- elders = intersection(elders, members);
- if (elders.empty() && INIT < state && state < CATCHUP) {
- QPID_LOG(critical, "Cannot update, all potential updaters left the cluster.");
- leave(l);
- return;
- }
- bool memberChange = map.configChange(members);
-
- // Update initital status for members joining or leaving.
- initMap.configChange(members);
- if (initMap.isResendNeeded()) {
- mcast.mcastControl(
- ClusterInitialStatusBody(
- ProtocolVersion(), CLUSTER_VERSION, state > INIT, clusterId,
- store.getState(), store.getShutdownId(),
- initMap.getFirstConfigStr(),
- vectorToUrlArray(getUrls(l))
- ),
- self);
- }
- if (initMap.transitionToComplete()) initMapCompleted(l);
-
- if (state >= CATCHUP && memberChange) {
- memberUpdate(l);
- if (elders.empty()) becomeElder(l);
- }
-
- updateMgmtMembership(l); // Update on every config change for consistency
-}
-
-struct ClusterClockTask : public sys::TimerTask {
- Cluster& cluster;
- sys::Timer& timer;
-
- ClusterClockTask(Cluster& cluster, sys::Timer& timer, uint16_t clockInterval)
- : TimerTask(Duration(clockInterval * TIME_MSEC),"ClusterClock"), cluster(cluster), timer(timer) {}
-
- void fire() {
- cluster.sendClockUpdate();
- setupNextFire();
- timer.add(this);
- }
-};
-
-void Cluster::becomeElder(Lock&) {
- if (elder) return; // We were already the elder.
- // We are the oldest, reactive links if necessary
- QPID_LOG(info, *this << " became the elder, active for links.");
- elder = true;
- broker.getLinks().setPassive(false);
- timer->becomeElder();
-
- clockTimer.add(new ClusterClockTask(*this, clockTimer, settings.clockInterval));
-}
-
-void Cluster::makeOffer(const MemberId& id, Lock& ) {
- if (state == READY && map.isJoiner(id)) {
- state = OFFER;
- QPID_LOG(info, *this << " send update-offer to " << id);
- mcast.mcastControl(ClusterUpdateOfferBody(ProtocolVersion(), id), self);
- }
-}
-
-namespace {
-struct AppendQueue {
- ostream* os;
- AppendQueue(ostream& o) : os(&o) {}
- void operator()(const boost::shared_ptr<broker::Queue>& q) {
- (*os) << " " << q->getName() << "=" << q->getMessageCount();
- }
-};
-} // namespace
-
-// Log a snapshot of broker state, used for debugging inconsistency problems.
-// May only be called in deliver thread.
-std::string Cluster::debugSnapshot() {
- assertClusterSafe();
- std::ostringstream msg;
- msg << "Member joined, frameSeq=" << map.getFrameSeq() << ", queue snapshot:";
- AppendQueue append(msg);
- broker.getQueues().eachQueue(append);
- return msg.str();
-}
-
-// Called from Broker::~Broker when broker is shut down. At this
-// point we know the poller has stopped so no poller callbacks will be
-// invoked. We must ensure that CPG has also shut down so no CPG
-// callbacks will be invoked.
-//
-void Cluster::brokerShutdown() {
- sys::ClusterSafeScope css; // Don't trigger cluster-safe asserts.
- try { cpg.shutdown(); }
- catch (const std::exception& e) {
- QPID_LOG(error, *this << " shutting down CPG: " << e.what());
- }
- delete this;
-}
-
-void Cluster::updateRequest(const MemberId& id, const std::string& url, Lock& l) {
- map.updateRequest(id, url);
- makeOffer(id, l);
-}
-
-void Cluster::initialStatus(const MemberId& member, uint32_t version, bool active,
- const framing::Uuid& id,
- framing::cluster::StoreState store,
- const framing::Uuid& shutdownId,
- const std::string& firstConfig,
- const framing::Array& urls,
- Lock& l)
-{
- if (version != CLUSTER_VERSION) {
- QPID_LOG(critical, *this << " incompatible cluster versions " <<
- version << " != " << CLUSTER_VERSION);
- leave(l);
- return;
- }
- QPID_LOG_IF(debug, state == PRE_INIT, *this
- << " received initial status from " << member);
- initMap.received(
- member,
- ClusterInitialStatusBody(ProtocolVersion(), version, active, id,
- store, shutdownId, firstConfig, urls)
- );
- if (initMap.transitionToComplete()) initMapCompleted(l);
-}
-
-void Cluster::ready(const MemberId& id, const std::string& url, Lock& l) {
- try {
- if (map.ready(id, Url(url)))
- memberUpdate(l);
- if (state == CATCHUP && id == self) {
- setReady(l);
- QPID_LOG(notice, *this << " caught up.");
- }
- } catch (const Url::Invalid& e) {
- QPID_LOG(error, "Invalid URL in cluster ready command: " << url);
- }
- // Update management on every ready event to be consistent across cluster.
- setMgmtStatus(l);
- updateMgmtMembership(l);
-}
-
-void Cluster::updateOffer(const MemberId& updater, uint64_t updateeInt, Lock& l) {
- // NOTE: deliverEventQueue has been stopped at the update offer by
- // deliveredEvent in case an update is required.
- if (state == LEFT) return;
- MemberId updatee(updateeInt);
- boost::optional<Url> url = map.updateOffer(updater, updatee);
- if (updater == self) {
- assert(state == OFFER);
- if (url) // My offer was first.
- updateStart(updatee, *url, l);
- else { // Another offer was first.
- QPID_LOG(info, *this << " cancelled offer to " << updatee << " unstall");
- setReady(l);
- makeOffer(map.firstJoiner(), l); // Maybe make another offer.
- deliverEventQueue.start(); // Go back to normal processing
- }
- }
- else if (updatee == self && url) {
- assert(state == JOINER);
- state = UPDATEE;
- acl = broker.getAcl();
- broker.setAcl(0); // Disable ACL during update
- QPID_LOG(notice, *this << " receiving update from " << updater);
- checkUpdateIn(l);
- }
- else {
- QPID_LOG(info, *this << " unstall, ignore update " << updater
- << " to " << updatee);
- deliverEventQueue.start(); // Not involved in update.
- }
- if (updatee != self && url) {
- QPID_LOG(debug, debugSnapshot());
- if (mAgent) mAgent->clusterUpdate();
- // Updatee will call clusterUpdate() via checkUpdateIn() when update completes
- }
-}
-
-static client::ConnectionSettings connectionSettings(const ClusterSettings& settings) {
- client::ConnectionSettings cs;
- cs.username = settings.username;
- cs.password = settings.password;
- cs.mechanism = settings.mechanism;
- return cs;
-}
-
-void Cluster::retractOffer(const MemberId& updater, uint64_t updateeInt, Lock& l) {
- // An offer was received while handling an error, and converted to a retract.
- // Behavior is very similar to updateOffer.
- if (state == LEFT) return;
- MemberId updatee(updateeInt);
- boost::optional<Url> url = map.updateOffer(updater, updatee);
- if (updater == self) {
- assert(state == OFFER);
- if (url) { // My offer was first.
- if (updateThread)
- updateThread.join(); // Join the previous updateThread to avoid leaks.
- updateThread = Thread(new RetractClient(*url, connectionSettings(settings)));
- }
- setReady(l);
- makeOffer(map.firstJoiner(), l); // Maybe make another offer.
- // Don't unstall the event queue, that was already done in deliveredFrame
- }
- QPID_LOG(debug,*this << " retracted offer " << updater << " to " << updatee);
-}
-
-void Cluster::updateStart(const MemberId& updatee, const Url& url, Lock& l) {
- // Check for credentials if authentication is enabled.
- if (broker.getOptions().auth && !credentialsExchange->check(updatee)) {
- QPID_LOG(error, "Un-authenticated attempt to join the cluster");
- return;
- }
- // NOTE: deliverEventQueue is already stopped at the stall point by deliveredEvent.
- if (state == LEFT) return;
- assert(state == OFFER);
- state = UPDATER;
- QPID_LOG(notice, *this << " sending update to " << updatee << " at " << url);
- if (updateThread)
- updateThread.join(); // Join the previous updateThread to avoid leaks.
- updateThread = Thread(
- new UpdateClient(self, updatee, url, broker, map, *expiryPolicy,
- getConnections(l), decoder,
- boost::bind(&Cluster::updateOutDone, this),
- boost::bind(&Cluster::updateOutError, this, _1),
- connectionSettings(settings)));
-}
-
-// Called in network thread
-void Cluster::updateInClosed() {
- Lock l(lock);
- assert(!updateClosed);
- updateClosed = true;
- checkUpdateIn(l);
-}
-
-// Called in update thread.
-void Cluster::updateInDone(const ClusterMap& m) {
- Lock l(lock);
- updatedMap = m;
- checkUpdateIn(l);
-}
-
-void Cluster::updateInRetracted() {
- Lock l(lock);
- updateRetracted = true;
- map.clearStatus();
- checkUpdateIn(l);
-}
-
-bool Cluster::isExpectingUpdate() {
- Lock l(lock);
- return state <= UPDATEE;
-}
-
-// Called in update thread or deliver thread.
-void Cluster::checkUpdateIn(Lock& l) {
- if (state != UPDATEE) return; // Wait till we reach the stall point.
- if (!updateClosed) return; // Wait till update connection closes.
- if (updatedMap) { // We're up to date
- map = *updatedMap;
- mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), self);
- state = CATCHUP;
- memberUpdate(l);
- // Must be called *after* memberUpdate() to avoid sending an extra update.
- failoverExchange->setReady();
- // NB: don't updateMgmtMembership() here as we are not in the deliver
- // thread. It will be updated on delivery of the "ready" we just mcast.
- broker.setClusterUpdatee(false);
- broker.setAcl(acl); // Restore ACL
- discarding = false; // OK to set, we're stalled for update.
- QPID_LOG(notice, *this << " update complete, starting catch-up.");
- QPID_LOG(debug, debugSnapshot()); // OK to call because we're stalled.
- if (mAgent) {
- // Update management agent now, after all update activity is complete.
- updateDataExchange->updateManagementAgent(mAgent);
- mAgent->suppress(false); // Enable management output.
- mAgent->clusterUpdate();
- }
- // Restore alternate exchange settings on exchanges.
- broker.getExchanges().eachExchange(
- boost::bind(&broker::Exchange::recoveryComplete, _1,
- boost::ref(broker.getExchanges())));
- enableClusterSafe(); // Enable cluster-safe assertions
- deliverEventQueue.start();
- // FIXME aconway 2012-04-04: unregister/delete Update[Data]Exchange
- updateDataExchange.reset();
- broker.getExchanges().destroy(UpdateDataExchange::EXCHANGE_NAME);
- broker.getExchanges().destroy(UpdateClient::UPDATE);
- }
- else if (updateRetracted) { // Update was retracted, request another update
- updateRetracted = false;
- updateClosed = false;
- state = JOINER;
- QPID_LOG(notice, *this << " update retracted, sending new update request.");
- mcast.mcastControl(ClusterUpdateRequestBody(ProtocolVersion(), myUrl.str()), self);
- deliverEventQueue.start();
- }
-}
-
-void Cluster::updateOutDone() {
- Monitor::ScopedLock l(lock);
- updateOutDone(l);
-}
-
-void Cluster::updateOutDone(Lock& l) {
- QPID_LOG(notice, *this << " update sent");
- assert(state == UPDATER);
- state = READY;
- deliverEventQueue.start(); // Start processing events again.
- makeOffer(map.firstJoiner(), l); // Try another offer
-}
-
-void Cluster::updateOutError(const std::exception& e) {
- Monitor::ScopedLock l(lock);
- QPID_LOG(error, *this << " error sending update: " << e.what());
- updateOutDone(l);
-}
-
-void Cluster ::shutdown(const MemberId& , const Uuid& id, Lock& l) {
- QPID_LOG(notice, *this << " cluster shut down by administrator.");
- if (store.hasStore()) store.clean(id);
- leave(l);
-}
-
-ManagementObject* Cluster::GetManagementObject() const { return mgmtObject; }
-
-Manageable::status_t Cluster::ManagementMethod (uint32_t methodId, Args& args, string&) {
- Lock l(lock);
- QPID_LOG(debug, *this << " managementMethod [id=" << methodId << "]");
- switch (methodId) {
- case _qmf::Cluster::METHOD_STOPCLUSTERNODE :
- {
- _qmf::ArgsClusterStopClusterNode& iargs = (_qmf::ArgsClusterStopClusterNode&) args;
- stringstream stream;
- stream << self;
- if (iargs.i_brokerId == stream.str())
- stopClusterNode(l);
- }
- break;
- case _qmf::Cluster::METHOD_STOPFULLCLUSTER :
- stopFullCluster(l);
- break;
- default:
- return Manageable::STATUS_UNKNOWN_METHOD;
- }
- return Manageable::STATUS_OK;
-}
-
-void Cluster::stopClusterNode(Lock& l) {
- QPID_LOG(notice, *this << " cluster member stopped by administrator.");
- leave(l);
-}
-
-void Cluster::stopFullCluster(Lock& ) {
- QPID_LOG(notice, *this << " shutting down cluster " << name);
- mcast.mcastControl(ClusterShutdownBody(ProtocolVersion(), Uuid(true)), self);
-}
-
-void Cluster::memberUpdate(Lock& l) {
- // Ignore config changes while we are joining.
- if (state < CATCHUP) return;
- QPID_LOG(info, *this << " member update: " << map);
- size_t aliveCount = map.aliveCount();
- assert(map.isAlive(self));
- failoverExchange->updateUrls(getUrls(l));
-
- // Mark store clean if I am the only broker, dirty otherwise.
- if (store.hasStore()) {
- if (aliveCount == 1) {
- if (store.getState() != STORE_STATE_CLEAN_STORE) {
- QPID_LOG(notice, *this << "Sole member of cluster, marking store clean.");
- store.clean(Uuid(true));
- }
- }
- else {
- if (store.getState() != STORE_STATE_DIRTY_STORE) {
- QPID_LOG(notice, "Running in a cluster, marking store dirty.");
- store.dirty();
- }
- }
- }
-
- // If I am the last member standing, set queue policies.
- if (aliveCount == 1 && lastAliveCount > 1 && state >= CATCHUP) {
- QPID_LOG(notice, *this << " last broker standing, update queue policies");
- lastBroker = true;
- broker.getQueues().updateQueueClusterState(true);
- }
- else if (aliveCount > 1 && lastBroker) {
- QPID_LOG(notice, *this << " last broker standing joined by " << aliveCount-1
- << " replicas, updating queue policies.");
- lastBroker = false;
- broker.getQueues().updateQueueClusterState(false);
- }
- lastAliveCount = aliveCount;
-
- // Close connections belonging to members that have left the cluster.
- ConnectionMap::iterator i = connections.begin();
- while (i != connections.end()) {
- ConnectionMap::iterator j = i++;
- MemberId m = j->second->getId().getMember();
- if (m != self && !map.isMember(m)) {
- j->second->close();
- erase(j->second->getId(), l);
- }
- }
-}
-
-// See comment on Cluster::setMgmtStatus
-void Cluster::updateMgmtMembership(Lock& l) {
- if (!mgmtObject) return;
- std::vector<Url> urls = getUrls(l);
- mgmtObject->set_clusterSize(urls.size());
- string urlstr;
- for(std::vector<Url>::iterator i = urls.begin(); i != urls.end(); i++ ) {
- if (i != urls.begin()) urlstr += ";";
- urlstr += i->str();
- }
- std::vector<string> ids = getIds(l);
- string idstr;
- for(std::vector<string>::iterator i = ids.begin(); i != ids.end(); i++ ) {
- if (i != ids.begin()) idstr += ";";
- idstr += *i;
- }
- mgmtObject->set_members(urlstr);
- mgmtObject->set_memberIDs(idstr);
-}
-
-namespace {
-template <class T> struct AutoClose {
- T closeme;
- AutoClose(T t) : closeme(t) {}
- ~AutoClose() { closeme.close(); }
-};
-}
-
-// Updatee connects to established member and stores credentials
-// in the qpid.cluster-credentials exchange to prove it
-// is safe for updater to connect and give an update.
-void Cluster::authenticate() {
- if (!broker.getOptions().auth) return;
- std::vector<Url> urls = initMap.getUrls();
- for (std::vector<Url>::iterator i = urls.begin(); i != urls.end(); ++i) {
- if (!i->empty()) {
- client::Connection c;
- c.open(*i, connectionSettings(settings));
- AutoClose<client::Connection> closeConnection(c);
- client::Session s = c.newSession(CredentialsExchange::NAME);
- AutoClose<client::Session> closeSession(s);
- client::Message credentials;
- credentials.getHeaders().setUInt64(CredentialsExchange::NAME, getId());
- s.messageTransfer(arg::content=credentials, arg::destination=CredentialsExchange::NAME);
- s.sync();
- }
- }
-}
-
-std::ostream& operator<<(std::ostream& o, const Cluster& cluster) {
- static const char* STATE[] = {
- "PRE_INIT", "INIT", "JOINER", "UPDATEE", "CATCHUP",
- "READY", "OFFER", "UPDATER", "LEFT"
- };
- assert(sizeof(STATE)/sizeof(*STATE) == Cluster::LEFT+1);
- o << "cluster(" << cluster.self << " " << STATE[cluster.state];
- if (cluster.error.isUnresolved()) o << "/error";
- return o << ")";
-}
-
-MemberId Cluster::getId() const {
- return self; // Immutable, no need to lock.
-}
-
-broker::Broker& Cluster::getBroker() const {
- return broker; // Immutable, no need to lock.
-}
-
-void Cluster::setClusterId(const Uuid& uuid, Lock&) {
- clusterId = uuid;
- if (store.hasStore()) store.setClusterId(uuid);
- if (mgmtObject) {
- stringstream stream;
- stream << self;
- mgmtObject->set_clusterID(clusterId.str());
- mgmtObject->set_memberID(stream.str());
- }
- QPID_LOG(notice, *this << " cluster-uuid = " << clusterId);
-}
-
-void Cluster::errorCheck(const MemberId& from, uint8_t type, framing::SequenceNumber frameSeq, Lock&) {
- // If we see an errorCheck here (rather than in the ErrorCheck
- // class) then we have processed succesfully past the point of the
- // error.
- if (state >= CATCHUP) // Don't respond pre catchup, we don't know what happened
- error.respondNone(from, type, frameSeq);
-}
-
-void Cluster::timerWakeup(const MemberId& , const std::string& name, Lock&) {
- if (state >= CATCHUP) // Pre catchup our timer isn't set up.
- timer->deliverWakeup(name);
-}
-
-void Cluster::timerDrop(const MemberId& , const std::string& name, Lock&) {
- QPID_LOG(debug, "Cluster timer drop " << map.getFrameSeq() << ": " << name)
- if (state >= CATCHUP) // Pre catchup our timer isn't set up.
- timer->deliverDrop(name);
-}
-
-bool Cluster::isElder() const {
- return elder;
-}
-
-void Cluster::deliverToQueue(const std::string& queue, const std::string& message, Lock& l)
-{
- broker::Queue::shared_ptr q = broker.getQueues().find(queue);
- if (!q) {
- QPID_LOG(critical, *this << " cluster delivery to non-existent queue: " << queue);
- leave(l);
- }
- framing::Buffer buf(const_cast<char*>(message.data()), message.size());
- boost::intrusive_ptr<broker::Message> msg(new broker::Message);
- msg->decodeHeader(buf);
- msg->decodeContent(buf);
- q->deliver(msg);
-}
-
-sys::AbsTime Cluster::getClusterTime() {
- Mutex::ScopedLock l(lock);
- return clusterTime;
-}
-
-// This method is called during update on the updatee to set the initial cluster time.
-void Cluster::clock(const uint64_t time) {
- Mutex::ScopedLock l(lock);
- clock(time, l);
-}
-
-// called when broadcast message received
-void Cluster::clock(const uint64_t time, Lock&) {
- clusterTime = AbsTime(EPOCH, time);
- AbsTime now = AbsTime::now();
-
- if (!elder) {
- clusterTimeOffset = Duration(now, clusterTime);
- }
-}
-
-// called by elder timer to send clock broadcast
-void Cluster::sendClockUpdate() {
- Mutex::ScopedLock l(lock);
- int64_t nanosecondsSinceEpoch = Duration(EPOCH, now());
- nanosecondsSinceEpoch += clusterTimeOffset;
- mcast.mcastControl(ClusterClockBody(ProtocolVersion(), nanosecondsSinceEpoch), self);
-}
-
-bool Cluster::deferDeliveryImpl(const std::string& queue,
- const boost::intrusive_ptr<broker::Message>& msg)
-{
- if (isClusterSafe()) return false;
- std::string message;
- message.resize(msg->encodedSize());
- framing::Buffer buf(const_cast<char*>(message.data()), message.size());
- msg->encode(buf);
- mcast.mcastControl(ClusterDeliverToQueueBody(ProtocolVersion(), queue, message), self);
- return true;
-}
-
-bool Cluster::loggable(const AMQFrame& f) {
- const AMQMethodBody* method = (f.getMethod());
- if (!method) return true; // Not a method
- bool isClock = method->amqpClassId() == ClusterClockBody::CLASS_ID
- && method->amqpMethodId() == ClusterClockBody::METHOD_ID;
- return !isClock;
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Cluster.h b/cpp/src/qpid/cluster/Cluster.h
deleted file mode 100644
index 40f1445f23..0000000000
--- a/cpp/src/qpid/cluster/Cluster.h
+++ /dev/null
@@ -1,332 +0,0 @@
-#ifndef QPID_CLUSTER_CLUSTER_H
-#define QPID_CLUSTER_CLUSTER_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "ClusterMap.h"
-#include "ClusterSettings.h"
-#include "Cpg.h"
-#include "Decoder.h"
-#include "ErrorCheck.h"
-#include "Event.h"
-#include "EventFrame.h"
-#include "ExpiryPolicy.h"
-#include "FailoverExchange.h"
-#include "InitialStatusMap.h"
-#include "LockedConnectionMap.h"
-#include "Multicaster.h"
-#include "NoOpConnectionOutputHandler.h"
-#include "PollableQueue.h"
-#include "PollerDispatch.h"
-#include "Quorum.h"
-#include "StoreStatus.h"
-#include "UpdateReceiver.h"
-
-#include "qmf/org/apache/qpid/cluster/Cluster.h"
-#include "qpid/Url.h"
-#include "qpid/broker/Broker.h"
-#include "qpid/management/Manageable.h"
-#include "qpid/sys/Monitor.h"
-
-#include <boost/bind.hpp>
-#include <boost/intrusive_ptr.hpp>
-#include <boost/optional.hpp>
-
-#include <algorithm>
-#include <map>
-#include <vector>
-
-namespace qpid {
-
-namespace broker {
-class Message;
-class AclModule;
-}
-
-namespace framing {
-class AMQFrame;
-class AMQBody;
-struct Uuid;
-}
-
-namespace sys {
-class Timer;
-class AbsTime;
-class Duration;
-}
-
-namespace cluster {
-
-class Connection;
-struct EventFrame;
-class ClusterTimer;
-class UpdateDataExchange;
-class CredentialsExchange;
-
-/**
- * Connection to the cluster
- */
-class Cluster : private Cpg::Handler, public management::Manageable {
- public:
- typedef boost::intrusive_ptr<Connection> ConnectionPtr;
- typedef std::vector<ConnectionPtr> ConnectionVector;
-
- // Public functions are thread safe unless otherwise mentioned in a comment.
-
- // Construct the cluster in plugin earlyInitialize.
- Cluster(const ClusterSettings&, broker::Broker&);
- virtual ~Cluster();
-
- // Called by plugin initialize: cluster start-up requires transport plugins .
- // Thread safety: only called by plugin initialize.
- void initialize();
-
- // Connection map.
- void addLocalConnection(const ConnectionPtr&);
- void addShadowConnection(const ConnectionPtr&);
- void erase(const ConnectionId&);
- void eraseLocal(const ConnectionId&);
-
- // URLs of current cluster members.
- std::vector<std::string> getIds() const;
- std::vector<Url> getUrls() const;
- boost::shared_ptr<FailoverExchange> getFailoverExchange() const { return failoverExchange; }
-
- // Leave the cluster - called when fatal errors occur.
- void leave();
-
- // Update completed - called in update thread
- void updateInClosed();
- void updateInDone(const ClusterMap&);
- void updateInRetracted();
- // True if we are expecting to receive catch-up connections.
- bool isExpectingUpdate();
-
- MemberId getId() const;
- broker::Broker& getBroker() const;
- Multicaster& getMulticast() { return mcast; }
-
- const ClusterSettings& getSettings() const { return settings; }
-
- void deliverFrame(const EventFrame&);
-
- // Called in deliverFrame thread to indicate an error from the broker.
- void flagError(Connection&, ErrorCheck::ErrorType, const std::string& msg);
-
- // Called only during update by Connection::shadowReady
- Decoder& getDecoder() { return decoder; }
-
- ExpiryPolicy& getExpiryPolicy() { return *expiryPolicy; }
-
- UpdateReceiver& getUpdateReceiver() { return updateReceiver; }
-
- bool isElder() const;
-
- // Generates a log message for debugging purposes.
- std::string debugSnapshot();
-
- // Defer messages delivered in an unsafe context by multicasting.
- bool deferDeliveryImpl(const std::string& queue,
- const boost::intrusive_ptr<broker::Message>& msg);
-
- sys::AbsTime getClusterTime();
- void sendClockUpdate();
- void clock(const uint64_t time);
-
- static bool loggable(const framing::AMQFrame&); // True if the frame should be logged.
-
- private:
- typedef sys::Monitor::ScopedLock Lock;
-
- typedef PollableQueue<Event> PollableEventQueue;
- typedef PollableQueue<EventFrame> PollableFrameQueue;
- typedef std::map<ConnectionId, ConnectionPtr> ConnectionMap;
-
- /** Version number of the cluster protocol, to avoid mixed versions. */
- static const uint32_t CLUSTER_VERSION;
-
- // NB: A dummy Lock& parameter marks functions that must only be
- // called with Cluster::lock locked.
-
- void leave(Lock&);
- std::vector<std::string> getIds(Lock&) const;
- std::vector<Url> getUrls(Lock&) const;
-
- // == Called in main thread from Broker destructor.
- void brokerShutdown();
-
- // == Called in deliverEventQueue thread
- void deliveredEvent(const Event&);
-
- // == Called in deliverFrameQueue thread
- void deliveredFrame(const EventFrame&);
- void processFrame(const EventFrame&, Lock&);
-
- // Cluster controls implement XML methods from cluster.xml.
- void updateRequest(const MemberId&, const std::string&, Lock&);
- void updateOffer(const MemberId& updater, uint64_t updatee, Lock&);
- void retractOffer(const MemberId& updater, uint64_t updatee, Lock&);
- void initialStatus(const MemberId&,
- uint32_t version,
- bool active,
- const framing::Uuid& clusterId,
- framing::cluster::StoreState,
- const framing::Uuid& shutdownId,
- const std::string& firstConfig,
- const framing::Array& urls,
- Lock&);
- void ready(const MemberId&, const std::string&, Lock&);
- void configChange(const MemberId&,
- const std::string& members,
- const std::string& left,
- const std::string& joined,
- Lock& l);
- void errorCheck(const MemberId&, uint8_t type, SequenceNumber frameSeq, Lock&);
- void timerWakeup(const MemberId&, const std::string& name, Lock&);
- void timerDrop(const MemberId&, const std::string& name, Lock&);
- void shutdown(const MemberId&, const framing::Uuid& shutdownId, Lock&);
- void deliverToQueue(const std::string& queue, const std::string& message, Lock&);
- void clock(const uint64_t time, Lock&);
-
- // Helper functions
- ConnectionPtr getConnection(const EventFrame&, Lock&);
- ConnectionVector getConnections(Lock&);
- void updateStart(const MemberId& updatee, const Url& url, Lock&);
- void makeOffer(const MemberId&, Lock&);
- void setReady(Lock&);
- void memberUpdate(Lock&);
- void setClusterId(const framing::Uuid&, Lock&);
- void erase(const ConnectionId&, Lock&);
- void eraseLocal(const ConnectionId&, Lock&);
- void requestUpdate(Lock& );
- void initMapCompleted(Lock&);
- void becomeElder(Lock&);
- void setMgmtStatus(Lock&);
- void updateMgmtMembership(Lock&);
- void authenticate();
-
- // == Called in CPG dispatch thread
- void deliver( // CPG deliver callback.
- cpg_handle_t /*handle*/,
- const struct cpg_name *group,
- uint32_t /*nodeid*/,
- uint32_t /*pid*/,
- void* /*msg*/,
- int /*msg_len*/);
-
- void deliverEvent(const Event&);
-
- void configChange( // CPG config change callback.
- cpg_handle_t /*handle*/,
- const struct cpg_name */*group*/,
- const struct cpg_address */*members*/, int /*nMembers*/,
- const struct cpg_address */*left*/, int /*nLeft*/,
- const struct cpg_address */*joined*/, int /*nJoined*/
- );
-
- // == Called in management threads.
- virtual qpid::management::ManagementObject* GetManagementObject() const;
- virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
-
- void stopClusterNode(Lock&);
- void stopFullCluster(Lock&);
-
- // == Called in connection IO threads .
- void checkUpdateIn(Lock&);
-
- // == Called in UpdateClient thread.
- void updateOutDone();
- void updateOutError(const std::exception&);
- void updateOutDone(Lock&);
-
- // Immutable members set on construction, never changed.
- const ClusterSettings settings;
- broker::Broker& broker;
- qmf::org::apache::qpid::cluster::Cluster* mgmtObject; // mgnt owns lifecycle
- boost::shared_ptr<sys::Poller> poller;
- Cpg cpg;
- const std::string name;
- Url myUrl;
- const MemberId self;
- framing::Uuid clusterId;
- NoOpConnectionOutputHandler shadowOut;
- qpid::management::ManagementAgent* mAgent;
- boost::intrusive_ptr<ExpiryPolicy> expiryPolicy;
-
- // Thread safe members
- Multicaster mcast;
- PollerDispatch dispatcher;
- PollableEventQueue deliverEventQueue;
- PollableFrameQueue deliverFrameQueue;
- boost::shared_ptr<FailoverExchange> failoverExchange;
- boost::shared_ptr<UpdateDataExchange> updateDataExchange;
- boost::shared_ptr<CredentialsExchange> credentialsExchange;
- Quorum quorum;
- LockedConnectionMap localConnections;
-
- // Used only in deliverEventQueue thread or when stalled for update.
- Decoder decoder;
- bool discarding;
-
-
- // Remaining members are protected by lock.
- mutable sys::Monitor lock;
-
-
- // Local cluster state, cluster map
- enum {
- PRE_INIT,///< Have not yet received complete initial status map.
- INIT, ///< Waiting to reach cluster-size.
- JOINER, ///< Sent update request, waiting for update offer.
- UPDATEE, ///< Stalled receive queue at update offer, waiting for update to complete.
- CATCHUP, ///< Update complete, unstalled but has not yet seen own "ready" event.
- READY, ///< Fully operational
- OFFER, ///< Sent an offer, waiting for accept/reject.
- UPDATER, ///< Offer accepted, sending a state update.
- LEFT ///< Final state, left the cluster.
- } state;
-
- ConnectionMap connections;
- InitialStatusMap initMap;
- StoreStatus store;
- ClusterMap map;
- MemberSet elders;
- bool elder;
- size_t lastAliveCount;
- bool lastBroker;
- sys::Thread updateThread;
- boost::optional<ClusterMap> updatedMap;
- bool updateRetracted, updateClosed;
- ErrorCheck error;
- UpdateReceiver updateReceiver;
- ClusterTimer* timer;
- sys::Timer clockTimer;
- sys::AbsTime clusterTime;
- sys::Duration clusterTimeOffset;
- broker::AclModule* acl;
-
- friend std::ostream& operator<<(std::ostream&, const Cluster&);
- friend struct ClusterDispatcher;
-};
-
-}} // namespace qpid::cluster
-
-
-
-#endif /*!QPID_CLUSTER_CLUSTER_H*/
diff --git a/cpp/src/qpid/cluster/ClusterMap.cpp b/cpp/src/qpid/cluster/ClusterMap.cpp
deleted file mode 100644
index d9817db35f..0000000000
--- a/cpp/src/qpid/cluster/ClusterMap.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/ClusterMap.h"
-#include "qpid/Url.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/framing/FieldValue.h"
-#include "qpid/log/Statement.h"
-#include <boost/bind.hpp>
-#include <algorithm>
-#include <functional>
-#include <iterator>
-#include <ostream>
-
-using namespace std;
-using boost::ref;
-using boost::optional;
-
-namespace qpid {
-using namespace framing;
-
-namespace cluster {
-
-namespace {
-
-void addFieldTableValue(FieldTable::ValueMap::value_type vt, ClusterMap::Map& map, ClusterMap::Set& set) {
- MemberId id(vt.first);
- set.insert(id);
- string url = vt.second->get<string>();
- if (!url.empty())
- map.insert(ClusterMap::Map::value_type(id, Url(url)));
-}
-
-void insertFieldTableFromMapValue(FieldTable& ft, const ClusterMap::Map::value_type& vt) {
- ft.setString(vt.first.str(), vt.second.str());
-}
-
-}
-
-ClusterMap::ClusterMap() : frameSeq(0) {}
-
-ClusterMap::ClusterMap(const Map& map) : frameSeq(0) {
- transform(map.begin(), map.end(), inserter(alive, alive.begin()), bind(&Map::value_type::first, _1));
- members = map;
-}
-
-ClusterMap::ClusterMap(const FieldTable& joinersFt, const FieldTable& membersFt,
- framing::SequenceNumber frameSeq_)
- : frameSeq(frameSeq_)
-{
- for_each(joinersFt.begin(), joinersFt.end(), bind(&addFieldTableValue, _1, ref(joiners), ref(alive)));
- for_each(membersFt.begin(), membersFt.end(), bind(&addFieldTableValue, _1, ref(members), ref(alive)));
-}
-
-void ClusterMap::toMethodBody(framing::ClusterConnectionMembershipBody& b) const {
- b.getJoiners().clear();
- for_each(joiners.begin(), joiners.end(), bind(&insertFieldTableFromMapValue, ref(b.getJoiners()), _1));
- for(Set::const_iterator i = alive.begin(); i != alive.end(); ++i) {
- if (!isMember(*i) && !isJoiner(*i))
- b.getJoiners().setString(i->str(), string());
- }
- b.getMembers().clear();
- for_each(members.begin(), members.end(), bind(&insertFieldTableFromMapValue, ref(b.getMembers()), _1));
- b.setFrameSeq(frameSeq);
-}
-
-Url ClusterMap::getUrl(const Map& map, const MemberId& id) {
- Map::const_iterator i = map.find(id);
- return i == map.end() ? Url() : i->second;
-}
-
-MemberId ClusterMap::firstJoiner() const {
- return joiners.empty() ? MemberId() : joiners.begin()->first;
-}
-
-vector<string> ClusterMap::memberIds() const {
- vector<string> ids;
- for (Map::const_iterator iter = members.begin();
- iter != members.end(); iter++) {
- stringstream stream;
- stream << iter->first;
- ids.push_back(stream.str());
- }
- return ids;
-}
-
-vector<Url> ClusterMap::memberUrls() const {
- vector<Url> urls(members.size());
- transform(members.begin(), members.end(), urls.begin(),
- bind(&Map::value_type::second, _1));
- return urls;
-}
-
-ClusterMap::Set ClusterMap::getAlive() const { return alive; }
-
-ClusterMap::Set ClusterMap::getMembers() const {
- Set s;
- transform(members.begin(), members.end(), inserter(s, s.begin()),
- bind(&Map::value_type::first, _1));
- return s;
-}
-
-ostream& operator<<(ostream& o, const ClusterMap::Map& m) {
- ostream_iterator<MemberId> oi(o);
- transform(m.begin(), m.end(), oi, bind(&ClusterMap::Map::value_type::first, _1));
- return o;
-}
-
-ostream& operator<<(ostream& o, const ClusterMap& m) {
- for (ClusterMap::Set::const_iterator i = m.alive.begin(); i != m.alive.end(); ++i) {
- o << *i;
- if (m.isMember(*i)) o << "(member)";
- else if (m.isJoiner(*i)) o << "(joiner)";
- else o << "(unknown)";
- o << " ";
- }
- o << "frameSeq=" << m.getFrameSeq();
- return o;
-}
-
-bool ClusterMap::updateRequest(const MemberId& id, const string& url) {
- try {
- if (isAlive(id)) {
- joiners[id] = Url(url);
- return true;
- }
- } catch (const Url::Invalid&) {
- QPID_LOG(error, "Invalid URL in cluster update request: " << url);
- }
- return false;
-}
-
-bool ClusterMap::ready(const MemberId& id, const Url& url) {
- return isAlive(id) && members.insert(Map::value_type(id,url)).second;
-}
-
-bool ClusterMap::configChange(const Set& update) {
- bool memberChange = false;
- Set removed;
- set_difference(alive.begin(), alive.end(),
- update.begin(), update.end(),
- inserter(removed, removed.begin()));
- alive = update;
- for (Set::const_iterator i = removed.begin(); i != removed.end(); ++i) {
- memberChange = memberChange || members.erase(*i);
- joiners.erase(*i);
- }
- return memberChange;
-}
-
-optional<Url> ClusterMap::updateOffer(const MemberId& from, const MemberId& to) {
- Map::iterator i = joiners.find(to);
- if (isAlive(from) && i != joiners.end()) {
- Url url= i->second;
- joiners.erase(i); // No longer a potential updatee.
- return url;
- }
- return optional<Url>();
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ClusterMap.h b/cpp/src/qpid/cluster/ClusterMap.h
deleted file mode 100644
index cfa4ad924a..0000000000
--- a/cpp/src/qpid/cluster/ClusterMap.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef QPID_CLUSTER_CLUSTERMAP_H
-#define QPID_CLUSTER_CLUSTERMAP_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "MemberSet.h"
-#include "qpid/Url.h"
-#include "qpid/framing/ClusterConnectionMembershipBody.h"
-#include "qpid/framing/SequenceNumber.h"
-
-#include <boost/function.hpp>
-#include <boost/optional.hpp>
-
-#include <vector>
-#include <deque>
-#include <map>
-#include <iosfwd>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Map of established cluster members and joiners waiting for an update,
- * along with other cluster state that must be updated.
- */
-class ClusterMap {
- public:
- typedef std::map<MemberId, Url> Map;
- typedef std::set<MemberId> Set;
-
- ClusterMap();
- ClusterMap(const Map& map);
- ClusterMap(const framing::FieldTable& joiners, const framing::FieldTable& members,
- framing::SequenceNumber frameSeq);
-
- /** Update from config change.
- *@return true if member set changed.
- */
- bool configChange(const Set& members);
-
- bool isJoiner(const MemberId& id) const { return joiners.find(id) != joiners.end(); }
- bool isMember(const MemberId& id) const { return members.find(id) != members.end(); }
- bool isAlive(const MemberId& id) const { return alive.find(id) != alive.end(); }
-
- Url getJoinerUrl(const MemberId& id) { return getUrl(joiners, id); }
- Url getMemberUrl(const MemberId& id) { return getUrl(members, id); }
-
- /** First joiner in the cluster in ID order, target for offers */
- MemberId firstJoiner() const;
-
- /** Convert map contents to a cluster control body. */
- void toMethodBody(framing::ClusterConnectionMembershipBody&) const;
-
- size_t aliveCount() const { return alive.size(); }
- size_t memberCount() const { return members.size(); }
- std::vector<std::string> memberIds() const;
- std::vector<Url> memberUrls() const;
- Set getAlive() const;
- Set getMembers() const;
-
- bool updateRequest(const MemberId& id, const std::string& url);
- /** Return non-empty Url if accepted */
- boost::optional<Url> updateOffer(const MemberId& from, const MemberId& to);
-
- /**@return true If this is a new member */
- bool ready(const MemberId& id, const Url&);
-
- framing::SequenceNumber getFrameSeq() const { return frameSeq; }
- framing::SequenceNumber incrementFrameSeq() { return ++frameSeq; }
-
- /** Clear out all knowledge of joiners & members, just keep alive set */
- void clearStatus() { joiners.clear(); members.clear(); }
-
- private:
- Url getUrl(const Map& map, const MemberId& id);
-
- Map joiners, members;
- Set alive;
- framing::SequenceNumber frameSeq;
-
- friend std::ostream& operator<<(std::ostream&, const Map&);
- friend std::ostream& operator<<(std::ostream&, const ClusterMap&);
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_CLUSTERMAP_H*/
diff --git a/cpp/src/qpid/cluster/ClusterPlugin.cpp b/cpp/src/qpid/cluster/ClusterPlugin.cpp
deleted file mode 100644
index 69ba095f16..0000000000
--- a/cpp/src/qpid/cluster/ClusterPlugin.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "config.h"
-#include "qpid/cluster/Connection.h"
-#include "qpid/cluster/ConnectionCodec.h"
-#include "qpid/cluster/ClusterSettings.h"
-
-#include "qpid/cluster/SecureConnectionFactory.h"
-
-#include "qpid/cluster/Cluster.h"
-#include "qpid/cluster/ConnectionCodec.h"
-#include "qpid/cluster/UpdateClient.h"
-
-#include "qpid/broker/Broker.h"
-#include "qpid/Plugin.h"
-#include "qpid/Options.h"
-#include "qpid/sys/AtomicValue.h"
-#include "qpid/log/Statement.h"
-
-#include "qpid/management/ManagementAgent.h"
-#include "qpid/broker/Exchange.h"
-#include "qpid/broker/Message.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/SessionState.h"
-#include "qpid/client/ConnectionSettings.h"
-
-#include <boost/shared_ptr.hpp>
-#include <boost/utility/in_place_factory.hpp>
-#include <boost/scoped_ptr.hpp>
-
-namespace qpid {
-namespace cluster {
-
-using namespace std;
-using broker::Broker;
-using management::ManagementAgent;
-
-
-/** Note separating options from settings to work around boost version differences.
- * Old boost takes a reference to options objects, but new boost makes a copy.
- * New boost allows a shared_ptr but that's not compatible with old boost.
- */
-struct ClusterOptions : public Options {
- ClusterSettings& settings;
-
- ClusterOptions(ClusterSettings& v) : Options("Cluster Options"), settings(v) {
- addOptions()
- ("cluster-name", optValue(settings.name, "NAME"), "Name of cluster to join")
- ("cluster-url", optValue(settings.url,"URL"),
- "Set URL of this individual broker, to be advertized to clients.\n"
- "Defaults to a URL listing all the local IP addresses\n")
- ("cluster-username", optValue(settings.username, ""), "Username for connections between brokers")
- ("cluster-password", optValue(settings.password, ""), "Password for connections between brokers")
- ("cluster-mechanism", optValue(settings.mechanism, ""), "Authentication mechanism for connections between brokers")
-#if HAVE_LIBCMAN_H
- ("cluster-cman", optValue(settings.quorum), "Integrate with Cluster Manager (CMAN) cluster.")
-#endif
- ("cluster-size", optValue(settings.size, "N"), "Wait for N cluster members before allowing clients to connect.")
- ("cluster-clock-interval", optValue(settings.clockInterval,"N"), "How often to broadcast the current time to the cluster nodes, in milliseconds. A value between 5 and 1000 is recommended.")
- ("cluster-read-max", optValue(settings.readMax,"N"), "Experimental: flow-control limit reads per connection. 0=no limit.")
- ;
- }
-};
-
-typedef boost::shared_ptr<sys::ConnectionCodec::Factory> CodecFactoryPtr;
-
-struct ClusterPlugin : public Plugin {
-
- ClusterSettings settings;
- ClusterOptions options;
- Cluster* cluster;
- boost::scoped_ptr<ConnectionCodec::Factory> factory;
-
- ClusterPlugin() : options(settings), cluster(0) {}
-
- // Cluster needs to be initialized after the store
- int initOrder() const { return Plugin::DEFAULT_INIT_ORDER+500; }
-
- Options* getOptions() { return &options; }
-
- void earlyInitialize(Plugin::Target& target) {
- if (settings.name.empty()) return; // Only if --cluster-name option was specified.
- Broker* broker = dynamic_cast<Broker*>(&target);
- if (!broker) return;
- cluster = new Cluster(settings, *broker);
- CodecFactoryPtr simpleFactory(new broker::ConnectionFactory(*broker));
- CodecFactoryPtr clusterFactory(new ConnectionCodec::Factory(simpleFactory, *cluster));
- CodecFactoryPtr secureFactory(new SecureConnectionFactory(clusterFactory));
- broker->setConnectionFactory(secureFactory);
- }
-
- void disallowManagementMethods(ManagementAgent* agent) {
- if (!agent) return;
- agent->disallowV1Methods();
- }
-
- void initialize(Plugin::Target& target) {
- Broker* broker = dynamic_cast<Broker*>(&target);
- if (broker && cluster) {
- disallowManagementMethods(broker->getManagementAgent());
- cluster->initialize();
- }
- }
-};
-
-static ClusterPlugin instance; // Static initialization.
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ClusterSettings.h b/cpp/src/qpid/cluster/ClusterSettings.h
deleted file mode 100644
index 2f7b5be20a..0000000000
--- a/cpp/src/qpid/cluster/ClusterSettings.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef QPID_CLUSTER_CLUSTERSETTINGS_H
-#define QPID_CLUSTER_CLUSTERSETTINGS_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <qpid/Url.h>
-#include <string>
-
-namespace qpid {
-namespace cluster {
-
-struct ClusterSettings {
- std::string name;
- std::string url;
- bool quorum;
- size_t readMax;
- std::string username, password, mechanism;
- size_t size;
- uint16_t clockInterval;
-
- ClusterSettings() : quorum(false), readMax(10), size(1), clockInterval(10)
- {}
-
- Url getUrl(uint16_t port) const {
- if (url.empty()) return Url::getIpAddressesUrl(port);
- return Url(url);
- }
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_CLUSTERSETTINGS_H*/
diff --git a/cpp/src/qpid/cluster/ClusterTimer.cpp b/cpp/src/qpid/cluster/ClusterTimer.cpp
deleted file mode 100644
index 90e4fa9d4d..0000000000
--- a/cpp/src/qpid/cluster/ClusterTimer.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License "); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "Cluster.h"
-#include "ClusterTimer.h"
-#include "qpid/log/Statement.h"
-#include "qpid/framing/ClusterTimerWakeupBody.h"
-#include "qpid/framing/ClusterTimerDropBody.h"
-#include "qpid/sys/ClusterSafe.h"
-
-namespace qpid {
-namespace cluster {
-
-using boost::intrusive_ptr;
-using std::max;
-using sys::Timer;
-using sys::TimerTask;
-
-//
-// Note on use of Broker::getTimer() rather than getClusterTime in broker code.
-// The following uses of getTimer() are cluster safe:
-//
-// LinkRegistry: maintenance visits in timer can call Bridge::create/cancel
-// but these don't modify any management state.
-//
-// broker::Connection:
-// - Heartbeats use ClusterOrderOutput to ensure consistency
-// - timeout: aborts connection in timer, cluster does an orderly connection close.
-//
-// SessionState: scheduledCredit - uses ClusterOrderProxy
-// Broker::queueCleaner: cluster implements ExpiryPolicy for consistent expiry.
-//
-// Broker::dtxManager: dtx disabled with cluster.
-//
-// requestIOProcessing: called in doOutput.
-//
-
-
-ClusterTimer::ClusterTimer(Cluster& c) : cluster(c) {
- // Allow more generous overrun threshold with cluster as we
- // have to do a CPG round trip before executing the task.
- overran = 10*sys::TIME_MSEC;
- late = 100*sys::TIME_MSEC;
-}
-
-ClusterTimer::~ClusterTimer() {}
-
-// Initialization or deliver thread.
-void ClusterTimer::add(intrusive_ptr<TimerTask> task)
-{
- QPID_LOG(trace, "Adding cluster timer task " << task->getName());
- Map::iterator i = map.find(task->getName());
- if (i != map.end())
- throw Exception(QPID_MSG("Task already exists with name " << task->getName()));
- map[task->getName()] = task;
-
- // Only the elder actually activates the task with the Timer base class.
- if (cluster.isElder()) {
- QPID_LOG(trace, "Elder activating cluster timer task " << task->getName());
- Timer::add(task);
- }
-}
-
-// Timer thread
-void ClusterTimer::fire(intrusive_ptr<TimerTask> t) {
- // Elder mcasts wakeup on fire, task is not fired until deliverWakeup
- if (cluster.isElder()) {
- QPID_LOG(trace, "Sending cluster timer wakeup " << t->getName());
- cluster.getMulticast().mcastControl(
- framing::ClusterTimerWakeupBody(framing::ProtocolVersion(), t->getName()),
- cluster.getId());
- }
- else
- QPID_LOG(trace, "Cluster timer task fired, but not elder " << t->getName());
-}
-
-// Timer thread
-void ClusterTimer::drop(intrusive_ptr<TimerTask> t) {
- // Elder mcasts drop, task is droped in deliverDrop
- if (cluster.isElder()) {
- QPID_LOG(trace, "Sending cluster timer drop " << t->getName());
- cluster.getMulticast().mcastControl(
- framing::ClusterTimerDropBody(framing::ProtocolVersion(), t->getName()),
- cluster.getId());
- }
- else
- QPID_LOG(trace, "Cluster timer task dropped, but not on elder " << t->getName());
-}
-
-// Deliver thread
-void ClusterTimer::deliverWakeup(const std::string& name) {
- QPID_LOG(trace, "Cluster timer wakeup delivered for " << name);
- qpid::sys::assertClusterSafe();
- Map::iterator i = map.find(name);
- if (i == map.end())
- throw Exception(QPID_MSG("Cluster timer wakeup non-existent task " << name));
- else {
- intrusive_ptr<TimerTask> t = i->second;
- map.erase(i);
- // Move the nextFireTime so readyToFire() is true. This is to ensure we
- // don't get an error if the fired task calls setupNextFire()
- t->setFired();
- Timer::fire(t);
- }
-}
-
-// Deliver thread
-void ClusterTimer::deliverDrop(const std::string& name) {
- QPID_LOG(trace, "Cluster timer drop delivered for " << name);
- Map::iterator i = map.find(name);
- if (i == map.end())
- throw Exception(QPID_MSG("Cluster timer drop non-existent task " << name));
- else {
- intrusive_ptr<TimerTask> t = i->second;
- map.erase(i);
- }
-}
-
-// Deliver thread
-void ClusterTimer::becomeElder() {
- for (Map::iterator i = map.begin(); i != map.end(); ++i) {
- Timer::add(i->second);
- }
-}
-
-}}
diff --git a/cpp/src/qpid/cluster/ClusterTimer.h b/cpp/src/qpid/cluster/ClusterTimer.h
deleted file mode 100644
index 69f6c622e4..0000000000
--- a/cpp/src/qpid/cluster/ClusterTimer.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef QPID_CLUSTER_CLUSTERTIMER_H
-#define QPID_CLUSTER_CLUSTERTIMER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/sys/Timer.h"
-#include <map>
-
-namespace qpid {
-namespace cluster {
-
-class Cluster;
-
-/**
- * Timer implementation that executes tasks consistently in the
- * deliver thread across a cluster. Task is not executed when timer
- * fires, instead the elder multicasts a wakeup. The task is executed
- * when the wakeup is delivered.
- */
-class ClusterTimer : public sys::Timer {
- public:
- ClusterTimer(Cluster&);
- ~ClusterTimer();
-
- void add(boost::intrusive_ptr<sys::TimerTask> task);
-
- void deliverWakeup(const std::string& name);
- void deliverDrop(const std::string& name);
- void becomeElder();
-
- protected:
- void fire(boost::intrusive_ptr<sys::TimerTask> task);
- void drop(boost::intrusive_ptr<sys::TimerTask> task);
-
- private:
- typedef std::map<std::string, boost::intrusive_ptr<sys::TimerTask> > Map;
- Cluster& cluster;
- Map map;
-};
-
-
-}}
-
-
-#endif /*!QPID_CLUSTER_CLUSTERTIMER_H*/
diff --git a/cpp/src/qpid/cluster/Connection.cpp b/cpp/src/qpid/cluster/Connection.cpp
deleted file mode 100644
index ff855eef18..0000000000
--- a/cpp/src/qpid/cluster/Connection.cpp
+++ /dev/null
@@ -1,878 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/amqp_0_10/Codecs.h"
-#include "Connection.h"
-#include "UpdateClient.h"
-#include "Cluster.h"
-#include "UpdateReceiver.h"
-#include "qpid/assert.h"
-#include "qpid/broker/DtxAck.h"
-#include "qpid/broker/DtxBuffer.h"
-#include "qpid/broker/SessionState.h"
-#include "qpid/broker/SemanticState.h"
-#include "qpid/broker/TxBuffer.h"
-#include "qpid/broker/TxPublish.h"
-#include "qpid/broker/TxAccept.h"
-#include "qpid/broker/RecoveredEnqueue.h"
-#include "qpid/broker/RecoveredDequeue.h"
-#include "qpid/broker/Exchange.h"
-#include "qpid/broker/Fairshare.h"
-#include "qpid/broker/Link.h"
-#include "qpid/broker/Bridge.h"
-#include "qpid/broker/StatefulQueueObserver.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/framing/enum.h"
-#include "qpid/framing/AMQFrame.h"
-#include "qpid/framing/AllInvoker.h"
-#include "qpid/framing/DeliveryProperties.h"
-#include "qpid/framing/ClusterConnectionDeliverCloseBody.h"
-#include "qpid/framing/ClusterConnectionAnnounceBody.h"
-#include "qpid/framing/ConnectionCloseBody.h"
-#include "qpid/framing/ConnectionCloseOkBody.h"
-#include "qpid/framing/FieldValue.h"
-#include "qpid/log/Statement.h"
-#include "qpid/sys/ClusterSafe.h"
-#include "qpid/types/Variant.h"
-#include "qpid/management/ManagementAgent.h"
-#include <boost/current_function.hpp>
-
-
-namespace qpid {
-namespace cluster {
-
-using std::string;
-
-using namespace framing;
-using namespace framing::cluster;
-using amqp_0_10::ListCodec;
-using types::Variant;
-
-qpid::sys::AtomicValue<uint64_t> Connection::catchUpId(0x5000000000000000LL);
-
-Connection::NullFrameHandler Connection::nullFrameHandler;
-
-struct NullFrameHandler : public framing::FrameHandler {
- void handle(framing::AMQFrame&) {}
-};
-
-
-namespace {
-sys::AtomicValue<uint64_t> idCounter;
-const std::string shadowPrefix("[shadow]");
-}
-
-
-// Shadow connection
-Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
- const std::string& mgmtId,
- const ConnectionId& id, const qpid::sys::SecuritySettings& external)
- : cluster(c), self(id), catchUp(false), announced(false), output(*this, out),
- connectionCtor(&output, cluster.getBroker(), mgmtId, external,
- false/*isLink*/, 0/*objectId*/, true/*shadow*/, false/*delayManagement*/,
- false/*authenticated*/),
- expectProtocolHeader(false),
- mcastFrameHandler(cluster.getMulticast(), self),
- updateIn(c.getUpdateReceiver()),
- secureConnection(0)
-{}
-
-// Local connection
-Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out,
- const std::string& mgmtId, MemberId member,
- bool isCatchUp, bool isLink, const qpid::sys::SecuritySettings& external
-) : cluster(c), self(member, ++idCounter), catchUp(isCatchUp), announced(false), output(*this, out),
- connectionCtor(&output, cluster.getBroker(),
- mgmtId,
- external,
- isLink,
- isCatchUp ? ++catchUpId : 0,
- // The first catch-up connection is not a shadow
- isCatchUp && self.second > 1,
- false, // delayManagement
- true), // catch up connecytions are authenticated
- expectProtocolHeader(isLink),
- mcastFrameHandler(cluster.getMulticast(), self),
- updateIn(c.getUpdateReceiver()),
- secureConnection(0)
-{
- if (isLocalClient()) {
- giveReadCredit(cluster.getSettings().readMax); // Flow control
- // Delay adding the connection to the management map until announce()
- connectionCtor.delayManagement = true;
- }
- else {
- // Catch-up shadow connections initialized using nextShadow id.
- assert(catchUp);
- if (!updateIn.nextShadowMgmtId.empty())
- connectionCtor.mgmtId = updateIn.nextShadowMgmtId;
- updateIn.nextShadowMgmtId.clear();
- }
- init();
- QPID_LOG(debug, cluster << " local connection " << *this);
-}
-
-void Connection::setSecureConnection(broker::SecureConnection* sc) {
- secureConnection = sc;
- if (connection.get()) connection->setSecureConnection(sc);
-}
-
-void Connection::init() {
- connection = connectionCtor.construct();
- if (isLocalClient()) {
- if (secureConnection) connection->setSecureConnection(secureConnection);
- // Actively send cluster-order frames from local node
- connection->setClusterOrderOutput(mcastFrameHandler);
- }
- else { // Shadow or catch-up connection
- // Passive, discard cluster-order frames
- connection->setClusterOrderOutput(nullFrameHandler);
- }
- if (!isCatchUp())
- connection->setErrorListener(this);
-}
-
-// Called when we have consumed a read buffer to give credit to the
-// connection layer to continue reading.
-void Connection::giveReadCredit(int credit) {
- if (cluster.getSettings().readMax && credit)
- output.giveReadCredit(credit);
-}
-
-void Connection::announce(
- const std::string& mgmtId, uint32_t ssf, const std::string& authid, bool nodict,
- const std::string& username, const std::string& initialFrames)
-{
- QPID_ASSERT(mgmtId == connectionCtor.mgmtId);
- QPID_ASSERT(ssf == connectionCtor.external.ssf);
- QPID_ASSERT(authid == connectionCtor.external.authid);
- QPID_ASSERT(nodict == connectionCtor.external.nodict);
- // Local connections are already initialized but with management delayed.
- if (isLocalClient()) {
- connection->addManagementObject();
- }
- else if (isShadow()) {
- init();
- // Play initial frames into the connection.
- Buffer buf(const_cast<char*>(initialFrames.data()), initialFrames.size());
- AMQFrame frame;
- while (frame.decode(buf))
- connection->received(frame);
- connection->setUserId(username);
- }
- // Do managment actions now that the connection is replicated.
- connection->raiseConnectEvent();
- QPID_LOG(debug, cluster << " replicated connection " << *this);
-}
-
-Connection::~Connection() {
- if (connection.get()) connection->setErrorListener(0);
- // Don't trigger cluster-safe asserts in broker:: ~Connection as
- // it may be called in an IO thread context during broker
- // shutdown.
- sys::ClusterSafeScope css;
- connection.reset();
-}
-
-bool Connection::doOutput() {
- return output.doOutput();
-}
-
-// Received from a directly connected client.
-void Connection::received(framing::AMQFrame& f) {
- if (!connection.get()) {
- QPID_LOG(warning, cluster << " ignoring frame on closed connection "
- << *this << ": " << f);
- return;
- }
- QPID_LOG_IF(trace, Cluster::loggable(f), cluster << " RECV " << *this << ": " << f);
- if (isLocal()) { // Local catch-up connection.
- currentChannel = f.getChannel();
- if (!framing::invoke(*this, *f.getBody()).wasHandled())
- connection->received(f);
- }
- else { // Shadow or updated catch-up connection.
- if (f.getMethod() && f.getMethod()->isA<ConnectionCloseBody>()) {
- if (isShadow())
- cluster.addShadowConnection(this);
- AMQFrame ok((ConnectionCloseOkBody()));
- connection->getOutput().send(ok);
- output.closeOutput();
- catchUp = false;
- }
- else
- QPID_LOG(warning, cluster << " ignoring unexpected frame " << *this << ": " << f);
- }
-}
-
-bool Connection::checkUnsupported(const AMQBody&) {
- // Throw an exception for unsupported commands. Currently all are supported.
- return false;
-}
-
-struct GiveReadCreditOnExit {
- Connection& connection;
- int credit;
- GiveReadCreditOnExit(Connection& connection_, int credit_) :
- connection(connection_), credit(credit_) {}
- ~GiveReadCreditOnExit() { if (credit) connection.giveReadCredit(credit); }
-};
-
-void Connection::deliverDoOutput(uint32_t limit) {
- output.deliverDoOutput(limit);
-}
-
-// Called in delivery thread, in cluster order.
-void Connection::deliveredFrame(const EventFrame& f) {
- GiveReadCreditOnExit gc(*this, f.readCredit);
- assert(!catchUp);
- currentChannel = f.frame.getChannel();
- if (f.frame.getBody() // frame can be emtpy with just readCredit
- && !framing::invoke(*this, *f.frame.getBody()).wasHandled() // Connection contol.
- && !checkUnsupported(*f.frame.getBody())) // Unsupported operation.
- {
- if (f.type == DATA) // incoming data frames to broker::Connection
- connection->received(const_cast<AMQFrame&>(f.frame));
- else { // frame control, send frame via SessionState
- broker::SessionState* ss = connection->getChannel(currentChannel).getSession();
- if (ss) ss->out(const_cast<AMQFrame&>(f.frame));
- }
- }
-}
-
-// A local connection is closed by the network layer. Called in the connection thread.
-void Connection::closed() {
- try {
- if (isUpdated()) {
- QPID_LOG(debug, cluster << " update connection closed " << *this);
- close();
- cluster.updateInClosed();
- }
- else if (catchUp && cluster.isExpectingUpdate()) {
- QPID_LOG(critical, cluster << " catch-up connection closed prematurely " << *this);
- cluster.leave();
- }
- else if (isLocal()) {
- // This was a local replicated connection. Multicast a deliver
- // closed and process any outstanding frames from the cluster
- // until self-delivery of deliver-close.
- output.closeOutput();
- if (announced)
- cluster.getMulticast().mcastControl(
- ClusterConnectionDeliverCloseBody(), self);
- else
- close();
- }
- }
- catch (const std::exception& e) {
- QPID_LOG(error, cluster << " error closing connection " << *this << ": " << e.what());
- }
-}
-
-// Self-delivery of close message, close the connection.
-void Connection::deliverClose () {
- close();
- cluster.erase(self);
-}
-
-// Close the connection
-void Connection::close() {
- if (connection.get()) {
- QPID_LOG(debug, cluster << " closed connection " << *this);
- connection->closed();
- connection.reset();
- }
-}
-
-// The connection has sent invalid data and should be aborted.
-// All members will get the same abort since they all process the same data.
-void Connection::abort() {
- connection->abort();
- // Aborting the connection will result in a call to ::closed()
- // and allow the connection to close in an orderly manner.
-}
-
-// ConnectionCodec::decode receives read buffers from directly-connected clients.
-size_t Connection::decode(const char* data, size_t size) {
- GiveReadCreditOnExit grc(*this, 1); // Give a read credit by default.
- const char* ptr = data;
- const char* end = data + size;
- if (catchUp) { // Handle catch-up locally.
- if (!cluster.isExpectingUpdate()) {
- QPID_LOG(error, "Rejecting unexpected catch-up connection.");
- abort(); // Cluster is not expecting catch-up connections.
- }
- bool wasOpen = connection->isOpen();
- Buffer buf(const_cast<char*>(ptr), size);
- ptr += size;
- while (localDecoder.decode(buf))
- received(localDecoder.getFrame());
- if (!wasOpen && connection->isOpen()) {
- // Connections marked with setUserProxyAuth are allowed to proxy
- // messages with user-ID that doesn't match the connection's
- // authenticated ID. This is important for updates.
- connection->setUserProxyAuth(isCatchUp());
- }
- }
- else { // Multicast local connections.
- assert(isLocalClient());
- assert(connection.get());
- if (!checkProtocolHeader(ptr, size)) // Updates ptr
- return 0; // Incomplete header
-
- if (!connection->isOpen())
- processInitialFrames(ptr, end-ptr); // Updates ptr
-
- if (connection->isOpen() && end - ptr > 0) {
- // We're multi-casting, we will give read credit on delivery.
- grc.credit = 0;
- cluster.getMulticast().mcastBuffer(ptr, end - ptr, self);
- ptr = end;
- }
- }
- return ptr - data;
-}
-
-// Decode the protocol header if needed. Updates data and size
-// returns true if the header is complete or already read.
-bool Connection::checkProtocolHeader(const char*& data, size_t size) {
- if (expectProtocolHeader) {
- // This is an outgoing link connection, we will receive a protocol
- // header which needs to be decoded first
- framing::ProtocolInitiation pi;
- Buffer buf(const_cast<char*&>(data), size);
- if (pi.decode(buf)) {
- //TODO: check the version is correct
- expectProtocolHeader = false;
- data += pi.encodedSize();
- } else {
- return false;
- }
- }
- return true;
-}
-
-void Connection::processInitialFrames(const char*& ptr, size_t size) {
- // Process the initial negotiation locally and store it so
- // it can be replayed on other brokers in announce()
- Buffer buf(const_cast<char*>(ptr), size);
- framing::AMQFrame frame;
- while (!connection->isOpen() && frame.decode(buf))
- received(frame);
- initialFrames.append(ptr, buf.getPosition());
- ptr += buf.getPosition();
- if (connection->isOpen()) { // initial negotiation complete
- cluster.getMulticast().mcastControl(
- ClusterConnectionAnnounceBody(
- ProtocolVersion(),
- connectionCtor.mgmtId,
- connectionCtor.external.ssf,
- connectionCtor.external.authid,
- connectionCtor.external.nodict,
- connection->getUserId(),
- initialFrames),
- getId());
- announced = true;
- initialFrames.clear();
- }
-}
-
-broker::SessionState& Connection::sessionState() {
- return *connection->getChannel(currentChannel).getSession();
-}
-
-broker::SemanticState& Connection::semanticState() {
- return sessionState().getSemanticState();
-}
-
-void Connection::shadowPrepare(const std::string& mgmtId) {
- updateIn.nextShadowMgmtId = mgmtId;
-}
-
-void Connection::shadowSetUser(const std::string& userId) {
- connection->setUserId(userId);
-}
-
-void Connection::consumerState(const string& name, bool blocked, bool notifyEnabled, const SequenceNumber& position,
- uint32_t usedMsgCredit, uint32_t usedByteCredit, const uint32_t deliveryCount)
-{
- broker::SemanticState::ConsumerImpl::shared_ptr c = semanticState().find(name);
- c->setPosition(position);
- c->setBlocked(blocked);
- c->setDeliveryCount(deliveryCount);
- if (c->getCredit().isWindowMode()) c->getCredit().consume(usedMsgCredit, usedByteCredit);
- if (notifyEnabled) c->enableNotify(); else c->disableNotify();
- updateIn.consumerNumbering.add(c);
-}
-
-
-void Connection::sessionState(
- const SequenceNumber& replayStart,
- const SequenceNumber& sendCommandPoint,
- const SequenceSet& sentIncomplete,
- const SequenceNumber& expected,
- const SequenceNumber& received,
- const SequenceSet& unknownCompleted,
- const SequenceSet& receivedIncomplete,
- bool dtxSelected)
-{
- sessionState().setState(
- replayStart,
- sendCommandPoint,
- sentIncomplete,
- expected,
- received,
- unknownCompleted,
- receivedIncomplete);
- if (dtxSelected) semanticState().selectDtx();
- QPID_LOG(debug, cluster << " received session state update for "
- << sessionState().getId());
- // The output tasks will be added later in the update process.
- connection->getOutputTasks().removeAll();
-}
-
-void Connection::outputTask(uint16_t channel, const std::string& name) {
- broker::SessionState* session = connection->getChannel(channel).getSession();
- if (!session)
- throw Exception(QPID_MSG(cluster << " channel not attached " << *this
- << "[" << channel << "] "));
- OutputTask* task = session->getSemanticState().find(name).get();
- connection->getOutputTasks().addOutputTask(task);
-}
-
-void Connection::shadowReady(
- uint64_t memberId, uint64_t connectionId, const string& mgmtId,
- const string& username, const string& fragment, uint32_t sendMax)
-{
- QPID_ASSERT(mgmtId == getBrokerConnection()->getMgmtId());
- ConnectionId shadowId = ConnectionId(memberId, connectionId);
- QPID_LOG(debug, cluster << " catch-up connection " << *this
- << " becomes shadow " << shadowId);
- self = shadowId;
- connection->setUserId(username);
- // OK to use decoder here because cluster is stalled for update.
- cluster.getDecoder().get(self).setFragment(fragment.data(), fragment.size());
- connection->setErrorListener(this);
- output.setSendMax(sendMax);
-}
-
-void Connection::setDtxBuffer(const UpdateReceiver::DtxBufferRef& bufRef) {
- broker::DtxManager& mgr = cluster.getBroker().getDtxManager();
- broker::DtxWorkRecord* record = mgr.getWork(bufRef.xid);
- broker::DtxBuffer::shared_ptr buffer = (*record)[bufRef.index];
- if (bufRef.suspended)
- bufRef.semanticState->getSuspendedXids()[bufRef.xid] = buffer;
- else
- bufRef.semanticState->setDtxBuffer(buffer);
-}
-
-// Marks the end of the update.
-void Connection::membership(const FieldTable& joiners, const FieldTable& members,
- const framing::SequenceNumber& frameSeq)
-{
- QPID_LOG(debug, cluster << " incoming update complete on connection " << *this);
- updateIn.consumerNumbering.clear();
- for_each(updateIn.dtxBuffers.begin(), updateIn.dtxBuffers.end(),
- boost::bind(&Connection::setDtxBuffer, this, _1));
- closeUpdated();
- cluster.updateInDone(ClusterMap(joiners, members, frameSeq));
-}
-
-void Connection::retractOffer() {
- QPID_LOG(info, cluster << " incoming update retracted on connection " << *this);
- closeUpdated();
- cluster.updateInRetracted();
-}
-
-void Connection::closeUpdated() {
- self.second = 0; // Mark this as completed update connection.
- if (connection.get())
- connection->close(connection::CLOSE_CODE_NORMAL, "OK");
-}
-
-bool Connection::isLocal() const {
- return self.first == cluster.getId() && self.second;
-}
-
-bool Connection::isShadow() const {
- return self.first != cluster.getId();
-}
-
-bool Connection::isUpdated() const {
- return self.first == cluster.getId() && self.second == 0;
-}
-
-
-boost::shared_ptr<broker::Queue> Connection::findQueue(const std::string& qname) {
- boost::shared_ptr<broker::Queue> queue = cluster.getBroker().getQueues().find(qname);
- if (!queue) throw Exception(QPID_MSG(cluster << " can't find queue " << qname));
- return queue;
-}
-
-broker::QueuedMessage Connection::getUpdateMessage() {
- boost::shared_ptr<broker::Queue> updateq = findQueue(UpdateClient::UPDATE);
- assert(!updateq->isDurable());
- broker::QueuedMessage m = updateq->get();
- updateq->dequeue(0, m);
- if (!m.payload) throw Exception(QPID_MSG(cluster << " empty update queue"));
- return m;
-}
-
-void Connection::deliveryRecord(const string& qname,
- const SequenceNumber& position,
- const string& tag,
- const SequenceNumber& id,
- bool acquired,
- bool accepted,
- bool cancelled,
- bool completed,
- bool ended,
- bool windowing,
- bool enqueued,
- uint32_t credit)
-{
- broker::QueuedMessage m;
- broker::Queue::shared_ptr queue = findQueue(qname);
- if (!ended) { // Has a message
- if (acquired) { // Message is on the update queue
- m = getUpdateMessage();
- m.queue = queue.get();
- m.position = position;
- if (enqueued) queue->updateEnqueued(m); //inform queue of the message
- } else { // Message at original position in original queue
- queue->find(position, m);
- }
- // NOTE: removed:
- // if (!m.payload)
- // throw Exception(QPID_MSG("deliveryRecord no update message"));
- //
- // It seems this could happen legitimately in the case one
- // session browses message M, then another session acquires
- // it. In that case the browsers delivery record is !acquired
- // but the message is not on its original Queue. In that case
- // we'll get a deliveryRecord with no payload for the browser.
- //
- }
-
- // If a subscription is cancelled while there are unacked messages for it
- // there won't be a consumer. Just null it out in this case, it isn't needed.
- boost::shared_ptr<broker::Consumer> consumer;
- try { consumer = semanticState().find(tag); }
- catch(...) {}
-
- broker::DeliveryRecord dr(
- m, queue, tag, consumer, acquired, accepted, windowing, credit);
- dr.setId(id);
- if (cancelled) dr.cancel(dr.getTag());
- if (completed) dr.complete();
- if (ended) dr.setEnded(); // Exsitance of message
-
- if (dtxBuffer) // Record for next dtx-ack
- dtxAckRecords.push_back(dr);
- else
- semanticState().record(dr); // Record on session's unacked list.
-}
-
-void Connection::queuePosition(const string& qname, const SequenceNumber& position) {
- findQueue(qname)->setPosition(position);
-}
-
-void Connection::queueFairshareState(const std::string& qname, const uint8_t priority, const uint8_t count)
-{
- if (!qpid::broker::Fairshare::setState(findQueue(qname)->getMessages(), priority, count)) {
- QPID_LOG(error, "Failed to set fair share state on queue " << qname << "; this will result in inconsistencies.");
- }
-}
-
-
-namespace {
-// find a StatefulQueueObserver that matches a given identifier
-class ObserverFinder {
- const std::string id;
- boost::shared_ptr<broker::QueueObserver> target;
- ObserverFinder(const ObserverFinder&) {}
- public:
- ObserverFinder(const std::string& _id) : id(_id) {}
- broker::StatefulQueueObserver *getObserver()
- {
- if (target)
- return dynamic_cast<broker::StatefulQueueObserver *>(target.get());
- return 0;
- }
- void operator() (boost::shared_ptr<broker::QueueObserver> o)
- {
- if (!target) {
- broker::StatefulQueueObserver *p = dynamic_cast<broker::StatefulQueueObserver *>(o.get());
- if (p && p->getId() == id) {
- target = o;
- }
- }
- }
-};
-}
-
-
-void Connection::queueObserverState(const std::string& qname, const std::string& observerId, const FieldTable& state)
-{
- boost::shared_ptr<broker::Queue> queue(findQueue(qname));
- ObserverFinder finder(observerId); // find this observer
- queue->eachObserver<ObserverFinder &>(finder);
- broker::StatefulQueueObserver *so = finder.getObserver();
- if (so) {
- so->setState( state );
- QPID_LOG(debug, "updated queue observer " << observerId << "'s state on queue " << qname << "; ...");
- return;
- }
- QPID_LOG(error, "Failed to find observer " << observerId << " state on queue " << qname << "; this will result in inconsistencies.");
-}
-
-std::ostream& operator<<(std::ostream& o, const Connection& c) {
- const char* type="unknown";
- if (c.isLocal()) type = "local";
- else if (c.isShadow()) type = "shadow";
- else if (c.isUpdated()) type = "updated";
- const broker::Connection* bc = c.getBrokerConnection();
- if (bc) o << bc->getMgmtId();
- else o << "<disconnected>";
- return o << "(" << c.getId() << " " << type << (c.isCatchUp() ? ",catchup":"") << ")";
-}
-
-void Connection::txStart() {
- txBuffer.reset(new broker::TxBuffer());
-}
-
-void Connection::txAccept(const framing::SequenceSet& acked) {
- txBuffer->enlist(boost::shared_ptr<broker::TxAccept>(
- new broker::TxAccept(acked, semanticState().getUnacked())));
-}
-
-void Connection::txDequeue(const std::string& queue) {
- txBuffer->enlist(boost::shared_ptr<broker::RecoveredDequeue>(
- new broker::RecoveredDequeue(findQueue(queue), getUpdateMessage().payload)));
-}
-
-void Connection::txEnqueue(const std::string& queue) {
- txBuffer->enlist(boost::shared_ptr<broker::RecoveredEnqueue>(
- new broker::RecoveredEnqueue(findQueue(queue), getUpdateMessage().payload)));
-}
-
-void Connection::txPublish(const framing::Array& queues, bool delivered)
-{
- boost::shared_ptr<broker::TxPublish> txPub(
- new broker::TxPublish(getUpdateMessage().payload));
- for (framing::Array::const_iterator i = queues.begin(); i != queues.end(); ++i)
- txPub->deliverTo(findQueue((*i)->get<std::string>()));
- txPub->delivered = delivered;
- txBuffer->enlist(txPub);
-}
-
-void Connection::txEnd() {
- semanticState().setTxBuffer(txBuffer);
-}
-
-void Connection::accumulatedAck(const qpid::framing::SequenceSet& s) {
- semanticState().setAccumulatedAck(s);
-}
-
-void Connection::dtxStart(const std::string& xid,
- bool ended,
- bool suspended,
- bool failed,
- bool expired)
-{
- dtxBuffer.reset(new broker::DtxBuffer(xid, ended, suspended, failed, expired));
- txBuffer = dtxBuffer;
-}
-
-void Connection::dtxEnd() {
- broker::DtxManager& mgr = cluster.getBroker().getDtxManager();
- std::string xid = dtxBuffer->getXid();
- if (mgr.exists(xid))
- mgr.join(xid, dtxBuffer);
- else
- mgr.start(xid, dtxBuffer);
- dtxBuffer.reset();
- txBuffer.reset();
-}
-
-// Sent after all DeliveryRecords for a dtx-ack have been collected in dtxAckRecords
-void Connection::dtxAck() {
- dtxBuffer->enlist(
- boost::shared_ptr<broker::DtxAck>(new broker::DtxAck(dtxAckRecords)));
- dtxAckRecords.clear();
-}
-
-void Connection::dtxBufferRef(const std::string& xid, uint32_t index, bool suspended) {
- // Save the association between DtxBuffers and the session so we
- // can set the DtxBuffers at the end of the update when the
- // DtxManager has been replicated.
- updateIn.dtxBuffers.push_back(
- UpdateReceiver::DtxBufferRef(xid, index, suspended, &semanticState()));
-}
-
-// Sent at end of work record.
-void Connection::dtxWorkRecord(const std::string& xid, bool prepared, uint32_t timeout)
-{
- broker::DtxManager& mgr = cluster.getBroker().getDtxManager();
- if (timeout) mgr.setTimeout(xid, timeout);
- if (prepared) mgr.prepare(xid);
-}
-
-
-void Connection::exchange(const std::string& encoded) {
- Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
- broker::Exchange::shared_ptr ex = broker::Exchange::decode(cluster.getBroker().getExchanges(), buf);
- if(ex.get() && ex->isDurable() && !ex->getName().find("amq.") == 0 && !ex->getName().find("qpid.") == 0) {
- cluster.getBroker().getStore().create(*(ex.get()), ex->getArgs());
- }
- QPID_LOG(debug, cluster << " updated exchange " << ex->getName());
-}
-
-void Connection::sessionError(uint16_t , const std::string& msg) {
- // Ignore errors before isOpen(), we're not multicasting yet.
- if (connection->isOpen())
- cluster.flagError(*this, ERROR_TYPE_SESSION, msg);
-}
-
-void Connection::connectionError(const std::string& msg) {
- // Ignore errors before isOpen(), we're not multicasting yet.
- if (connection->isOpen()) {
- cluster.flagError(*this, ERROR_TYPE_CONNECTION, msg);
- }
- else
- cluster.eraseLocal(self);
-}
-
-void Connection::addQueueListener(const std::string& q, uint32_t listener) {
- if (listener >= updateIn.consumerNumbering.size())
- throw Exception(QPID_MSG("Invalid listener ID: " << listener));
- findQueue(q)->getListeners().addListener(updateIn.consumerNumbering[listener]);
-}
-
-//
-// This is the handler for incoming managementsetup messages.
-//
-void Connection::managementSetupState(
- uint64_t objectNum, uint16_t bootSequence, const framing::Uuid& id,
- const std::string& vendor, const std::string& product, const std::string& instance)
-{
- QPID_LOG(debug, cluster << " updated management: object number="
- << objectNum << " boot sequence=" << bootSequence
- << " broker-id=" << id
- << " vendor=" << vendor
- << " product=" << product
- << " instance=" << instance);
- management::ManagementAgent* agent = cluster.getBroker().getManagementAgent();
- if (!agent)
- throw Exception(QPID_MSG("Management schema update but management not enabled."));
- agent->setNextObjectId(objectNum);
- agent->setBootSequence(bootSequence);
- agent->setUuid(id);
- agent->setName(vendor, product, instance);
-}
-
-void Connection::config(const std::string& encoded) {
- Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
- string kind;
- uint32_t p = buf.getPosition();
- buf.getShortString (kind);
- buf.setPosition(p);
- if (broker::Link::isEncodedLink(kind)) {
- broker::Link::shared_ptr link =
- broker::Link::decode(cluster.getBroker().getLinks(), buf);
- QPID_LOG(debug, cluster << " updated link "
- << link->getHost() << ":" << link->getPort());
- }
- else if (broker::Bridge::isEncodedBridge(kind)) {
- broker::Bridge::shared_ptr bridge =
- broker::Bridge::decode(cluster.getBroker().getLinks(), buf);
- QPID_LOG(debug, cluster << " updated bridge " << bridge->getName());
- }
- else throw Exception(QPID_MSG("Update failed, invalid kind of config: " << kind));
-}
-
-namespace {
- // find a Link that matches the given Address
- class LinkFinder {
- qpid::Address id;
- boost::shared_ptr<broker::Link> link;
- public:
- LinkFinder(const qpid::Address& _id) : id(_id) {}
- boost::shared_ptr<broker::Link> getLink() { return link; }
- void operator() (boost::shared_ptr<broker::Link> l)
- {
- if (!link) {
- qpid::Address addr(l->getTransport(), l->getHost(), l->getPort());
- if (id == addr) {
- link = l;
- }
- }
- }
- };
-}
-
-void Connection::internalState(const std::string& type,
- const std::string& name,
- const framing::FieldTable& state)
-{
- if (type == "link") {
- // name is the string representation of the Link's _configured_ destination address
- Url dest;
- try {
- dest = name;
- } catch(...) {
- throw Exception(QPID_MSG("Update failed, invalid format for Link destination address: " << name));
- }
- assert(dest.size());
- LinkFinder finder(dest[0]);
- cluster.getBroker().getLinks().eachLink(boost::ref(finder));
- if (finder.getLink()) {
- try {
- finder.getLink()->setState(state);
- } catch(...) {
- throw Exception(QPID_MSG("Update failed, invalid state for Link " << name << ", state: " << state));
- }
- QPID_LOG(debug, cluster << " updated link " << dest[0] << " with state: " << state);
- } else throw Exception(QPID_MSG("Update failed, unable to find Link named: " << name));
- }
- else throw Exception(QPID_MSG("Update failed, invalid object type for internal state replication: " << type));
-}
-
-
-void Connection::doCatchupIoCallbacks() {
- // We need to process IO callbacks during the catch-up phase in
- // order to service asynchronous completions for messages
- // transferred during catch-up.
-
- if (catchUp) getBrokerConnection()->doIoCallbacks();
-}
-
-void Connection::clock(uint64_t time) {
- QPID_LOG(debug, "Cluster connection received time update");
- cluster.clock(time);
-}
-
-void Connection::queueDequeueSincePurgeState(const std::string& qname, uint32_t dequeueSincePurge) {
- boost::shared_ptr<broker::Queue> queue(findQueue(qname));
- queue->setDequeueSincePurge(dequeueSincePurge);
-}
-
-}} // Namespace qpid::cluster
-
diff --git a/cpp/src/qpid/cluster/Connection.h b/cpp/src/qpid/cluster/Connection.h
deleted file mode 100644
index b0e7b3bd9e..0000000000
--- a/cpp/src/qpid/cluster/Connection.h
+++ /dev/null
@@ -1,302 +0,0 @@
-#ifndef QPID_CLUSTER_CONNECTION_H
-#define QPID_CLUSTER_CONNECTION_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "types.h"
-#include "OutputInterceptor.h"
-#include "McastFrameHandler.h"
-#include "UpdateReceiver.h"
-
-#include "qpid/RefCounted.h"
-#include "qpid/broker/Connection.h"
-#include "qpid/broker/DeliveryRecord.h"
-#include "qpid/broker/SecureConnection.h"
-#include "qpid/broker/SemanticState.h"
-#include "qpid/amqp_0_10/Connection.h"
-#include "qpid/sys/AtomicValue.h"
-#include "qpid/sys/ConnectionInputHandler.h"
-#include "qpid/sys/ConnectionOutputHandler.h"
-#include "qpid/sys/SecuritySettings.h"
-#include "qpid/framing/SequenceNumber.h"
-#include "qpid/framing/FrameDecoder.h"
-
-#include <iosfwd>
-
-namespace qpid {
-
-namespace framing { class AMQFrame; }
-
-namespace broker {
-class SemanticState;
-struct QueuedMessage;
-class TxBuffer;
-class TxAccept;
-}
-
-namespace cluster {
-class Cluster;
-class Event;
-struct EventFrame;
-
-/** Intercept broker::Connection calls for shadow and local cluster connections. */
-class Connection :
- public RefCounted,
- public sys::ConnectionInputHandler,
- public framing::AMQP_AllOperations::ClusterConnectionHandler,
- private broker::Connection::ErrorListener
-
-{
- public:
-
- /** Local connection. */
- Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& mgmtId, MemberId, bool catchUp, bool isLink,
- const qpid::sys::SecuritySettings& external);
- /** Shadow connection. */
- Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& mgmtId, const ConnectionId& id,
- const qpid::sys::SecuritySettings& external);
- ~Connection();
-
- ConnectionId getId() const { return self; }
- broker::Connection* getBrokerConnection() { return connection.get(); }
- const broker::Connection* getBrokerConnection() const { return connection.get(); }
-
- /** Local connections may be clients or catch-up connections */
- bool isLocal() const;
-
- bool isLocalClient() const { return isLocal() && !isCatchUp(); }
-
- /** True for connections that are shadowing remote broker connections */
- bool isShadow() const;
-
- /** True if the connection is in "catch-up" mode: building initial broker state. */
- bool isCatchUp() const { return catchUp; }
-
- /** True if the connection is a completed shared update connection */
- bool isUpdated() const;
-
- Cluster& getCluster() { return cluster; }
-
- // ConnectionInputHandler methods
- void received(framing::AMQFrame&);
- void closed();
- bool doOutput();
- void idleOut() { if (connection.get()) connection->idleOut(); }
- void idleIn() { if (connection.get()) connection->idleIn(); }
-
- // ConnectionCodec methods - called by IO layer with a read buffer.
- size_t decode(const char* buffer, size_t size);
-
- // Called for data delivered from the cluster.
- void deliveredFrame(const EventFrame&);
-
- void consumerState(const std::string& name, bool blocked, bool notifyEnabled, const qpid::framing::SequenceNumber& position,
- uint32_t usedMsgCredit, uint32_t usedByteCredit, const uint32_t deliveryCount);
-
- // ==== Used in catch-up mode to build initial state.
- //
- // State update methods.
- void shadowPrepare(const std::string&);
-
- void shadowSetUser(const std::string&);
-
- void sessionState(const framing::SequenceNumber& replayStart,
- const framing::SequenceNumber& sendCommandPoint,
- const framing::SequenceSet& sentIncomplete,
- const framing::SequenceNumber& expected,
- const framing::SequenceNumber& received,
- const framing::SequenceSet& unknownCompleted,
- const SequenceSet& receivedIncomplete,
- bool dtxSelected);
-
- void outputTask(uint16_t channel, const std::string& name);
-
- void shadowReady(uint64_t memberId,
- uint64_t connectionId,
- const std::string& managementId,
- const std::string& username,
- const std::string& fragment,
- uint32_t sendMax);
-
- void membership(const framing::FieldTable&, const framing::FieldTable&,
- const framing::SequenceNumber& frameSeq);
-
- void retractOffer();
-
- void deliveryRecord(const std::string& queue,
- const framing::SequenceNumber& position,
- const std::string& tag,
- const framing::SequenceNumber& id,
- bool acquired,
- bool accepted,
- bool cancelled,
- bool completed,
- bool ended,
- bool windowing,
- bool enqueued,
- uint32_t credit);
-
- void queuePosition(const std::string&, const framing::SequenceNumber&);
- void queueFairshareState(const std::string&, const uint8_t priority, const uint8_t count);
- void queueObserverState(const std::string&, const std::string&, const framing::FieldTable&);
-
- void txStart();
- void txAccept(const framing::SequenceSet&);
- void txDequeue(const std::string&);
- void txEnqueue(const std::string&);
- void txPublish(const framing::Array&, bool);
- void txEnd();
- void accumulatedAck(const framing::SequenceSet&);
-
- // Dtx state
- void dtxStart(const std::string& xid,
- bool ended,
- bool suspended,
- bool failed,
- bool expired);
- void dtxEnd();
- void dtxAck();
- void dtxBufferRef(const std::string& xid, uint32_t index, bool suspended);
- void dtxWorkRecord(const std::string& xid, bool prepared, uint32_t timeout);
-
- // Encoded exchange replication.
- void exchange(const std::string& encoded);
-
- void giveReadCredit(int credit);
- void announce(const std::string& mgmtId, uint32_t ssf, const std::string& authid,
- bool nodict, const std::string& username,
- const std::string& initFrames);
- void close();
- void abort();
- void deliverClose();
-
- OutputInterceptor& getOutput() { return output; }
-
- void addQueueListener(const std::string& queue, uint32_t listener);
- void managementSetupState(uint64_t objectNum,
- uint16_t bootSequence,
- const framing::Uuid&,
- const std::string& vendor,
- const std::string& product,
- const std::string& instance);
-
- void config(const std::string& encoded);
- void internalState(const std::string& type, const std::string& name,
- const framing::FieldTable& state);
-
- void setSecureConnection ( broker::SecureConnection * sc );
-
- void doCatchupIoCallbacks();
-
- void clock(uint64_t time);
-
- void queueDequeueSincePurgeState(const std::string&, uint32_t);
-
- bool isAnnounced() const { return announced; }
-
- private:
- struct NullFrameHandler : public framing::FrameHandler {
- void handle(framing::AMQFrame&) {}
- };
-
- // Arguments to construct a broker::Connection
- struct ConnectionCtor {
- sys::ConnectionOutputHandler* out;
- broker::Broker& broker;
- std::string mgmtId;
- qpid::sys::SecuritySettings external;
- bool isLink;
- uint64_t objectId;
- bool shadow;
- bool delayManagement;
- bool authenticated;
-
- ConnectionCtor(
- sys::ConnectionOutputHandler* out_,
- broker::Broker& broker_,
- const std::string& mgmtId_,
- const qpid::sys::SecuritySettings& external_,
- bool isLink_=false,
- uint64_t objectId_=0,
- bool shadow_=false,
- bool delayManagement_=false,
- bool authenticated_=true
- ) : out(out_), broker(broker_), mgmtId(mgmtId_), external(external_),
- isLink(isLink_), objectId(objectId_), shadow(shadow_),
- delayManagement(delayManagement_), authenticated(authenticated_)
- {}
-
- std::auto_ptr<broker::Connection> construct() {
- return std::auto_ptr<broker::Connection>(
- new broker::Connection(
- out, broker, mgmtId, external, isLink, objectId,
- shadow, delayManagement, authenticated)
- );
- }
- };
-
- static NullFrameHandler nullFrameHandler;
-
- // Error listener functions
- void connectionError(const std::string&);
- void sessionError(uint16_t channel, const std::string&);
-
- void init();
- bool checkUnsupported(const framing::AMQBody& body);
- void deliverDoOutput(uint32_t limit);
-
- bool checkProtocolHeader(const char*& data, size_t size);
- void processInitialFrames(const char*& data, size_t size);
- boost::shared_ptr<broker::Queue> findQueue(const std::string& qname);
- broker::SessionState& sessionState();
- broker::SemanticState& semanticState();
- broker::QueuedMessage getUpdateMessage();
- void closeUpdated();
- void setDtxBuffer(const UpdateReceiver::DtxBuffers::value_type &);
- Cluster& cluster;
- ConnectionId self;
- bool catchUp;
- bool announced;
- OutputInterceptor output;
- framing::FrameDecoder localDecoder;
- ConnectionCtor connectionCtor;
- std::auto_ptr<broker::Connection> connection;
- framing::SequenceNumber deliverSeq;
- framing::ChannelId currentChannel;
- boost::shared_ptr<broker::TxBuffer> txBuffer;
- boost::shared_ptr<broker::DtxBuffer> dtxBuffer;
- broker::DeliveryRecords dtxAckRecords;
- broker::DtxWorkRecord* dtxCurrent;
- bool expectProtocolHeader;
- McastFrameHandler mcastFrameHandler;
- UpdateReceiver& updateIn;
- qpid::broker::SecureConnection* secureConnection;
- std::string initialFrames;
-
- static qpid::sys::AtomicValue<uint64_t> catchUpId;
-
- friend std::ostream& operator<<(std::ostream&, const Connection&);
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_CONNECTION_H*/
diff --git a/cpp/src/qpid/cluster/ConnectionCodec.cpp b/cpp/src/qpid/cluster/ConnectionCodec.cpp
deleted file mode 100644
index 54327fbfe2..0000000000
--- a/cpp/src/qpid/cluster/ConnectionCodec.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/ConnectionCodec.h"
-#include "qpid/cluster/Connection.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/cluster/ProxyInputHandler.h"
-#include "qpid/broker/AclModule.h"
-#include "qpid/broker/Connection.h"
-#include "qpid/framing/ConnectionCloseBody.h"
-#include "qpid/framing/ConnectionCloseOkBody.h"
-#include "qpid/log/Statement.h"
-#include "qpid/memory.h"
-#include <stdexcept>
-#include <boost/utility/in_place_factory.hpp>
-
-namespace qpid {
-namespace cluster {
-
-using namespace framing;
-
-sys::ConnectionCodec*
-ConnectionCodec::Factory::create(ProtocolVersion v, sys::OutputControl& out,
- const std::string& id,
- const qpid::sys::SecuritySettings& external)
-{
- if (v == ProtocolVersion(0, 10))
- return new ConnectionCodec(v, out, id, cluster, false, false, external);
- else if (v == ProtocolVersion(0x80 + 0, 0x80 + 10)) // Catch-up connection
- return new ConnectionCodec(v, out, id, cluster, true, false, external);
- return 0;
-}
-
-// Used for outgoing Link connections
-sys::ConnectionCodec*
-ConnectionCodec::Factory::create(sys::OutputControl& out, const std::string& logId,
- const qpid::sys::SecuritySettings& external) {
- return new ConnectionCodec(ProtocolVersion(0,10), out, logId, cluster, false, true, external);
-}
-
-ConnectionCodec::ConnectionCodec(
- const ProtocolVersion& v, sys::OutputControl& out,
- const std::string& logId, Cluster& cluster, bool catchUp, bool isLink, const qpid::sys::SecuritySettings& external
-) : codec(out, logId, isLink),
- interceptor(new Connection(cluster, codec, logId, cluster.getId(), catchUp, isLink, external))
-{
- cluster.addLocalConnection(interceptor);
- std::auto_ptr<sys::ConnectionInputHandler> ih(new ProxyInputHandler(interceptor));
- codec.setInputHandler(ih);
- codec.setVersion(v);
-}
-
-ConnectionCodec::~ConnectionCodec() {}
-
-size_t ConnectionCodec::decode(const char* buffer, size_t size) {
- return interceptor->decode(buffer, size);
-}
-
-bool ConnectionCodec::isClosed() const { return codec.isClosed(); }
-
-size_t ConnectionCodec::encode(const char* buffer, size_t size) { return codec.encode(buffer, size); }
-
-bool ConnectionCodec::canEncode() { return codec.canEncode(); }
-
-void ConnectionCodec::closed() { codec.closed(); }
-
-ProtocolVersion ConnectionCodec::getVersion() const { return codec.getVersion(); }
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ConnectionCodec.h b/cpp/src/qpid/cluster/ConnectionCodec.h
deleted file mode 100644
index 17a08904d9..0000000000
--- a/cpp/src/qpid/cluster/ConnectionCodec.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef QPID_CLUSTER_CONNCTIONCODEC_H
-#define QPID_CLUSTER_CONNCTIONCODEC_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/amqp_0_10/Connection.h"
-#include "qpid/cluster/Connection.h"
-#include <boost/shared_ptr.hpp>
-#include <boost/intrusive_ptr.hpp>
-
-namespace qpid {
-
-namespace broker {
-class Connection;
-}
-
-namespace cluster {
-class Cluster;
-
-/**
- * Encapsulates the standard amqp_0_10::ConnectionCodec and sets up
- * a cluster::Connection for the connection.
- *
- * The ConnectionCodec is deleted by the network layer when the
- * connection closes. The cluster::Connection needs to be kept
- * around until all cluster business on the connection is complete.
- *
- */
-class ConnectionCodec : public sys::ConnectionCodec {
- public:
- struct Factory : public sys::ConnectionCodec::Factory {
- boost::shared_ptr<sys::ConnectionCodec::Factory> next;
- Cluster& cluster;
- Factory(boost::shared_ptr<sys::ConnectionCodec::Factory> f, Cluster& c)
- : next(f), cluster(c) {}
- sys::ConnectionCodec* create(framing::ProtocolVersion, sys::OutputControl&, const std::string& id,
- const qpid::sys::SecuritySettings& external);
- sys::ConnectionCodec* create(sys::OutputControl&, const std::string& id,
- const qpid::sys::SecuritySettings& external);
- };
-
- ConnectionCodec(const framing::ProtocolVersion&, sys::OutputControl& out,
- const std::string& logId, Cluster& c, bool catchUp, bool isLink,
- const qpid::sys::SecuritySettings& external);
- ~ConnectionCodec();
-
- // ConnectionCodec functions.
- size_t decode(const char* buffer, size_t size);
- size_t encode(const char* buffer, size_t size);
- bool canEncode();
- void closed();
- bool isClosed() const;
- framing::ProtocolVersion getVersion() const;
- void setSecureConnection(broker::SecureConnection* sc) { interceptor->setSecureConnection(sc); }
-
- private:
- amqp_0_10::Connection codec;
- boost::intrusive_ptr<cluster::Connection> interceptor;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_CONNCTIONCODEC_H*/
diff --git a/cpp/src/qpid/cluster/Cpg.cpp b/cpp/src/qpid/cluster/Cpg.cpp
deleted file mode 100644
index 6e9e22a42f..0000000000
--- a/cpp/src/qpid/cluster/Cpg.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "qpid/cluster/Cpg.h"
-#include "qpid/sys/Mutex.h"
-#include "qpid/sys/Time.h"
-#include "qpid/sys/posix/PrivatePosix.h"
-#include "qpid/log/Statement.h"
-
-#include <vector>
-#include <limits>
-#include <iterator>
-#include <sstream>
-
-#include <unistd.h>
-
-// This is a macro instead of a function because we don't want to
-// evaluate the MSG argument unless there is an error.
-#define CPG_CHECK(RESULT, MSG) \
- if ((RESULT) != CS_OK) throw Exception(errorStr((RESULT), (MSG)))
-
-namespace qpid {
-namespace cluster {
-
-using namespace std;
-
-
-
-Cpg* Cpg::cpgFromHandle(cpg_handle_t handle) {
- void* cpg=0;
- CPG_CHECK(cpg_context_get(handle, &cpg), "Cannot get CPG instance.");
- if (!cpg) throw Exception("Cannot get CPG instance.");
- return reinterpret_cast<Cpg*>(cpg);
-}
-
-// Applies the same retry-logic to all cpg calls that need it.
-void Cpg::callCpg ( CpgOp & c ) {
- cs_error_t result;
- unsigned int snooze = 10;
- for ( unsigned int nth_try = 0; nth_try < cpgRetries; ++ nth_try ) {
- if ( CS_OK == (result = c.op(handle, & group))) {
- break;
- }
- else if ( result == CS_ERR_TRY_AGAIN ) {
- QPID_LOG(info, "Retrying " << c.opName );
- sys::usleep ( snooze );
- snooze *= 10;
- snooze = (snooze <= maxCpgRetrySleep) ? snooze : maxCpgRetrySleep;
- }
- else break; // Don't retry unless CPG tells us to.
- }
-
- if ( result != CS_OK )
- CPG_CHECK(result, c.msg(group));
-}
-
-// Global callback functions.
-void Cpg::globalDeliver (
- cpg_handle_t handle,
- const struct cpg_name *group,
- uint32_t nodeid,
- uint32_t pid,
- void* msg,
- size_t msg_len)
-{
- cpgFromHandle(handle)->handler.deliver(handle, group, nodeid, pid, msg, msg_len);
-}
-
-void Cpg::globalConfigChange(
- cpg_handle_t handle,
- const struct cpg_name *group,
- const struct cpg_address *members, size_t nMembers,
- const struct cpg_address *left, size_t nLeft,
- const struct cpg_address *joined, size_t nJoined
-)
-{
- cpgFromHandle(handle)->handler.configChange(handle, group, members, nMembers, left, nLeft, joined, nJoined);
-}
-
-void Cpg::globalDeliver (
- cpg_handle_t handle,
- struct cpg_name *group,
- uint32_t nodeid,
- uint32_t pid,
- void* msg,
- int msg_len)
-{
- cpgFromHandle(handle)->handler.deliver(handle, group, nodeid, pid, msg, msg_len);
-}
-
-void Cpg::globalConfigChange(
- cpg_handle_t handle,
- struct cpg_name *group,
- struct cpg_address *members, int nMembers,
- struct cpg_address *left, int nLeft,
- struct cpg_address *joined, int nJoined
-)
-{
- cpgFromHandle(handle)->handler.configChange(handle, group, members, nMembers, left, nLeft, joined, nJoined);
-}
-
-int Cpg::getFd() {
- int fd;
- CPG_CHECK(cpg_fd_get(handle, &fd), "Cannot get CPG file descriptor");
- return fd;
-}
-
-Cpg::Cpg(Handler& h) : IOHandle(new sys::IOHandlePrivate), handler(h), isShutdown(false) {
- cpg_callbacks_t callbacks;
- ::memset(&callbacks, 0, sizeof(callbacks));
- callbacks.cpg_deliver_fn = &globalDeliver;
- callbacks.cpg_confchg_fn = &globalConfigChange;
-
- QPID_LOG(notice, "Initializing CPG");
- cs_error_t err = cpg_initialize(&handle, &callbacks);
- int retries = 6; // FIXME aconway 2009-08-06: make this configurable.
- while (err == CS_ERR_TRY_AGAIN && --retries) {
- QPID_LOG(notice, "Re-trying CPG initialization.");
- sys::sleep(5);
- err = cpg_initialize(&handle, &callbacks);
- }
- CPG_CHECK(err, "Failed to initialize CPG.");
- CPG_CHECK(cpg_context_set(handle, this), "Cannot set CPG context");
- // Note: CPG is currently unix-specific. If CPG is ported to
- // windows then this needs to be refactored into
- // qpid::sys::<platform>
- IOHandle::impl->fd = getFd();
-}
-
-Cpg::~Cpg() {
- try {
- shutdown();
- } catch (const std::exception& e) {
- QPID_LOG(error, "Error during CPG shutdown: " << e.what());
- }
-}
-
-void Cpg::join(const std::string& name) {
- group = name;
- callCpg ( cpgJoinOp );
-}
-
-void Cpg::leave() {
- callCpg ( cpgLeaveOp );
-}
-
-
-
-
-bool Cpg::mcast(const iovec* iov, int iovLen) {
- // Check for flow control
- cpg_flow_control_state_t flowState;
- CPG_CHECK(cpg_flow_control_state_get(handle, &flowState), "Cannot get CPG flow control status.");
- if (flowState == CPG_FLOW_CONTROL_ENABLED)
- return false;
-
- cs_error_t result;
- do {
- result = cpg_mcast_joined(handle, CPG_TYPE_AGREED, const_cast<iovec*>(iov), iovLen);
- if (result != CS_ERR_TRY_AGAIN) CPG_CHECK(result, cantMcastMsg(group));
- } while(result == CS_ERR_TRY_AGAIN);
- return true;
-}
-
-void Cpg::shutdown() {
- if (!isShutdown) {
- QPID_LOG(debug,"Shutting down CPG");
- isShutdown=true;
-
- callCpg ( cpgFinalizeOp );
- }
-}
-
-void Cpg::dispatchOne() {
- CPG_CHECK(cpg_dispatch(handle,CS_DISPATCH_ONE), "Error in CPG dispatch");
-}
-
-void Cpg::dispatchAll() {
- CPG_CHECK(cpg_dispatch(handle,CS_DISPATCH_ALL), "Error in CPG dispatch");
-}
-
-void Cpg::dispatchBlocking() {
- CPG_CHECK(cpg_dispatch(handle,CS_DISPATCH_BLOCKING), "Error in CPG dispatch");
-}
-
-string Cpg::errorStr(cs_error_t err, const std::string& msg) {
- std::ostringstream os;
- os << msg << ": ";
- switch (err) {
- case CS_OK: os << "ok"; break;
- case CS_ERR_LIBRARY: os << "library"; break;
- case CS_ERR_TIMEOUT: os << "timeout"; break;
- case CS_ERR_TRY_AGAIN: os << "try again"; break;
- case CS_ERR_INVALID_PARAM: os << "invalid param"; break;
- case CS_ERR_NO_MEMORY: os << "no memory"; break;
- case CS_ERR_BAD_HANDLE: os << "bad handle"; break;
- case CS_ERR_ACCESS: os << "access denied. You may need to set your group ID to 'ais'"; break;
- case CS_ERR_NOT_EXIST: os << "not exist"; break;
- case CS_ERR_EXIST: os << "exist"; break;
- case CS_ERR_NOT_SUPPORTED: os << "not supported"; break;
- case CS_ERR_SECURITY: os << "security"; break;
- case CS_ERR_TOO_MANY_GROUPS: os << "too many groups"; break;
- default: os << ": unknown cpg error " << err;
- };
- os << " (" << err << ")";
- return os.str();
-}
-
-std::string Cpg::cantJoinMsg(const Name& group) {
- return "Cannot join CPG group "+group.str();
-}
-
-std::string Cpg::cantFinalizeMsg(const Name& group) {
- return "Cannot finalize CPG group "+group.str();
-}
-
-std::string Cpg::cantLeaveMsg(const Name& group) {
- return "Cannot leave CPG group "+group.str();
-}
-
-std::string Cpg::cantMcastMsg(const Name& group) {
- return "Cannot mcast to CPG group "+group.str();
-}
-
-MemberId Cpg::self() const {
- unsigned int nodeid;
- CPG_CHECK(cpg_local_get(handle, &nodeid), "Cannot get local CPG identity");
- return MemberId(nodeid, getpid());
-}
-
-namespace { int byte(uint32_t value, int i) { return (value >> (i*8)) & 0xff; } }
-
-ostream& operator<<(ostream& out, const MemberId& id) {
- if (id.first) {
- out << byte(id.first, 0) << "."
- << byte(id.first, 1) << "."
- << byte(id.first, 2) << "."
- << byte(id.first, 3)
- << ":";
- }
- return out << id.second;
-}
-
-ostream& operator<<(ostream& o, const ConnectionId& c) {
- return o << c.first << "-" << c.second;
-}
-
-std::string MemberId::str() const {
- char s[8];
- uint32_t x;
- x = htonl(first);
- ::memcpy(s, &x, 4);
- x = htonl(second);
- ::memcpy(s+4, &x, 4);
- return std::string(s,8);
-}
-
-MemberId::MemberId(const std::string& s) {
- uint32_t x;
- memcpy(&x, &s[0], 4);
- first = ntohl(x);
- memcpy(&x, &s[4], 4);
- second = ntohl(x);
-}
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Cpg.h b/cpp/src/qpid/cluster/Cpg.h
deleted file mode 100644
index 1afbce8d75..0000000000
--- a/cpp/src/qpid/cluster/Cpg.h
+++ /dev/null
@@ -1,236 +0,0 @@
-#ifndef CPG_H
-#define CPG_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "qpid/Exception.h"
-#include "qpid/cluster/types.h"
-#include "qpid/sys/IOHandle.h"
-#include "qpid/sys/Mutex.h"
-
-#include <boost/scoped_ptr.hpp>
-
-#include <cassert>
-#include <string.h>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Lightweight C++ interface to cpg.h operations.
- *
- * Manages a single CPG handle, initialized in ctor, finialzed in destructor.
- * On error all functions throw Cpg::Exception.
- *
- */
-
-class Cpg : public sys::IOHandle {
- public:
- struct Exception : public ::qpid::Exception {
- Exception(const std::string& msg) : ::qpid::Exception(msg) {}
- };
-
- struct Name : public cpg_name {
- Name() { length = 0; }
- Name(const char* s) { copy(s, strlen(s)); }
- Name(const char* s, size_t n) { copy(s,n); }
- Name(const std::string& s) { copy(s.data(), s.size()); }
- void copy(const char* s, size_t n) {
- assert(n < CPG_MAX_NAME_LENGTH);
- memcpy(value, s, n);
- length=n;
- }
-
- std::string str() const { return std::string(value, length); }
- };
-
- static std::string str(const cpg_name& n) {
- return std::string(n.value, n.length);
- }
-
- struct Handler {
- virtual ~Handler() {};
- virtual void deliver(
- cpg_handle_t /*handle*/,
- const struct cpg_name *group,
- uint32_t /*nodeid*/,
- uint32_t /*pid*/,
- void* /*msg*/,
- int /*msg_len*/) = 0;
-
- virtual void configChange(
- cpg_handle_t /*handle*/,
- const struct cpg_name */*group*/,
- const struct cpg_address */*members*/, int /*nMembers*/,
- const struct cpg_address */*left*/, int /*nLeft*/,
- const struct cpg_address */*joined*/, int /*nJoined*/
- ) = 0;
- };
-
- /** Open a CPG handle.
- *@param handler for CPG events.
- */
- Cpg(Handler&);
-
- /** Destructor calls shutdown if not already calledx. */
- ~Cpg();
-
- /** Disconnect from CPG */
- void shutdown();
-
- void dispatchOne();
- void dispatchAll();
- void dispatchBlocking();
-
- void join(const std::string& group);
- void leave();
-
- /** Multicast to the group. NB: must not be called concurrently.
- *
- *@return true if the message was multi-cast, false if
- * it was not sent due to flow control.
- */
- bool mcast(const iovec* iov, int iovLen);
-
- cpg_handle_t getHandle() const { return handle; }
-
- MemberId self() const;
-
- int getFd();
-
- private:
-
- // Maximum number of retries for cog functions that can tell
- // us to "try again later".
- static const unsigned int cpgRetries = 5;
-
- // Don't let sleep-time between cpg retries to go above 0.1 second.
- static const unsigned int maxCpgRetrySleep = 100000;
-
-
- // Base class for the Cpg operations that need retry capability.
- struct CpgOp {
- std::string opName;
-
- CpgOp ( std::string opName )
- : opName(opName) { }
-
- virtual cs_error_t op ( cpg_handle_t handle, struct cpg_name * ) = 0;
- virtual std::string msg(const Name&) = 0;
- virtual ~CpgOp ( ) { }
- };
-
-
- struct CpgJoinOp : public CpgOp {
- CpgJoinOp ( )
- : CpgOp ( std::string("cpg_join") ) { }
-
- cs_error_t op(cpg_handle_t handle, struct cpg_name * group) {
- return cpg_join ( handle, group );
- }
-
- std::string msg(const Name& name) { return cantJoinMsg(name); }
- };
-
- struct CpgLeaveOp : public CpgOp {
- CpgLeaveOp ( )
- : CpgOp ( std::string("cpg_leave") ) { }
-
- cs_error_t op(cpg_handle_t handle, struct cpg_name * group) {
- return cpg_leave ( handle, group );
- }
-
- std::string msg(const Name& name) { return cantLeaveMsg(name); }
- };
-
- struct CpgFinalizeOp : public CpgOp {
- CpgFinalizeOp ( )
- : CpgOp ( std::string("cpg_finalize") ) { }
-
- cs_error_t op(cpg_handle_t handle, struct cpg_name *) {
- return cpg_finalize ( handle );
- }
-
- std::string msg(const Name& name) { return cantFinalizeMsg(name); }
- };
-
- // This fn standardizes retry policy across all Cpg ops that need it.
- void callCpg ( CpgOp & );
-
- CpgJoinOp cpgJoinOp;
- CpgLeaveOp cpgLeaveOp;
- CpgFinalizeOp cpgFinalizeOp;
-
- static std::string errorStr(cs_error_t err, const std::string& msg);
- static std::string cantJoinMsg(const Name&);
- static std::string cantLeaveMsg(const Name&);
- static std::string cantMcastMsg(const Name&);
- static std::string cantFinalizeMsg(const Name&);
-
- static Cpg* cpgFromHandle(cpg_handle_t);
-
- // New versions for corosync 1.0 and higher
- static void globalDeliver(
- cpg_handle_t handle,
- const struct cpg_name *group,
- uint32_t nodeid,
- uint32_t pid,
- void* msg,
- size_t msg_len);
-
- static void globalConfigChange(
- cpg_handle_t handle,
- const struct cpg_name *group,
- const struct cpg_address *members, size_t nMembers,
- const struct cpg_address *left, size_t nLeft,
- const struct cpg_address *joined, size_t nJoined
- );
-
- // Old versions for openais
- static void globalDeliver(
- cpg_handle_t handle,
- struct cpg_name *group,
- uint32_t nodeid,
- uint32_t pid,
- void* msg,
- int msg_len);
-
- static void globalConfigChange(
- cpg_handle_t handle,
- struct cpg_name *group,
- struct cpg_address *members, int nMembers,
- struct cpg_address *left, int nLeft,
- struct cpg_address *joined, int nJoined
- );
-
- cpg_handle_t handle;
- Handler& handler;
- bool isShutdown;
- Name group;
- sys::Mutex dispatchLock;
-};
-
-inline bool operator==(const cpg_name& a, const cpg_name& b) {
- return a.length==b.length && strncmp(a.value, b.value, a.length) == 0;
-}
-inline bool operator!=(const cpg_name& a, const cpg_name& b) { return !(a == b); }
-
-}} // namespace qpid::cluster
-
-#endif /*!CPG_H*/
diff --git a/cpp/src/qpid/cluster/CredentialsExchange.cpp b/cpp/src/qpid/cluster/CredentialsExchange.cpp
deleted file mode 100644
index 416a3636e9..0000000000
--- a/cpp/src/qpid/cluster/CredentialsExchange.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "CredentialsExchange.h"
-#include "Cluster.h"
-#include "qpid/broker/ConnectionState.h"
-#include "qpid/framing/reply_exceptions.h"
-#include "qpid/sys/Time.h"
-
-namespace qpid {
-namespace cluster {
-
-using namespace std;
-
-const string CredentialsExchange::NAME=("qpid.cluster-credentials");
-
-namespace {
-const string ANONYMOUS_MECH("ANONYMOUS");
-const string ANONYMOUS_USER("anonymous");
-
-string effectiveUserId(const string& username, const string& mechanism) {
- if (mechanism == ANONYMOUS_MECH && username.empty())
- return ANONYMOUS_USER;
- else
- return username;
-}
-}
-
-CredentialsExchange::CredentialsExchange(Cluster& cluster)
- : broker::Exchange(NAME, &cluster),
- username(effectiveUserId(cluster.getSettings().username,
- cluster.getSettings().mechanism)),
- timeout(120*sys::TIME_SEC),
- authenticate(cluster.getBroker().getOptions().auth)
-{}
-
-static const string anonymous("anonymous");
-
-bool CredentialsExchange::check(MemberId member) {
- sys::Mutex::ScopedLock l(lock);
- Map::iterator i = map.find(member);
- if (i == map.end()) return false;
- bool valid = (sys::Duration(i->second, sys::AbsTime::now()) < timeout);
- map.erase(i);
- return valid;
-}
-
-void CredentialsExchange::route(broker::Deliverable& msg) {
- const framing::FieldTable* args = msg.getMessage().getApplicationHeaders();
- sys::Mutex::ScopedLock l(lock);
- const broker::ConnectionState* connection =
- static_cast<const broker::ConnectionState*>(msg.getMessage().getPublisher());
- if (authenticate && !connection->isAuthenticatedUser(username))
- throw framing::UnauthorizedAccessException(
- QPID_MSG("Unauthorized user " << connection->getUserId() << " for " << NAME
- << ", should be " << username));
- if (!args || !args->isSet(NAME))
- throw framing::InvalidArgumentException(
- QPID_MSG("Invalid message received by " << NAME));
- MemberId member(args->getAsUInt64(NAME));
- map[member] = sys::AbsTime::now();
-}
-
-string CredentialsExchange::getType() const { return NAME; }
-
-namespace {
-void throwIllegal() {
- throw framing::NotAllowedException(
- QPID_MSG("Illegal use of " << CredentialsExchange::NAME+" exchange"));
-}
-}
-
-bool CredentialsExchange::bind(boost::shared_ptr<broker::Queue> , const string& /*routingKey*/, const framing::FieldTable* ) { throwIllegal(); return false; }
-bool CredentialsExchange::unbind(boost::shared_ptr<broker::Queue> , const string& /*routingKey*/, const framing::FieldTable* ) { throwIllegal(); return false; }
-bool CredentialsExchange::isBound(boost::shared_ptr<broker::Queue>, const string* const /*routingKey*/, const framing::FieldTable* const ) { throwIllegal(); return false; }
-
-
-}} // Namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/CredentialsExchange.h b/cpp/src/qpid/cluster/CredentialsExchange.h
deleted file mode 100644
index 74cf8350a6..0000000000
--- a/cpp/src/qpid/cluster/CredentialsExchange.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef QPID_CLUSTER_CREDENTIALSEXCHANGE_H
-#define QPID_CLUSTER_CREDENTIALSEXCHANGE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "types.h"
-#include <qpid/broker/Exchange.h>
-#include <qpid/sys/Mutex.h>
-#include <qpid/sys/Time.h>
-#include <string>
-#include <map>
-
-namespace qpid {
-namespace cluster {
-
-class Cluster;
-
-/**
- * New members joining the cluster send their identity information to this
- * exchange to prove they are authenticated as the cluster user.
- * The exchange rejects messages that are not properly authenticated
- */
-class CredentialsExchange : public broker::Exchange
-{
- public:
- static const std::string NAME;
-
- CredentialsExchange(Cluster&);
-
- /** Check if this member has credentials. The credentials are deleted. */
- bool check(MemberId member);
-
- /** Throw an exception if the calling connection is not the cluster user. Store credentials in msg. */
- void route(broker::Deliverable& msg);
-
- // Exchange overrides
- std::string getType() const;
- bool bind(boost::shared_ptr<broker::Queue> queue, const std::string& routingKey, const framing::FieldTable* args);
- bool unbind(boost::shared_ptr<broker::Queue> queue, const std::string& routingKey, const framing::FieldTable* args);
- bool isBound(boost::shared_ptr<broker::Queue> queue, const std::string* const routingKey, const framing::FieldTable* const args);
-
- private:
- typedef std::map<MemberId, sys::AbsTime> Map;
- sys::Mutex lock;
- Map map;
- std::string username;
- sys::Duration timeout;
- bool authenticate;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_CREDENTIALSEXCHANGE_H*/
diff --git a/cpp/src/qpid/cluster/Decoder.cpp b/cpp/src/qpid/cluster/Decoder.cpp
deleted file mode 100644
index 23ba372d78..0000000000
--- a/cpp/src/qpid/cluster/Decoder.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/Decoder.h"
-#include "qpid/cluster/EventFrame.h"
-#include "qpid/framing/ClusterConnectionDeliverCloseBody.h"
-#include "qpid/framing/Buffer.h"
-#include "qpid/framing/AMQFrame.h"
-
-
-namespace qpid {
-namespace cluster {
-
-void Decoder::decode(const EventHeader& eh, const char* data) {
- sys::Mutex::ScopedLock l(lock);
- assert(eh.getType() == DATA); // Only handle connection data events.
- const char* cp = static_cast<const char*>(data);
- framing::Buffer buf(const_cast<char*>(cp), eh.getSize());
- framing::FrameDecoder& decoder = map[eh.getConnectionId()];
- if (decoder.decode(buf)) { // Decoded a frame
- framing::AMQFrame frame(decoder.getFrame());
- while (decoder.decode(buf)) {
- callback(EventFrame(eh, frame));
- frame = decoder.getFrame();
- }
- // Set read-credit on the last frame ending in this event.
- // Credit will be given when this frame is processed.
- callback(EventFrame(eh, frame, 1));
- }
- else {
- // We must give 1 unit read credit per event.
- // This event does not complete any frames so
- // send an empty frame with the read credit.
- callback(EventFrame(eh, framing::AMQFrame(), 1));
- }
-}
-
-void Decoder::erase(const ConnectionId& c) {
- sys::Mutex::ScopedLock l(lock);
- map.erase(c);
-}
-
-framing::FrameDecoder& Decoder::get(const ConnectionId& c) {
- sys::Mutex::ScopedLock l(lock);
- return map[c];
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Decoder.h b/cpp/src/qpid/cluster/Decoder.h
deleted file mode 100644
index 3b5ada4a81..0000000000
--- a/cpp/src/qpid/cluster/Decoder.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef QPID_CLUSTER_DECODER_H
-#define QPID_CLUSTER_DECODER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/types.h"
-#include "qpid/framing/FrameDecoder.h"
-#include "qpid/sys/Mutex.h"
-#include <boost/function.hpp>
-#include <map>
-
-namespace qpid {
-namespace cluster {
-
-struct EventFrame;
-class EventHeader;
-
-/**
- * A map of decoders for connections.
- */
-class Decoder
-{
- public:
- typedef boost::function<void(const EventFrame&)> FrameHandler;
-
- Decoder(FrameHandler fh) : callback(fh) {}
- void decode(const EventHeader& eh, const char* data);
- void erase(const ConnectionId&);
- framing::FrameDecoder& get(const ConnectionId& c);
-
- private:
- typedef std::map<ConnectionId, framing::FrameDecoder> Map;
- sys::Mutex lock;
- Map map;
- void process(const EventFrame&);
- FrameHandler callback;
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_DECODER_H*/
diff --git a/cpp/src/qpid/cluster/Dispatchable.h b/cpp/src/qpid/cluster/Dispatchable.h
deleted file mode 100644
index e7f0df4218..0000000000
--- a/cpp/src/qpid/cluster/Dispatchable.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef QPID_CLUSTER_DISPATCHABLE_H
-#define QPID_CLUSTER_DISPATCHABLE_H
-
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Interface for classes that have some "events" that need dispatching
- * in a thread.
- */
-class Dispatchable
-{
- public:
- virtual ~Dispatchable() {}
-
- /** Dispatch one event in current thread. */
- virtual void dispatchOne() = 0;
- /** Dispatch all available events, don't block. */
- virtual void dispatchAll() = 0;
- /** Blocking loop to dispatch cluster events */
- virtual void dispatchBlocking() = 0;
-
- /** Wait for at least one event, then dispatch all available events.
- * Don't block. Useful for tests.
- */
- virtual void dispatchSome() { dispatchOne(); dispatchAll(); }
-
-};
-
-}} // namespace qpid::cluster
-
-
-
-#endif /*!QPID_CLUSTER_DISPATCHABLE_H*/
diff --git a/cpp/src/qpid/cluster/ErrorCheck.cpp b/cpp/src/qpid/cluster/ErrorCheck.cpp
deleted file mode 100644
index be671c0f48..0000000000
--- a/cpp/src/qpid/cluster/ErrorCheck.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/ErrorCheck.h"
-#include "qpid/cluster/EventFrame.h"
-#include "qpid/cluster/ClusterMap.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/framing/ClusterErrorCheckBody.h"
-#include "qpid/framing/ClusterConfigChangeBody.h"
-#include "qpid/log/Statement.h"
-
-#include <algorithm>
-
-namespace qpid {
-namespace cluster {
-
-using namespace std;
-using namespace framing;
-using namespace framing::cluster;
-
-ErrorCheck::ErrorCheck(Cluster& c)
- : cluster(c), mcast(c.getMulticast()), frameSeq(0), type(ERROR_TYPE_NONE), connection(0)
-{}
-
-void ErrorCheck::error(
- Connection& c, ErrorType t, framing::SequenceNumber seq, const MemberSet& ms,
- const std::string& msg)
-{
- // Detected a local error, inform cluster and set error state.
- assert(t != ERROR_TYPE_NONE); // Must be an error.
- assert(type == ERROR_TYPE_NONE); // Can't be called when already in an error state.
- type = t;
- unresolved = ms;
- frameSeq = seq;
- connection = &c;
- message = msg;
- QPID_LOG(debug, cluster<< (type == ERROR_TYPE_SESSION ? " channel" : " connection")
- << " error " << frameSeq << " on " << c
- << " must be resolved with: " << unresolved
- << ": " << message);
- mcast.mcastControl(
- ClusterErrorCheckBody(ProtocolVersion(), type, frameSeq), cluster.getId());
- // If there are already frames queued up by a previous error, review
- // them with respect to this new error.
- for (FrameQueue::iterator i = frames.begin(); i != frames.end(); i = review(i))
- ;
-}
-
-void ErrorCheck::delivered(const EventFrame& e) {
- frames.push_back(e);
- review(frames.end()-1);
-}
-
-// Review a frame in the queue with respect to the current error.
-ErrorCheck::FrameQueue::iterator ErrorCheck::review(const FrameQueue::iterator& i) {
- FrameQueue::iterator next = i+1;
- if(!isUnresolved() || !i->frame.getBody() || !i->frame.getMethod())
- return next; // Only interested in control frames while unresolved.
- const AMQMethodBody* method = i->frame.getMethod();
- if (method->isA<const ClusterErrorCheckBody>()) {
- const ClusterErrorCheckBody* errorCheck =
- static_cast<const ClusterErrorCheckBody*>(method);
-
- if (errorCheck->getFrameSeq() == frameSeq) { // Addresses current error
- next = frames.erase(i); // Drop matching error check controls
- if (errorCheck->getType() < type) { // my error is worse than his
- QPID_LOG(critical, cluster
- << " local error " << frameSeq << " did not occur on member "
- << i->getMemberId()
- << ": " << message);
- throw Exception(
- QPID_MSG("local error did not occur on all cluster members " << ": " << message));
- }
- else { // his error is worse/same as mine.
- QPID_LOG(debug, cluster << " error " << frameSeq
- << " resolved with " << i->getMemberId());
- unresolved.erase(i->getMemberId());
- checkResolved();
- }
- }
- else if (errorCheck->getFrameSeq() < frameSeq && errorCheck->getType() != NONE
- && i->connectionId.getMember() != cluster.getId())
- {
- // This error occured before the current error so we
- // have processed past it.
- next = frames.erase(i); // Drop the error check control
- respondNone(i->connectionId.getMember(), errorCheck->getType(),
- errorCheck->getFrameSeq());
- }
- // if errorCheck->getFrameSeq() > frameSeq then leave it in the queue.
- }
- else if (method->isA<const ClusterConfigChangeBody>()) {
- const ClusterConfigChangeBody* configChange =
- static_cast<const ClusterConfigChangeBody*>(method);
- if (configChange) {
- MemberSet members(decodeMemberSet(configChange->getMembers()));
- QPID_LOG(debug, cluster << " apply config change to error "
- << frameSeq << ": " << members);
- MemberSet intersect;
- set_intersection(members.begin(), members.end(),
- unresolved.begin(), unresolved.end(),
- inserter(intersect, intersect.begin()));
- unresolved.swap(intersect);
- checkResolved();
- }
- }
- return next;
-}
-
-void ErrorCheck::checkResolved() {
- if (unresolved.empty()) { // No more potentially conflicted members, we're clear.
- type = ERROR_TYPE_NONE;
- QPID_LOG(debug, cluster << " error " << frameSeq << " resolved.");
- }
- else
- QPID_LOG(debug, cluster << " error " << frameSeq
- << " must be resolved with " << unresolved);
-}
-
-EventFrame ErrorCheck::getNext() {
- assert(canProcess());
- EventFrame e(frames.front());
- frames.pop_front();
- return e;
-}
-
-void ErrorCheck::respondNone(const MemberId& from, uint8_t type, framing::SequenceNumber frameSeq) {
- // Don't respond to non-errors or to my own errors.
- if (type == ERROR_TYPE_NONE || from == cluster.getId())
- return;
- QPID_LOG(debug, cluster << " error " << frameSeq << " did not occur locally.");
- mcast.mcastControl(
- ClusterErrorCheckBody(ProtocolVersion(), ERROR_TYPE_NONE, frameSeq),
- cluster.getId()
- );
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/ErrorCheck.h b/cpp/src/qpid/cluster/ErrorCheck.h
deleted file mode 100644
index a417b2ec25..0000000000
--- a/cpp/src/qpid/cluster/ErrorCheck.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef QPID_CLUSTER_ERRORCHECK_H
-#define QPID_CLUSTER_ERRORCHECK_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/MemberSet.h"
-#include "qpid/cluster/Multicaster.h"
-#include "qpid/framing/enum.h"
-#include "qpid/framing/SequenceNumber.h"
-#include <boost/function.hpp>
-#include <deque>
-#include <set>
-
-namespace qpid {
-namespace cluster {
-
-struct EventFrame;
-class Cluster;
-class Multicaster;
-class Connection;
-
-/**
- * Error checking logic.
- *
- * When an error occurs queue up frames until we can determine if all
- * nodes experienced the error. If not, we shut down.
- */
-class ErrorCheck
-{
- public:
- typedef framing::cluster::ErrorType ErrorType;
- typedef framing::SequenceNumber SequenceNumber;
-
- ErrorCheck(Cluster&);
-
- /** A local error has occured */
- void error(Connection&, ErrorType, SequenceNumber frameSeq, const MemberSet&,
- const std::string& msg);
-
- /** Called when a frame is delivered */
- void delivered(const EventFrame&);
-
- /**@pre canProcess **/
- EventFrame getNext();
-
- bool canProcess() const { return type == NONE && !frames.empty(); }
-
- bool isUnresolved() const { return type != NONE; }
-
- /** Respond to an error check saying we had no error. */
- void respondNone(const MemberId&, uint8_t type, SequenceNumber frameSeq);
-
- private:
- static const ErrorType NONE = framing::cluster::ERROR_TYPE_NONE;
- typedef std::deque<EventFrame> FrameQueue;
- FrameQueue::iterator review(const FrameQueue::iterator&);
- void checkResolved();
-
- Cluster& cluster;
- Multicaster& mcast;
- FrameQueue frames;
- MemberSet unresolved;
- SequenceNumber frameSeq;
- ErrorType type;
- Connection* connection;
- std::string message;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_ERRORCHECK_H*/
diff --git a/cpp/src/qpid/cluster/Event.cpp b/cpp/src/qpid/cluster/Event.cpp
deleted file mode 100644
index da2bc89d8c..0000000000
--- a/cpp/src/qpid/cluster/Event.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/types.h"
-#include "qpid/cluster/Event.h"
-#include "qpid/cluster/Cpg.h"
-#include "qpid/framing/Buffer.h"
-#include "qpid/framing/AMQFrame.h"
-#include "qpid/RefCountedBuffer.h"
-#include "qpid/assert.h"
-#include <ostream>
-#include <iterator>
-#include <algorithm>
-
-namespace qpid {
-namespace cluster {
-
-using framing::Buffer;
-using framing::AMQFrame;
-
-const size_t EventHeader::HEADER_SIZE =
- sizeof(uint8_t) + // type
- sizeof(uint64_t) + // connection pointer only, CPG provides member ID.
- sizeof(uint32_t) // payload size
- ;
-
-EventHeader::EventHeader(EventType t, const ConnectionId& c, size_t s)
- : type(t), connectionId(c), size(s) {}
-
-
-Event::Event() {}
-
-Event::Event(EventType t, const ConnectionId& c, size_t s)
- : EventHeader(t,c,s), store(RefCountedBuffer::create(s+HEADER_SIZE))
-{}
-
-void EventHeader::decode(const MemberId& m, framing::Buffer& buf) {
- QPID_ASSERT(buf.available() >= HEADER_SIZE);
- type = (EventType)buf.getOctet();
- QPID_ASSERT(type == DATA || type == CONTROL);
- connectionId = ConnectionId(m, buf.getLongLong());
- size = buf.getLong();
-}
-
-Event Event::decodeCopy(const MemberId& m, framing::Buffer& buf) {
- Event e;
- e.decode(m, buf); // Header
- QPID_ASSERT(buf.available() >= e.size);
- e.store = RefCountedBuffer::create(e.size + HEADER_SIZE);
- memcpy(e.getData(), buf.getPointer() + buf.getPosition(), e.size);
- return e;
-}
-
-Event Event::control(const framing::AMQFrame& f, const ConnectionId& cid) {
- Event e(CONTROL, cid, f.encodedSize());
- Buffer buf(e);
- f.encode(buf);
- return e;
-}
-
-Event Event::control(const framing::AMQBody& body, const ConnectionId& cid) {
- return control(framing::AMQFrame(body), cid);
-}
-
-iovec Event::toIovec() const {
- encodeHeader();
- iovec iov = { const_cast<char*>(getStore()), getStoreSize() };
- return iov;
-}
-
-void EventHeader::encode(Buffer& b) const {
- b.putOctet(type);
- b.putLongLong(connectionId.getNumber());
- b.putLong(size);
-}
-
-// Encode my header in my buffer.
-void Event::encodeHeader () const {
- Buffer b(const_cast<char*>(getStore()), HEADER_SIZE);
- encode(b);
- assert(b.getPosition() == HEADER_SIZE);
-}
-
-Event::operator Buffer() const {
- return Buffer(const_cast<char*>(getData()), getSize());
-}
-
-const AMQFrame& Event::getFrame() const {
- assert(type == CONTROL);
- if (!frame.getBody()) {
- Buffer buf(*this);
- QPID_ASSERT(frame.decode(buf));
- }
- return frame;
-}
-
-static const char* EVENT_TYPE_NAMES[] = { "data", "control" };
-
-std::ostream& operator<< (std::ostream& o, EventType t) {
- return o << EVENT_TYPE_NAMES[t];
-}
-
-std::ostream& operator<< (std::ostream& o, const EventHeader& e) {
- return o << "Event[" << e.getConnectionId() << " " << e.getType()
- << " " << e.getSize() << " bytes]";
-}
-
-std::ostream& operator<< (std::ostream& o, const Event& e) {
- o << "Event[" << e.getConnectionId() << " ";
- if (e.getType() == CONTROL)
- o << e.getFrame();
- else
- o << " data " << e.getSize() << " bytes";
- return o << "]";
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Event.h b/cpp/src/qpid/cluster/Event.h
deleted file mode 100644
index 13283edff7..0000000000
--- a/cpp/src/qpid/cluster/Event.h
+++ /dev/null
@@ -1,116 +0,0 @@
-#ifndef QPID_CLUSTER_EVENT_H
-#define QPID_CLUSTER_EVENT_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/types.h"
-#include "qpid/BufferRef.h"
-#include "qpid/framing/AMQFrame.h"
-#include <sys/uio.h> // For iovec
-#include <iosfwd>
-
-#include "qpid/cluster/types.h"
-
-namespace qpid {
-
-namespace framing {
-class AMQBody;
-class AMQFrame;
-class Buffer;
-}
-
-namespace cluster {
-
-/** Header data for a multicast event */
-class EventHeader {
- public:
- EventHeader(EventType t=DATA, const ConnectionId& c=ConnectionId(), size_t size=0);
- void decode(const MemberId& m, framing::Buffer&);
- void encode(framing::Buffer&) const;
-
- EventType getType() const { return type; }
- ConnectionId getConnectionId() const { return connectionId; }
- MemberId getMemberId() const { return connectionId.getMember(); }
-
- /** Size of payload data, excluding header. */
- size_t getSize() const { return size; }
- /** Size of header + payload. */
- size_t getStoreSize() const { return size + HEADER_SIZE; }
-
- bool isCluster() const { return connectionId.getNumber() == 0; }
- bool isConnection() const { return connectionId.getNumber() != 0; }
- bool isControl() const { return type == CONTROL; }
-
- protected:
- static const size_t HEADER_SIZE;
-
- EventType type;
- ConnectionId connectionId;
- size_t size;
-};
-
-/**
- * Events are sent to/received from the cluster.
- * Refcounted so they can be stored on queues.
- */
-class Event : public EventHeader {
- public:
- Event();
- /** Create an event with a buffer that can hold size bytes plus an event header. */
- Event(EventType t, const ConnectionId& c, size_t);
-
- /** Create an event copied from delivered data. */
- static Event decodeCopy(const MemberId& m, framing::Buffer&);
-
- /** Create a control event. */
- static Event control(const framing::AMQBody&, const ConnectionId&);
-
- /** Create a control event. */
- static Event control(const framing::AMQFrame&, const ConnectionId&);
-
- // Data excluding header.
- char* getData() { return store.begin() + HEADER_SIZE; }
- const char* getData() const { return store.begin() + HEADER_SIZE; }
-
- // Store including header
- char* getStore() { return store.begin(); }
- const char* getStore() const { return store.begin(); }
-
- const framing::AMQFrame& getFrame() const;
-
- operator framing::Buffer() const;
-
- iovec toIovec() const;
-
- private:
- void encodeHeader() const;
-
- BufferRef store;
- mutable framing::AMQFrame frame;
-};
-
-std::ostream& operator << (std::ostream&, const Event&);
-std::ostream& operator << (std::ostream&, const EventHeader&);
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_EVENT_H*/
diff --git a/cpp/src/qpid/cluster/EventFrame.cpp b/cpp/src/qpid/cluster/EventFrame.cpp
deleted file mode 100644
index 5fbe1fe57c..0000000000
--- a/cpp/src/qpid/cluster/EventFrame.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/EventFrame.h"
-#include "qpid/cluster/Connection.h"
-
-namespace qpid {
-namespace cluster {
-
-EventFrame::EventFrame() {}
-
-EventFrame::EventFrame(const EventHeader& e, const framing::AMQFrame& f, int rc)
- : connectionId(e.getConnectionId()), frame(f), readCredit(rc), type(e.getType())
-{}
-
-std::ostream& operator<<(std::ostream& o, const EventFrame& e) {
- if (e.frame.getBody()) o << e.frame;
- else o << "null-frame";
- o << " " << e.type << " " << e.connectionId;
- if (e.readCredit) o << " read-credit=" << e.readCredit;
- return o;
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/EventFrame.h b/cpp/src/qpid/cluster/EventFrame.h
deleted file mode 100644
index 6b702a9bf8..0000000000
--- a/cpp/src/qpid/cluster/EventFrame.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef QPID_CLUSTER_EVENTFRAME_H
-#define QPID_CLUSTER_EVENTFRAME_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/types.h"
-#include "qpid/cluster/Event.h"
-#include "qpid/framing/AMQFrame.h"
-#include <boost/intrusive_ptr.hpp>
-#include <iosfwd>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * A frame decoded from an Event.
- */
-struct EventFrame
-{
- public:
- EventFrame();
-
- EventFrame(const EventHeader& e, const framing::AMQFrame& f, int rc=0);
-
- bool isCluster() const { return connectionId.getNumber() == 0; }
- bool isConnection() const { return connectionId.getNumber() != 0; }
- bool isLastInEvent() const { return readCredit; }
- MemberId getMemberId() const { return connectionId.getMember(); }
-
-
- ConnectionId connectionId;
- framing::AMQFrame frame;
- int readCredit; ///< last frame in an event, give credit when processed.
- EventType type;
-};
-
-std::ostream& operator<<(std::ostream& o, const EventFrame& e);
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_EVENTFRAME_H*/
diff --git a/cpp/src/qpid/cluster/FailoverExchange.cpp b/cpp/src/qpid/cluster/FailoverExchange.cpp
deleted file mode 100644
index 87202a887c..0000000000
--- a/cpp/src/qpid/cluster/FailoverExchange.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/FailoverExchange.h"
-#include "qpid/broker/Message.h"
-#include "qpid/broker/DeliverableMessage.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/framing/MessageProperties.h"
-#include "qpid/framing/AMQFrame.h"
-#include "qpid/framing/AMQHeaderBody.h"
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/log/Statement.h"
-#include "qpid/framing/Array.h"
-#include "qpid/UrlArray.h"
-#include <boost/bind.hpp>
-#include <algorithm>
-
-namespace qpid {
-namespace cluster {
-using namespace std;
-
-using namespace broker;
-using namespace framing;
-
-const string FailoverExchange::typeName("amq.failover");
-
-FailoverExchange::FailoverExchange(management::Manageable* parent, Broker* b)
- : Exchange(typeName, parent, b ), ready(false)
-{
- if (mgmtExchange != 0)
- mgmtExchange->set_type(typeName);
-}
-
-void FailoverExchange::setUrls(const vector<Url>& u) {
- Lock l(lock);
- urls = u;
-}
-
-void FailoverExchange::updateUrls(const vector<Url>& u) {
- Lock l(lock);
- urls=u;
- if (ready && !urls.empty()) {
- std::for_each(queues.begin(), queues.end(),
- boost::bind(&FailoverExchange::sendUpdate, this, _1));
- }
-}
-
-string FailoverExchange::getType() const { return typeName; }
-
-bool FailoverExchange::bind(Queue::shared_ptr queue, const string&, const framing::FieldTable*) {
- Lock l(lock);
- if (ready) sendUpdate(queue);
- return queues.insert(queue).second;
-}
-
-bool FailoverExchange::unbind(Queue::shared_ptr queue, const string&, const framing::FieldTable*) {
- Lock l(lock);
- return queues.erase(queue);
-}
-
-bool FailoverExchange::isBound(Queue::shared_ptr queue, const string* const, const framing::FieldTable*) {
- Lock l(lock);
- return queues.find(queue) != queues.end();
-}
-
-void FailoverExchange::route(Deliverable&) {
- QPID_LOG(warning, "Message received by exchange " << typeName << " ignoring");
-}
-
-void FailoverExchange::sendUpdate(const Queue::shared_ptr& queue) {
- // Called with lock held.
- if (urls.empty()) return;
- framing::Array array = vectorToUrlArray(urls);
- const ProtocolVersion v;
- boost::intrusive_ptr<Message> msg(new Message);
- AMQFrame command(MessageTransferBody(v, typeName, 1, 0));
- command.setLastSegment(false);
- msg->getFrames().append(command);
- AMQHeaderBody header;
- header.get<MessageProperties>(true)->setContentLength(0);
- header.get<MessageProperties>(true)->getApplicationHeaders().setArray(typeName, array);
- AMQFrame headerFrame(header);
- headerFrame.setFirstSegment(false);
- msg->getFrames().append(headerFrame);
- DeliverableMessage(msg).deliverTo(queue);
-}
-
-void FailoverExchange::setReady() {
- ready = true;
-}
-
-}} // namespace cluster
diff --git a/cpp/src/qpid/cluster/FailoverExchange.h b/cpp/src/qpid/cluster/FailoverExchange.h
deleted file mode 100644
index 5ac734a7ac..0000000000
--- a/cpp/src/qpid/cluster/FailoverExchange.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef QPID_CLUSTER_FAILOVEREXCHANGE_H
-#define QPID_CLUSTER_FAILOVEREXCHANGE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/broker/Exchange.h"
-#include "qpid/broker/DeliverableMessage.h"
-#include "qpid/Url.h"
-
-#include <vector>
-#include <set>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Failover exchange provides failover host list, as specified in AMQP 0-10.
- */
-class FailoverExchange : public broker::Exchange
-{
- public:
- static const std::string typeName;
-
- FailoverExchange(management::Manageable* parent, broker::Broker* b);
-
- /** Set the URLs but don't send an update.*/
- void setUrls(const std::vector<Url>&);
- /** Set the URLs and send an update.*/
- void updateUrls(const std::vector<Url>&);
- /** Flag the failover exchange as ready to generate updates (caught up) */
- void setReady();
-
- // Exchange overrides
- std::string getType() const;
- bool bind(boost::shared_ptr<broker::Queue> queue, const std::string& routingKey, const framing::FieldTable* args);
- bool unbind(boost::shared_ptr<broker::Queue> queue, const std::string& routingKey, const framing::FieldTable* args);
- bool isBound(boost::shared_ptr<broker::Queue> queue, const std::string* const routingKey, const framing::FieldTable* const args);
- void route(broker::Deliverable& msg);
-
- private:
- void sendUpdate(const boost::shared_ptr<broker::Queue>&);
-
- typedef sys::Mutex::ScopedLock Lock;
- typedef std::vector<Url> Urls;
- typedef std::set<boost::shared_ptr<broker::Queue> > Queues;
-
- sys::Mutex lock;
- Urls urls;
- Queues queues;
- bool ready;
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_FAILOVEREXCHANGE_H*/
diff --git a/cpp/src/qpid/cluster/InitialStatusMap.cpp b/cpp/src/qpid/cluster/InitialStatusMap.cpp
deleted file mode 100644
index fc53d1076b..0000000000
--- a/cpp/src/qpid/cluster/InitialStatusMap.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "InitialStatusMap.h"
-#include "StoreStatus.h"
-#include "qpid/log/Statement.h"
-#include "qpid/UrlArray.h"
-#include <algorithm>
-#include <vector>
-#include <boost/bind.hpp>
-
-namespace qpid {
-namespace cluster {
-
-using namespace std;
-using namespace framing::cluster;
-using namespace framing;
-using boost::optional;
-
-InitialStatusMap::InitialStatusMap(const MemberId& self_, size_t size_)
- : self(self_), completed(), resendNeeded(), size(size_)
-{}
-
-void InitialStatusMap::configChange(const MemberSet& members) {
- resendNeeded = false;
- bool wasComplete = isComplete();
- if (firstConfig.empty()) firstConfig = members;
- MemberSet::const_iterator i = members.begin();
- Map::iterator j = map.begin();
- while (i != members.end() || j != map.end()) {
- if (i == members.end()) { // j not in members, member left
- firstConfig.erase(j->first);
- Map::iterator k = j++;
- map.erase(k);
- }
- else if (j == map.end()) { // i not in map, member joined
- resendNeeded = true;
- map[*i] = optional<Status>();
- ++i;
- }
- else if (*i < j->first) { // i not in map, member joined
- resendNeeded = true;
- map[*i] = optional<Status>();
- ++i;
- }
- else if (*i > j->first) { // j not in members, member left
- firstConfig.erase(j->first);
- Map::iterator k = j++;
- map.erase(k);
- }
- else {
- i++; j++;
- }
- }
- if (resendNeeded) { // Clear all status
- for (Map::iterator i = map.begin(); i != map.end(); ++i)
- i->second = optional<Status>();
- }
- completed = isComplete() && !wasComplete; // Set completed on the transition.
-}
-
-void InitialStatusMap::received(const MemberId& m, const Status& s){
- bool wasComplete = isComplete();
- map[m] = s;
- completed = isComplete() && !wasComplete; // Set completed on the transition.
-}
-
-bool InitialStatusMap::notInitialized(const Map::value_type& v) {
- return !v.second;
-}
-
-bool InitialStatusMap::isComplete() const {
- return !map.empty() && find_if(map.begin(), map.end(), &notInitialized) == map.end();
-}
-
-bool InitialStatusMap::transitionToComplete() {
- return completed;
-}
-
-bool InitialStatusMap::isResendNeeded() {
- bool ret = resendNeeded;
- resendNeeded = false;
- return ret;
-}
-
-bool InitialStatusMap::isActiveEntry(const Map::value_type& v) {
- return v.second && v.second->getActive();
-}
-
-bool InitialStatusMap::hasStore(const Map::value_type& v) {
- return v.second &&
- (v.second->getStoreState() == STORE_STATE_CLEAN_STORE ||
- v.second->getStoreState() == STORE_STATE_DIRTY_STORE);
-}
-
-bool InitialStatusMap::isActive() {
- assert(isComplete());
- return (find_if(map.begin(), map.end(), &isActiveEntry) != map.end());
-}
-
-bool InitialStatusMap::isUpdateNeeded() {
- assert(isComplete());
- // We need an update if there are any active members.
- if (isActive()) return true;
-
- // Otherwise it depends on store status, get my own status:
- Map::iterator me = map.find(self);
- assert(me != map.end());
- assert(me->second);
- switch (me->second->getStoreState()) {
- case STORE_STATE_NO_STORE:
- case STORE_STATE_EMPTY_STORE:
- // If anybody has a store then we need an update.
- return find_if(map.begin(), map.end(), &hasStore) != map.end();
- case STORE_STATE_DIRTY_STORE: return true;
- case STORE_STATE_CLEAN_STORE: return false; // Use our own store
- }
- return false;
-}
-
-MemberSet InitialStatusMap::getElders() const {
- assert(isComplete());
- MemberSet elders;
- for (MemberSet::const_iterator i = firstConfig.begin(); i != firstConfig.end(); ++i) {
- // *i is in my first config, so a potential elder.
- if (*i == self) continue; // Not my own elder
- Map::const_iterator j = map.find(*i);
- assert(j != map.end());
- assert(j->second);
- const Status& s = *j->second;
- // If I'm not in i's first config then i is older than me.
- // Otherwise we were born in the same configuration so use
- // member ID to break the tie.
- MemberSet iFirstConfig = decodeMemberSet(s.getFirstConfig());
- if (iFirstConfig.find(self) == iFirstConfig.end() || *i > self)
- elders.insert(*i);
- }
- return elders;
-}
-
-// Get cluster ID from an active member or the youngest newcomer.
-Uuid InitialStatusMap::getClusterId() {
- assert(isComplete());
- assert(!map.empty());
- Map::iterator i = find_if(map.begin(), map.end(), &isActiveEntry);
- if (i != map.end())
- return i->second->getClusterId(); // An active member
- else
- return map.begin()->second->getClusterId(); // Youngest newcomer in node-id order
-}
-
-void checkId(Uuid& expect, const Uuid& actual, const string& msg) {
- if (!expect) expect = actual;
- assert(expect);
- if (expect != actual)
- throw Exception(msg);
-}
-
-void InitialStatusMap::checkConsistent() {
- assert(isComplete());
- int clean = 0;
- int dirty = 0;
- int empty = 0;
- int none = 0;
- int active = 0;
- Uuid clusterId;
- Uuid shutdownId;
-
- bool initialCluster = !isActive();
- for (Map::iterator i = map.begin(); i != map.end(); ++i) {
- assert(i->second);
- if (i->second->getActive()) ++active;
- switch (i->second->getStoreState()) {
- case STORE_STATE_NO_STORE: ++none; break;
- case STORE_STATE_EMPTY_STORE: ++empty; break;
- case STORE_STATE_DIRTY_STORE:
- ++dirty;
- checkId(clusterId, i->second->getClusterId(),
- "Cluster-ID mismatch. Stores belong to different clusters.");
- break;
- case STORE_STATE_CLEAN_STORE:
- ++clean;
- checkId(clusterId, i->second->getClusterId(),
- "Cluster-ID mismatch. Stores belong to different clusters.");
- // Only need shutdownId to match if we are in an initially forming cluster.
- if (initialCluster)
- checkId(shutdownId, i->second->getShutdownId(),
- "Shutdown-ID mismatch. Stores were not shut down together");
- break;
- }
- }
- // Can't mix transient and persistent members.
- if (none && (clean+dirty+empty))
- throw Exception("Mixing transient and persistent brokers in a cluster");
-
- if (map.size() >= size) {
- // All initial members are present. If there are no active
- // members and there are dirty stores there must be at least
- // one clean store.
- if (!active && dirty && !clean)
- throw Exception("Cannot recover, no clean store.");
- }
-}
-
-std::vector<Url> InitialStatusMap::getUrls() const {
- std::vector<Url> urls;
- for (Map::const_iterator i = map.begin(); i != map.end(); ++i) {
- if (i->second) {
- std::vector<Url> urls = urlArrayToVector(i->second->getUrls());
- if (!urls.empty()) return urls;
- }
- }
- return std::vector<Url>();
-}
-
-std::string InitialStatusMap::getFirstConfigStr() const {
- assert(!firstConfig.empty());
- return encodeMemberSet(firstConfig);
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/InitialStatusMap.h b/cpp/src/qpid/cluster/InitialStatusMap.h
deleted file mode 100644
index afa0110836..0000000000
--- a/cpp/src/qpid/cluster/InitialStatusMap.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef QPID_CLUSTER_INITIALSTATUSMAP_H
-#define QPID_CLUSTER_INITIALSTATUSMAP_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "MemberSet.h"
-#include "qpid/Url.h"
-#include <qpid/framing/ClusterInitialStatusBody.h>
-#include <boost/optional.hpp>
-#include <vector>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Track status of cluster members during initialization.
- *
- * When a new member joins the CPG cluster, all members send an initial-status
- * control. This map tracks those controls and provides data to make descisions
- * about joining the cluster.
- *
- */
-class InitialStatusMap
-{
- public:
- typedef framing::ClusterInitialStatusBody Status;
-
- InitialStatusMap(const MemberId& self, size_t size);
- /** Process a config change. May make isResendNeeded() true. */
- void configChange(const MemberSet& newConfig);
- /** @return true if we need to re-send status */
- bool isResendNeeded();
-
- /** Process received status */
- void received(const MemberId&, const Status& is);
-
- /**@return true if the map has an entry for all current cluster members. */
- bool isComplete() const;
-
- size_t getActualSize() const { return map.size(); }
- size_t getRequiredSize() const { return size; }
-
- /**@return true if the map was completed by the last config change or received. */
- bool transitionToComplete();
- /**@pre isComplete(). @return this node's elders */
- MemberSet getElders() const;
- /**@pre isComplete(). @return True if there are active members of the cluster. */
- bool isActive();
- /**@pre isComplete(). @return True if we need to request an update. */
- bool isUpdateNeeded();
- /**@pre isComplete(). @return Cluster-wide cluster ID. */
- framing::Uuid getClusterId();
- /**@pre isComplete(). @throw Exception if there are any inconsistencies. */
- void checkConsistent();
- /*@return cluster URLs */
- std::vector<Url> getUrls() const;
-
- /** Get first config-change for this member, encoded as a string.
- *@pre configChange has been called at least once.
- */
- std::string getFirstConfigStr() const;
- private:
- typedef std::map<MemberId, boost::optional<Status> > Map;
- static bool notInitialized(const Map::value_type&);
- static bool isActiveEntry(const Map::value_type&);
- static bool hasStore(const Map::value_type&);
-
- Map map;
- MemberSet firstConfig;
- MemberId self;
- bool completed, resendNeeded;
- size_t size;
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_INITIALSTATUSMAP_H*/
diff --git a/cpp/src/qpid/cluster/LockedConnectionMap.h b/cpp/src/qpid/cluster/LockedConnectionMap.h
deleted file mode 100644
index ac744d4f94..0000000000
--- a/cpp/src/qpid/cluster/LockedConnectionMap.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef QPID_CLUSTER_LOCKEDCONNECTIONMAP_H
-#define QPID_CLUSTER_LOCKEDCONNECTIONMAP_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/types.h"
-#include "qpid/sys/Mutex.h"
-#include "qpid/cluster/Connection.h"
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Thread safe map of connections.
- */
-class LockedConnectionMap
-{
- public:
- void insert(const ConnectionPtr& c) {
- sys::Mutex::ScopedLock l(lock);
- assert(map.find(c->getId()) == map.end());
- map[c->getId()] = c;
- }
-
- ConnectionPtr getErase(const ConnectionId& c) {
- sys::Mutex::ScopedLock l(lock);
- Map::iterator i = map.find(c);
- if (i != map.end()) {
- ConnectionPtr cp = i->second;
- map.erase(i);
- return cp;
- }
- else
- return 0;
- }
-
- void clear() { sys::Mutex::ScopedLock l(lock); map.clear(); }
-
- private:
- typedef std::map<ConnectionId, ConnectionPtr> Map;
- mutable sys::Mutex lock;
- Map map;
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_LOCKEDCONNECTIONMAP_H*/
diff --git a/cpp/src/qpid/cluster/McastFrameHandler.h b/cpp/src/qpid/cluster/McastFrameHandler.h
deleted file mode 100644
index 17e4c2e9f0..0000000000
--- a/cpp/src/qpid/cluster/McastFrameHandler.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef QPID_CLUSTER_MCASTFRAMEHANDLER_H
-#define QPID_CLUSTER_MCASTFRAMEHANDLER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/types.h"
-#include "qpid/cluster/Multicaster.h"
-#include "qpid/framing/FrameHandler.h"
-
-namespace qpid {
-namespace cluster {
-
-/**
- * A frame handler that multicasts frames as CONTROL events.
- */
-class McastFrameHandler : public framing::FrameHandler
-{
- public:
- McastFrameHandler(Multicaster& m, const ConnectionId& cid) : mcast(m), connection(cid) {}
- void handle(framing::AMQFrame& frame) { mcast.mcastControl(frame, connection); }
- private:
- Multicaster& mcast;
- ConnectionId connection;
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_MCASTFRAMEHANDLER_H*/
diff --git a/cpp/src/qpid/cluster/MemberSet.cpp b/cpp/src/qpid/cluster/MemberSet.cpp
deleted file mode 100644
index 97748947b3..0000000000
--- a/cpp/src/qpid/cluster/MemberSet.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "MemberSet.h"
-#include <ostream>
-#include <iterator>
-#include <algorithm>
-
-namespace qpid {
-namespace cluster {
-
-std::string encodeMemberSet(const MemberSet& m) {
- std::string addresses;
- for (MemberSet::const_iterator i = m.begin(); i != m.end(); ++i)
- addresses.append(i->str());
- return addresses;
-}
-
-MemberSet decodeMemberSet(const std::string& s) {
- MemberSet set;
- for (std::string::const_iterator i = s.begin(); i < s.end(); i += 8) {
- assert(size_t(i-s.begin())+8 <= s.size());
- set.insert(MemberId(std::string(i, i+8)));
- }
- return set;
-}
-
-MemberSet intersection(const MemberSet& a, const MemberSet& b)
-{
- MemberSet intersection;
- std::set_intersection(a.begin(), a.end(),
- b.begin(), b.end(),
- std::inserter(intersection, intersection.begin()));
- return intersection;
-
-}
-
-std::ostream& operator<<(std::ostream& o, const MemberSet& ms) {
- copy(ms.begin(), ms.end(), std::ostream_iterator<MemberId>(o, " "));
- return o;
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/MemberSet.h b/cpp/src/qpid/cluster/MemberSet.h
deleted file mode 100644
index 7c97145dc1..0000000000
--- a/cpp/src/qpid/cluster/MemberSet.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef QPID_CLUSTER_MEMBERSET_H
-#define QPID_CLUSTER_MEMBERSET_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "types.h"
-#include <set>
-#include <iosfwd>
-
-namespace qpid {
-namespace cluster {
-
-typedef std::set<MemberId> MemberSet;
-
-std::string encodeMemberSet(const MemberSet&);
-
-MemberSet decodeMemberSet(const std::string&);
-
-MemberSet intersection(const MemberSet& a, const MemberSet& b);
-
-std::ostream& operator<<(std::ostream& o, const MemberSet& ms);
-
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_MEMBERSET_H*/
diff --git a/cpp/src/qpid/cluster/Multicaster.cpp b/cpp/src/qpid/cluster/Multicaster.cpp
deleted file mode 100644
index 217641841c..0000000000
--- a/cpp/src/qpid/cluster/Multicaster.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/Multicaster.h"
-#include "qpid/cluster/Cpg.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/log/Statement.h"
-#include "qpid/framing/AMQBody.h"
-#include "qpid/framing/AMQFrame.h"
-
-namespace qpid {
-namespace cluster {
-
-Multicaster::Multicaster(Cpg& cpg_,
- const boost::shared_ptr<sys::Poller>& poller,
- boost::function<void()> onError_) :
- onError(onError_), cpg(cpg_),
- queue(boost::bind(&Multicaster::sendMcast, this, _1), poller),
- ready(false), bypass(true)
-{}
-
-void Multicaster::mcastControl(const framing::AMQBody& body, const ConnectionId& id) {
- mcast(Event::control(body, id));
-}
-
-void Multicaster::mcastControl(const framing::AMQFrame& frame, const ConnectionId& id) {
- mcast(Event::control(frame, id));
-}
-
-void Multicaster::mcastBuffer(const char* data, size_t size, const ConnectionId& id) {
- Event e(DATA, id, size);
- memcpy(e.getData(), data, size);
- mcast(e);
-}
-
-void Multicaster::mcast(const Event& e) {
- {
- sys::Mutex::ScopedLock l(lock);
- if (!ready && e.isConnection()) {
- holdingQueue.push_back(e);
- return;
- }
- }
- QPID_LOG_IF(trace, e.isControl() && Cluster::loggable(e.getFrame()), "MCAST " << e);
- if (bypass) { // direct, don't queue
- iovec iov = e.toIovec();
- while (!cpg.mcast(&iov, 1))
- ;
- }
- else
- queue.push(e);
-}
-
-Multicaster::PollableEventQueue::Batch::const_iterator Multicaster::sendMcast(const PollableEventQueue::Batch& values) {
- try {
- PollableEventQueue::Batch::const_iterator i = values.begin();
- while( i != values.end()) {
- iovec iov = i->toIovec();
- if (!cpg.mcast(&iov, 1)) {
- // cpg didn't send because of CPG flow control.
- break;
- }
- ++i;
- }
- return i;
- }
- catch (const std::exception& e) {
- QPID_LOG(critical, "Multicast error: " << e.what());
- queue.stop();
- onError();
- return values.end();
- }
-}
-
-void Multicaster::start() {
- queue.start();
- bypass = false;
-}
-
-void Multicaster::setReady() {
- sys::Mutex::ScopedLock l(lock);
- ready = true;
- std::for_each(holdingQueue.begin(), holdingQueue.end(), boost::bind(&Multicaster::mcast, this, _1));
- holdingQueue.clear();
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Multicaster.h b/cpp/src/qpid/cluster/Multicaster.h
deleted file mode 100644
index f70bd5ca31..0000000000
--- a/cpp/src/qpid/cluster/Multicaster.h
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef QPID_CLUSTER_MULTICASTER_H
-#define QPID_CLUSTER_MULTICASTER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/types.h"
-#include "qpid/cluster/Event.h"
-#include "qpid/sys/PollableQueue.h"
-#include "qpid/sys/Mutex.h"
-#include <boost/shared_ptr.hpp>
-#include <deque>
-
-namespace qpid {
-
-namespace sys {
-class Poller;
-}
-
-namespace cluster {
-
-class Cpg;
-
-/**
- * Multicast to the cluster. Shared, thread safe object.
- *
- * holding mode: Hold connection events for later multicast. Cluster
- * events are never held. Used during PRE_INIT/INIT state when we
- * want to hold any connection traffic till we are read in the
- * cluster.
- *
- * bypass mode: Multicast cluster events directly in the calling
- * thread. This mode is used by cluster in PRE_INIT state the poller
- * is not yet be active.
- *
- * Multicaster is created in bypass+holding mode, they are disabled by
- * start and setReady respectively.
- */
-class Multicaster
-{
- public:
- /** Starts in initializing mode. */
- Multicaster(Cpg& cpg_,
- const boost::shared_ptr<sys::Poller>&,
- boost::function<void()> onError
- );
- void mcastControl(const framing::AMQBody& controlBody, const ConnectionId&);
- void mcastControl(const framing::AMQFrame& controlFrame, const ConnectionId&);
- void mcastBuffer(const char*, size_t, const ConnectionId&);
- void mcast(const Event& e);
-
- /** Start the pollable queue, turn off bypass mode. */
- void start();
- /** Switch to ready mode, release held messages. */
- void setReady();
-
- private:
- typedef sys::PollableQueue<Event> PollableEventQueue;
- typedef std::deque<Event> PlainEventQueue;
-
- PollableEventQueue::Batch::const_iterator sendMcast(const PollableEventQueue::Batch& );
-
- sys::Mutex lock;
- boost::function<void()> onError;
- Cpg& cpg;
- PollableEventQueue queue;
- bool ready;
- PlainEventQueue holdingQueue;
- std::vector<struct ::iovec> ioVector;
- bool bypass;
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_MULTICASTER_H*/
diff --git a/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h b/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h
deleted file mode 100644
index 566a82476e..0000000000
--- a/cpp/src/qpid/cluster/NoOpConnectionOutputHandler.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H
-#define QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include <qpid/sys/ConnectionOutputHandler.h>
-
-namespace qpid {
-
-namespace framing { class AMQFrame; }
-
-namespace cluster {
-
-/**
- * Output handler shadow connections, simply discards frames.
- */
-class NoOpConnectionOutputHandler : public sys::ConnectionOutputHandler
-{
- public:
- virtual void send(framing::AMQFrame&) {}
- virtual void close() {}
- virtual void abort() {}
- virtual void activateOutput() {}
- virtual void giveReadCredit(int32_t) {}
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_NOOPCONNECTIONOUTPUTHANDLER_H*/
diff --git a/cpp/src/qpid/cluster/Numbering.h b/cpp/src/qpid/cluster/Numbering.h
deleted file mode 100644
index 99e152c212..0000000000
--- a/cpp/src/qpid/cluster/Numbering.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef QPID_CLUSTER_NUMBERING_H
-#define QPID_CLUSTER_NUMBERING_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <map>
-#include <vector>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * A set of numbered T, with two way mapping number->T T->number
- * Used to construct numberings of objects by code sending and receiving updates.
- */
-template <class T> class Numbering
-{
- public:
- size_t size() const { return byNumber.size(); }
-
- size_t add(const T& t) {
- size_t n = (*this)[t]; // Already in the set?
- if (n == size()) {
- byObject[t] = n;
- byNumber.push_back(t);
- }
- return n;
- }
-
- void clear() { byObject.clear(); byNumber.clear(); }
-
- /**@return object at index n or T() if n > size() */
- T operator[](size_t n) const { return(n < size()) ? byNumber[n] : T(); }
-
- /**@return index of t or size() if t is not in the map */
- size_t operator[](const T& t) const {
- typename Map::const_iterator i = byObject.find(t);
- return (i != byObject.end()) ? i->second : size();
- }
-
- private:
- typedef std::map<T, size_t> Map;
- Map byObject;
- std::vector<T> byNumber;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_NUMBERING_H*/
diff --git a/cpp/src/qpid/cluster/OutputInterceptor.cpp b/cpp/src/qpid/cluster/OutputInterceptor.cpp
deleted file mode 100644
index 2cd1cf9a83..0000000000
--- a/cpp/src/qpid/cluster/OutputInterceptor.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/OutputInterceptor.h"
-#include "qpid/cluster/Connection.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/framing/ClusterConnectionDeliverDoOutputBody.h"
-#include "qpid/framing/AMQFrame.h"
-#include "qpid/log/Statement.h"
-#include <boost/current_function.hpp>
-
-
-namespace qpid {
-namespace cluster {
-
-using namespace framing;
-using namespace std;
-
-NoOpConnectionOutputHandler OutputInterceptor::discardHandler;
-
-OutputInterceptor::OutputInterceptor(Connection& p, sys::ConnectionOutputHandler& h)
- : parent(p), closing(false), next(&h), sendMax(2048), sent(0), sentDoOutput(false)
-{}
-
-void OutputInterceptor::send(framing::AMQFrame& f) {
- sys::Mutex::ScopedLock l(lock);
- next->send(f);
-}
-
-void OutputInterceptor::activateOutput() {
- sys::Mutex::ScopedLock l(lock);
- if (parent.isCatchUp())
- next->activateOutput();
- else
- sendDoOutput(sendMax, l);
-}
-
-void OutputInterceptor::abort() {
- sys::Mutex::ScopedLock l(lock);
- if (parent.isLocal()) {
- next->abort();
- }
-}
-
-void OutputInterceptor::giveReadCredit(int32_t credit) {
- sys::Mutex::ScopedLock l(lock);
- next->giveReadCredit(credit);
-}
-
-// Called in write thread when the IO layer has no more data to write.
-// We only process IO callbacks in the write thread during catch-up.
-// Normally we run doOutput only on delivery of doOutput requests.
-bool OutputInterceptor::doOutput() {
- parent.doCatchupIoCallbacks();
- return false;
-}
-
-// Send output up to limit, calculate new limit.
-void OutputInterceptor::deliverDoOutput(uint32_t limit) {
- sys::Mutex::ScopedLock l(lock);
- sentDoOutput = false;
- sendMax = limit;
- size_t newLimit = limit;
- if (parent.isLocal()) {
- size_t buffered = next->getBuffered();
- if (buffered == 0 && sent == sendMax) // Could have sent more, increase the limit.
- newLimit = sendMax*2;
- else if (buffered > 0 && sent > 1) // Data left unsent, reduce the limit.
- newLimit = (sendMax + sent) / 2;
- }
- sent = 0;
- while (sent < limit) {
- {
- sys::Mutex::ScopedUnlock u(lock);
- if (!parent.getBrokerConnection()->doOutput()) break;
- }
- ++sent;
- }
- if (sent == limit) sendDoOutput(newLimit, l);
-}
-
-void OutputInterceptor::sendDoOutput(size_t newLimit, const sys::Mutex::ScopedLock&) {
- if (parent.isLocal() && !sentDoOutput && !closing && parent.isAnnounced()) {
- sentDoOutput = true;
- parent.getCluster().getMulticast().mcastControl(
- ClusterConnectionDeliverDoOutputBody(ProtocolVersion(), newLimit),
- parent.getId());
- }
-}
-
-// Called in connection thread when local connection closes.
-void OutputInterceptor::closeOutput() {
- sys::Mutex::ScopedLock l(lock);
- closing = true;
- next = &discardHandler;
-}
-
-void OutputInterceptor::close() {
- sys::Mutex::ScopedLock l(lock);
- next->close();
-}
-
-size_t OutputInterceptor::getBuffered() const {
- sys::Mutex::ScopedLock l(lock);
- return next->getBuffered();
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/OutputInterceptor.h b/cpp/src/qpid/cluster/OutputInterceptor.h
deleted file mode 100644
index 3abf5273a0..0000000000
--- a/cpp/src/qpid/cluster/OutputInterceptor.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef QPID_CLUSTER_OUTPUTINTERCEPTOR_H
-#define QPID_CLUSTER_OUTPUTINTERCEPTOR_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/NoOpConnectionOutputHandler.h"
-#include "qpid/sys/ConnectionOutputHandler.h"
-#include "qpid/sys/Mutex.h"
-#include "qpid/broker/ConnectionFactory.h"
-#include <boost/function.hpp>
-
-namespace qpid {
-namespace framing { class AMQFrame; }
-namespace cluster {
-
-class Connection;
-
-/**
- * Interceptor for connection OutputHandler, manages outgoing message replication.
- */
-class OutputInterceptor : public sys::ConnectionOutputHandler {
- public:
- OutputInterceptor(cluster::Connection& p, sys::ConnectionOutputHandler& h);
-
- // sys::ConnectionOutputHandler functions
- void send(framing::AMQFrame& f);
- void abort();
- void activateOutput();
- void giveReadCredit(int32_t);
- void close();
- size_t getBuffered() const;
-
- // Delivery point for doOutput requests.
- void deliverDoOutput(uint32_t limit);
- // Intercept doOutput requests on Connection.
- bool doOutput();
-
- void closeOutput();
-
- uint32_t getSendMax() const { return sendMax; }
- void setSendMax(uint32_t sendMax_) { sendMax=sendMax_; }
-
- cluster::Connection& parent;
-
- private:
- typedef sys::Mutex::ScopedLock Locker;
-
- void sendDoOutput(size_t newLimit, const sys::Mutex::ScopedLock&);
-
- mutable sys::Mutex lock;
- bool closing;
- sys::ConnectionOutputHandler* next;
- static NoOpConnectionOutputHandler discardHandler;
- uint32_t sendMax, sent;
- bool sentDoOutput;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_OUTPUTINTERCEPTOR_H*/
diff --git a/cpp/src/qpid/cluster/PollableQueue.h b/cpp/src/qpid/cluster/PollableQueue.h
deleted file mode 100644
index 10e2ed6ac3..0000000000
--- a/cpp/src/qpid/cluster/PollableQueue.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef QPID_CLUSTER_POLLABLEQUEUE_H
-#define QPID_CLUSTER_POLLABLEQUEUE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/sys/PollableQueue.h"
-#include <qpid/log/Statement.h>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * More convenient version of PollableQueue that handles iterating
- * over the batch and error handling.
- *
- * Constructed in "bypass" mode where items are processed directly
- * rather than put on the queue. This is important for the
- * PRE_INIT stage when Cluster is pumping CPG dispatch directly
- * before the poller has started.
- *
- * Calling start() starts the pollable queue and disabled bypass mode.
- */
-template <class T> class PollableQueue : public sys::PollableQueue<T> {
- public:
- typedef boost::function<void (const T&)> Callback;
- typedef boost::function<void()> ErrorCallback;
-
- PollableQueue(Callback f, ErrorCallback err, const std::string& msg,
- const boost::shared_ptr<sys::Poller>& poller)
- : sys::PollableQueue<T>(boost::bind(&PollableQueue<T>::handleBatch, this, _1),
- poller),
- callback(f), error(err), message(msg), bypass(true)
- {}
-
- typename sys::PollableQueue<T>::Batch::const_iterator
- handleBatch(const typename sys::PollableQueue<T>::Batch& values) {
- try {
- typename sys::PollableQueue<T>::Batch::const_iterator i = values.begin();
- while (i != values.end() && !this->isStopped()) {
- callback(*i);
- ++i;
- }
- return i;
- }
- catch (const std::exception& e) {
- QPID_LOG(critical, message << ": " << e.what());
- this->stop();
- error();
- return values.end();
- }
- }
-
- void push(const T& t) {
- if (bypass) callback(t);
- else sys::PollableQueue<T>::push(t);
- }
-
- void bypassOff() { bypass = false; }
-
- private:
- Callback callback;
- ErrorCallback error;
- std::string message;
- bool bypass;
-};
-
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_POLLABLEQUEUE_H*/
diff --git a/cpp/src/qpid/cluster/PollerDispatch.cpp b/cpp/src/qpid/cluster/PollerDispatch.cpp
deleted file mode 100644
index b8d94b95a5..0000000000
--- a/cpp/src/qpid/cluster/PollerDispatch.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/PollerDispatch.h"
-
-#include "qpid/log/Statement.h"
-#include <boost/bind.hpp>
-
-namespace qpid {
-namespace cluster {
-
-PollerDispatch::PollerDispatch(Cpg& c, boost::shared_ptr<sys::Poller> p,
- boost::function<void()> e)
- : cpg(c), poller(p), onError(e),
- dispatchHandle(cpg,
- boost::bind(&PollerDispatch::dispatch, this, _1), // read
- 0, // write
- boost::bind(&PollerDispatch::disconnect, this, _1) // disconnect
- ),
- started(false)
-{}
-
-PollerDispatch::~PollerDispatch() {
- if (started)
- dispatchHandle.stopWatch();
-}
-
-void PollerDispatch::start() {
- dispatchHandle.startWatch(poller);
- started = true;
-}
-
-// Entry point: called by IO to dispatch CPG events.
-void PollerDispatch::dispatch(sys::DispatchHandle& h) {
- try {
- cpg.dispatchAll();
- h.rewatch();
- } catch (const std::exception& e) {
- QPID_LOG(critical, "Error in cluster dispatch: " << e.what());
- onError();
- }
-}
-
-// Entry point: called if disconnected from CPG.
-void PollerDispatch::disconnect(sys::DispatchHandle& ) {
- if (!poller->hasShutdown()) {
- QPID_LOG(critical, "Disconnected from cluster");
- onError();
- }
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/PollerDispatch.h b/cpp/src/qpid/cluster/PollerDispatch.h
deleted file mode 100644
index 63801e0de9..0000000000
--- a/cpp/src/qpid/cluster/PollerDispatch.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef QPID_CLUSTER_POLLERDISPATCH_H
-#define QPID_CLUSTER_POLLERDISPATCH_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/Cpg.h"
-#include "qpid/sys/Poller.h"
-#include "qpid/sys/DispatchHandle.h"
-#include <boost/function.hpp>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Dispatch CPG events via the poller.
- */
-class PollerDispatch {
- public:
- PollerDispatch(Cpg&, boost::shared_ptr<sys::Poller> poller,
- boost::function<void()> onError) ;
-
- ~PollerDispatch();
-
- void start();
-
- private:
- // Poller callbacks
- void dispatch(sys::DispatchHandle&); // Dispatch CPG events.
- void disconnect(sys::DispatchHandle&); // CPG was disconnected
-
- Cpg& cpg;
- boost::shared_ptr<sys::Poller> poller;
- boost::function<void()> onError;
- sys::DispatchHandleRef dispatchHandle;
- bool started;
-
-
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_POLLERDISPATCH_H*/
diff --git a/cpp/src/qpid/cluster/ProxyInputHandler.h b/cpp/src/qpid/cluster/ProxyInputHandler.h
deleted file mode 100644
index ad7f2c44bd..0000000000
--- a/cpp/src/qpid/cluster/ProxyInputHandler.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef QPID_CLUSTER_PROXYINPUTHANDLER_H
-#define QPID_CLUSTER_PROXYINPUTHANDLER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/sys/ConnectionInputHandler.h"
-#include <boost/intrusive_ptr.hpp>
-
-namespace qpid {
-
-namespace framing { class AMQFrame; }
-
-namespace cluster {
-
-/**
- * Proxies ConnectionInputHandler functions and ensures target.closed()
- * is called, on deletion if not before.
- */
-class ProxyInputHandler : public sys::ConnectionInputHandler
-{
- public:
- ProxyInputHandler(boost::intrusive_ptr<cluster::Connection> t) : target(t) {}
- ~ProxyInputHandler() { closed(); }
-
- void received(framing::AMQFrame& f) { target->received(f); }
- void closed() { if (target) target->closed(); target = 0; }
- void idleOut() { target->idleOut(); }
- void idleIn() { target->idleIn(); }
- bool doOutput() { return target->doOutput(); }
-
- private:
- boost::intrusive_ptr<cluster::Connection> target;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_PROXYINPUTHANDLER_H*/
diff --git a/cpp/src/qpid/cluster/Quorum.h b/cpp/src/qpid/cluster/Quorum.h
deleted file mode 100644
index bbfa473f94..0000000000
--- a/cpp/src/qpid/cluster/Quorum.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef QPID_CLUSTER_QUORUM_H
-#define QPID_CLUSTER_QUORUM_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "config.h"
-
-#if HAVE_LIBCMAN_H
-#include "qpid/cluster/Quorum_cman.h"
-#else
-#include "qpid/cluster/Quorum_null.h"
-#endif
-
-#endif /*!QPID_CLUSTER_QUORUM_H*/
diff --git a/cpp/src/qpid/cluster/Quorum_cman.cpp b/cpp/src/qpid/cluster/Quorum_cman.cpp
deleted file mode 100644
index 728f824b16..0000000000
--- a/cpp/src/qpid/cluster/Quorum_cman.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/Quorum_cman.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/log/Statement.h"
-#include "qpid/Options.h"
-#include "qpid/sys/Time.h"
-#include "qpid/sys/posix/PrivatePosix.h"
-
-namespace qpid {
-namespace cluster {
-
-namespace {
-
-boost::function<void()> errorFn;
-
-void cmanCallbackFn(cman_handle_t handle, void */*privdata*/, int reason, int /*arg*/) {
- if (reason == CMAN_REASON_STATECHANGE && !cman_is_quorate(handle)) {
- QPID_LOG(critical, "Lost contact with cluster quorum.");
- if (errorFn) errorFn();
- cman_stop_notification(handle);
- }
-}
-}
-
-Quorum::Quorum(boost::function<void()> err) : cman(0), cmanFd(0) {
- errorFn = err;
-}
-
-Quorum::~Quorum() {
- if (dispatchHandle.get()) dispatchHandle->stopWatch();
- dispatchHandle.reset();
- if (cman) cman_finish(cman);
-}
-
-void Quorum::start(boost::shared_ptr<sys::Poller> p) {
- poller = p;
- QPID_LOG(debug, "Connecting to quorum service.");
- cman = cman_init(0);
- if (cman == 0) throw ErrnoException("Can't connect to cman service");
- if (!cman_is_quorate(cman)) {
- QPID_LOG(notice, "Waiting for cluster quorum.");
- while(!cman_is_quorate(cman)) sys::sleep(5);
- }
- int err = cman_start_notification(cman, cmanCallbackFn);
- if (err != 0) throw ErrnoException("Can't register for cman notifications");
- watch(getFd());
-}
-
-void Quorum::watch(int fd) {
- cmanFd = fd;
- if (dispatchHandle.get()) dispatchHandle->stopWatch();
- ioHandle.reset(new sys::PosixIOHandle(cmanFd));
- dispatchHandle.reset(
- new sys::DispatchHandleRef(
- *ioHandle, // This must outlive the dispatchHandleRef
- boost::bind(&Quorum::dispatch, this, _1), // read
- 0, // write
- boost::bind(&Quorum::disconnect, this, _1) // disconnect
- ));
- dispatchHandle->startWatch(poller);
-}
-
-int Quorum::getFd() {
- int fd = cman_get_fd(cman);
- if (fd == 0) throw ErrnoException("Can't get cman file descriptor");
- return fd;
-}
-
-void Quorum::dispatch(sys::DispatchHandle&) {
- try {
- cman_dispatch(cman, CMAN_DISPATCH_ALL);
- int fd = getFd();
- if (fd != cmanFd) watch(fd);
- } catch (const std::exception& e) {
- QPID_LOG(critical, "Error in quorum dispatch: " << e.what());
- errorFn();
- }
-}
-
-void Quorum::disconnect(sys::DispatchHandle&) {
- QPID_LOG(critical, "Disconnected from quorum service");
- errorFn();
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/Quorum_cman.h b/cpp/src/qpid/cluster/Quorum_cman.h
deleted file mode 100644
index 98e6baee89..0000000000
--- a/cpp/src/qpid/cluster/Quorum_cman.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef QPID_CLUSTER_QUORUM_CMAN_H
-#define QPID_CLUSTER_QUORUM_CMAN_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <qpid/sys/DispatchHandle.h>
-#include <boost/function.hpp>
-#include <boost/shared_ptr.hpp>
-#include <memory>
-
-extern "C" {
-#include <libcman.h>
-}
-
-namespace qpid {
-namespace sys {
-class Poller;
-class PosixIOHandle;
-}
-
-namespace cluster {
-class Cluster;
-
-class Quorum {
- public:
- Quorum(boost::function<void ()> onError);
- ~Quorum();
- void start(boost::shared_ptr<sys::Poller>);
-
- private:
- void dispatch(sys::DispatchHandle&);
- void disconnect(sys::DispatchHandle&);
- int getFd();
- void watch(int fd);
-
- cman_handle_t cman;
- int cmanFd;
- std::auto_ptr<sys::PosixIOHandle> ioHandle;
- std::auto_ptr<sys::DispatchHandleRef> dispatchHandle;
- boost::shared_ptr<sys::Poller> poller;
-};
-
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_QUORUM_CMAN_H*/
diff --git a/cpp/src/qpid/cluster/RetractClient.cpp b/cpp/src/qpid/cluster/RetractClient.cpp
deleted file mode 100644
index a8c4b0d543..0000000000
--- a/cpp/src/qpid/cluster/RetractClient.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/RetractClient.h"
-#include "qpid/cluster/UpdateClient.h"
-#include "qpid/framing/ClusterConnectionRetractOfferBody.h"
-#include "qpid/client/ConnectionAccess.h"
-#include "qpid/client/ConnectionImpl.h"
-#include "qpid/log/Statement.h"
-
-namespace qpid {
-namespace cluster {
-
-using namespace framing;
-
-namespace {
-
-struct AutoClose {
- client::Connection& connection;
- AutoClose(client::Connection& c) : connection(c) {}
- ~AutoClose() { connection.close(); }
-};
-}
-
-RetractClient::RetractClient(const Url& u, const client::ConnectionSettings& cs)
- : url(u), connectionSettings(cs)
-{}
-
-RetractClient::~RetractClient() { delete this; }
-
-
-void RetractClient::run() {
- try {
- client::Connection c = UpdateClient::catchUpConnection();
- c.open(url, connectionSettings);
- AutoClose ac(c);
- AMQFrame retract((ClusterConnectionRetractOfferBody()));
- client::ConnectionAccess::getImpl(c)->expand(retract.encodedSize(), false);
- client::ConnectionAccess::getImpl(c)->handle(retract);
- } catch (const std::exception& e) {
- QPID_LOG(error, " while retracting retract to " << url << ": " << e.what());
- }
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/RetractClient.h b/cpp/src/qpid/cluster/RetractClient.h
deleted file mode 100644
index 533fc3f7ef..0000000000
--- a/cpp/src/qpid/cluster/RetractClient.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef QPID_CLUSTER_RETRACTCLIENT_H
-#define QPID_CLUSTER_RETRACTCLIENT_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/client/ConnectionSettings.h"
-#include "qpid/sys/Runnable.h"
-#include "qpid/Url.h"
-
-
-namespace qpid {
-namespace cluster {
-
-/**
- * A client that retracts an offer to a remote broker using AMQP. @see UpdateClient
- */
-class RetractClient : public sys::Runnable {
- public:
-
- RetractClient(const Url&, const client::ConnectionSettings&);
- ~RetractClient();
- void run(); // Will delete this when finished.
-
- private:
- Url url;
- client::ConnectionSettings connectionSettings;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_RETRACTCLIENT_H*/
diff --git a/cpp/src/qpid/cluster/SecureConnectionFactory.cpp b/cpp/src/qpid/cluster/SecureConnectionFactory.cpp
deleted file mode 100644
index 2672d8360c..0000000000
--- a/cpp/src/qpid/cluster/SecureConnectionFactory.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/cluster/SecureConnectionFactory.h"
-#include "qpid/framing/ProtocolVersion.h"
-#include "qpid/cluster/ConnectionCodec.h"
-#include "qpid/broker/SecureConnection.h"
-#include "qpid/sys/SecuritySettings.h"
-#include "qpid/log/Statement.h"
-#include <memory>
-
-
-namespace qpid {
-namespace cluster {
-
-using framing::ProtocolVersion;
-using qpid::sys::SecuritySettings;
-using qpid::broker::SecureConnection;
-
-typedef std::auto_ptr<qpid::broker::SecureConnection> SecureConnectionPtr;
-typedef std::auto_ptr<qpid::sys::ConnectionCodec> CodecPtr;
-
-SecureConnectionFactory::SecureConnectionFactory(CodecFactoryPtr f) : codecFactory(f) {
-}
-
-sys::ConnectionCodec*
-SecureConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, const std::string& id,
- const SecuritySettings& external) {
- CodecPtr codec(codecFactory->create(v, out, id, external));
- ConnectionCodec* clusterCodec = dynamic_cast<qpid::cluster::ConnectionCodec*>(codec.get());
- if (clusterCodec) {
- SecureConnectionPtr sc(new SecureConnection());
- clusterCodec->setSecureConnection(sc.get());
- sc->setCodec(codec);
- return sc.release();
- }
- return 0;
-}
-
-sys::ConnectionCodec*
-SecureConnectionFactory::create(sys::OutputControl& out, const std::string& id,
- const SecuritySettings& external) {
- // used to create connections from one broker to another
- CodecPtr codec(codecFactory->create(out, id, external));
- ConnectionCodec* clusterCodec = dynamic_cast<qpid::cluster::ConnectionCodec*>(codec.get());
- if (clusterCodec) {
- SecureConnectionPtr sc(new SecureConnection());
- clusterCodec->setSecureConnection(sc.get());
- sc->setCodec(codec);
- return sc.release();
- }
- return 0;
-}
-
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/StoreStatus.cpp b/cpp/src/qpid/cluster/StoreStatus.cpp
deleted file mode 100644
index 14c999bb05..0000000000
--- a/cpp/src/qpid/cluster/StoreStatus.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "StoreStatus.h"
-#include "qpid/Exception.h"
-#include "qpid/Msg.h"
-#include "qpid/log/Statement.h"
-#include <boost/filesystem/path.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/filesystem/operations.hpp>
-#include <boost/scoped_array.hpp>
-#include <fstream>
-#include <sstream>
-
-namespace qpid {
-namespace cluster {
-
-using framing::Uuid;
-using namespace framing::cluster;
-namespace fs=boost::filesystem;
-using namespace std;
-
-StoreStatus::StoreStatus(const std::string& d)
- : state(STORE_STATE_NO_STORE), dataDir(d)
-{}
-
-namespace {
-
-const char* SUBDIR="cluster";
-const char* STORE_STATUS="store.status";
-
-string readFile(const fs::path& path) {
- fs::ifstream is;
- is.exceptions(std::ios::badbit | std::ios::failbit);
- is.open(path);
- // get length of file:
- is.seekg (0, ios::end);
- size_t length = is.tellg();
- is.seekg (0, ios::beg);
- // load data
- boost::scoped_array<char> buffer(new char[length]);
- is.read(buffer.get(), length);
- is.close();
- return string(buffer.get(), length);
-}
-
-void writeFile(const fs::path& path, const string& data) {
- fs::ofstream os;
- os.exceptions(std::ios::badbit | std::ios::failbit);
- os.open(path);
- os.write(data.data(), data.size());
- os.close();
-}
-
-} // namespace
-
-
-void StoreStatus::load() {
- if (dataDir.empty()) {
- throw Exception(QPID_MSG("No data-dir: When a store is loaded together with clustering, --data-dir must be specified."));
- }
- try {
- fs::path dir = fs::path(dataDir, fs::native)/SUBDIR;
- create_directory(dir);
- fs::path file = dir/STORE_STATUS;
- if (fs::exists(file)) {
- string data = readFile(file);
- istringstream is(data);
- is.exceptions(std::ios::badbit | std::ios::failbit);
- is >> ws >> clusterId >> ws >> shutdownId;
- if (!clusterId)
- throw Exception(QPID_MSG("Invalid cluster store state, no cluster-id"));
- if (shutdownId) state = STORE_STATE_CLEAN_STORE;
- else state = STORE_STATE_DIRTY_STORE;
- }
- else { // Starting from empty store
- clusterId = Uuid(true);
- save();
- state = STORE_STATE_EMPTY_STORE;
- }
- }
- catch (const std::exception&e) {
- throw Exception(QPID_MSG("Cannot load cluster store status: " << e.what()));
- }
-}
-
-void StoreStatus::save() {
- if (dataDir.empty()) return;
- try {
- ostringstream os;
- os << clusterId << endl << shutdownId << endl;
- fs::path file = fs::path(dataDir, fs::native)/SUBDIR/STORE_STATUS;
- writeFile(file, os.str());
- }
- catch (const std::exception& e) {
- throw Exception(QPID_MSG("Cannot save cluster store status: " << e.what()));
- }
-}
-
-bool StoreStatus::hasStore() const {
- return state != framing::cluster::STORE_STATE_NO_STORE;
-}
-
-void StoreStatus::dirty() {
- assert(hasStore());
- if (shutdownId) {
- shutdownId = Uuid();
- save();
- }
- state = STORE_STATE_DIRTY_STORE;
-}
-
-void StoreStatus::clean(const Uuid& shutdownId_) {
- assert(hasStore());
- assert(shutdownId_);
- if (shutdownId_ != shutdownId) {
- shutdownId = shutdownId_;
- save();
- }
- state = STORE_STATE_CLEAN_STORE;
-}
-
-void StoreStatus::setClusterId(const Uuid& clusterId_) {
- clusterId = clusterId_;
- save();
-}
-
-const char* stateName(StoreState s) {
- switch (s) {
- case STORE_STATE_NO_STORE: return "none";
- case STORE_STATE_EMPTY_STORE: return "empty";
- case STORE_STATE_DIRTY_STORE: return "dirty";
- case STORE_STATE_CLEAN_STORE: return "clean";
- }
- assert(0);
- return "unknown";
-}
-
-ostream& operator<<(ostream& o, framing::cluster::StoreState s) { return o << stateName(s); }
-
-ostream& operator<<(ostream& o, const StoreStatus& s) {
- o << s.getState();
- if (s.getState() == STORE_STATE_DIRTY_STORE)
- o << " cluster-id=" << s.getClusterId();
- if (s.getState() == STORE_STATE_CLEAN_STORE) {
- o << " cluster-id=" << s.getClusterId()
- << " shutdown-id=" << s.getShutdownId();
- }
- return o;
-}
-
-}} // namespace qpid::cluster
-
diff --git a/cpp/src/qpid/cluster/StoreStatus.h b/cpp/src/qpid/cluster/StoreStatus.h
deleted file mode 100644
index 7442fcf02c..0000000000
--- a/cpp/src/qpid/cluster/StoreStatus.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef QPID_CLUSTER_STORESTATE_H
-#define QPID_CLUSTER_STORESTATE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/framing/Uuid.h"
-#include "qpid/framing/SequenceNumber.h"
-#include "qpid/framing/enum.h"
-#include <iosfwd>
-
-namespace qpid {
-namespace cluster {
-
-/**
- * State of the store for cluster purposes.
- */
-class StoreStatus
-{
- public:
- typedef framing::Uuid Uuid;
- typedef framing::cluster::StoreState StoreState;
-
- StoreStatus(const std::string& dir);
-
- framing::cluster::StoreState getState() const { return state; }
-
- const Uuid& getClusterId() const { return clusterId; }
- void setClusterId(const Uuid&);
- const Uuid& getShutdownId() const { return shutdownId; }
-
- void load();
- void dirty(); // Mark the store in use.
- void clean(const Uuid& shutdownId); // Mark the store clean.
- bool hasStore() const;
-
- private:
- void save();
-
- framing::cluster::StoreState state;
- Uuid clusterId, shutdownId;
- std::string dataDir;
-};
-
-const char* stateName(framing::cluster::StoreState);
-std::ostream& operator<<(std::ostream&, framing::cluster::StoreState);
-std::ostream& operator<<(std::ostream&, const StoreStatus&);
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_STORESTATE_H*/
diff --git a/cpp/src/qpid/cluster/UpdateClient.cpp b/cpp/src/qpid/cluster/UpdateClient.cpp
deleted file mode 100644
index 8737418570..0000000000
--- a/cpp/src/qpid/cluster/UpdateClient.cpp
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/amqp_0_10/Codecs.h"
-#include "qpid/cluster/UpdateClient.h"
-#include "qpid/cluster/Cluster.h"
-#include "qpid/cluster/ClusterMap.h"
-#include "qpid/cluster/Connection.h"
-#include "qpid/cluster/Decoder.h"
-#include "qpid/cluster/ExpiryPolicy.h"
-#include "qpid/cluster/UpdateDataExchange.h"
-#include "qpid/client/SessionBase_0_10Access.h"
-#include "qpid/client/ConnectionAccess.h"
-#include "qpid/client/SessionImpl.h"
-#include "qpid/client/ConnectionImpl.h"
-#include "qpid/client/Future.h"
-#include "qpid/broker/Broker.h"
-#include "qpid/broker/Fairshare.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/QueueRegistry.h"
-#include "qpid/broker/LinkRegistry.h"
-#include "qpid/broker/Bridge.h"
-#include "qpid/broker/Link.h"
-#include "qpid/broker/Message.h"
-#include "qpid/broker/Exchange.h"
-#include "qpid/broker/ExchangeRegistry.h"
-#include "qpid/broker/SessionHandler.h"
-#include "qpid/broker/SessionState.h"
-#include "qpid/broker/TxOpVisitor.h"
-#include "qpid/broker/DtxAck.h"
-#include "qpid/broker/DtxBuffer.h"
-#include "qpid/broker/DtxWorkRecord.h"
-#include "qpid/broker/TxAccept.h"
-#include "qpid/broker/TxPublish.h"
-#include "qpid/broker/RecoveredDequeue.h"
-#include "qpid/broker/RecoveredEnqueue.h"
-#include "qpid/broker/StatefulQueueObserver.h"
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/framing/ClusterConnectionMembershipBody.h"
-#include "qpid/framing/ClusterConnectionShadowReadyBody.h"
-#include "qpid/framing/ClusterConnectionSessionStateBody.h"
-#include "qpid/framing/ClusterConnectionConsumerStateBody.h"
-#include "qpid/framing/FieldValue.h"
-#include "qpid/framing/enum.h"
-#include "qpid/framing/ProtocolVersion.h"
-#include "qpid/framing/TypeCode.h"
-#include "qpid/log/Statement.h"
-#include "qpid/types/Variant.h"
-#include "qpid/Url.h"
-#include "qmf/org/apache/qpid/broker/ManagementSetupState.h"
-#include <boost/bind.hpp>
-#include <boost/cast.hpp>
-#include <algorithm>
-#include <iterator>
-#include <sstream>
-
-namespace qpid {
-namespace cluster {
-
-using std::string;
-
-using amqp_0_10::ListCodec;
-using broker::Broker;
-using broker::Exchange;
-using broker::Queue;
-using broker::QueueBinding;
-using broker::Message;
-using broker::SemanticState;
-using types::Variant;
-
-using namespace framing;
-namespace arg=client::arg;
-using client::SessionBase_0_10Access;
-
-namespace _qmf = qmf::org::apache::qpid::broker;
-
-// Reserved exchange/queue name for catch-up, avoid clashes with user queues/exchanges.
-const std::string UpdateClient::UPDATE("x-qpid.cluster-update");
-// Name for header used to carry expiration information.
-const std::string UpdateClient::X_QPID_EXPIRATION = "x-qpid.expiration";
-// Headers used to flag headers/properties added by the UpdateClient so they can be
-// removed on the other side.
-const std::string UpdateClient::X_QPID_NO_MESSAGE_PROPS = "x-qpid.no-message-props";
-const std::string UpdateClient::X_QPID_NO_HEADERS = "x-qpid.no-headers";
-
-std::ostream& operator<<(std::ostream& o, const UpdateClient& c) {
- return o << "cluster(" << c.updaterId << " UPDATER)";
-}
-
-struct ClusterConnectionProxy : public AMQP_AllProxy::ClusterConnection, public framing::FrameHandler
-{
- boost::shared_ptr<qpid::client::ConnectionImpl> connection;
-
- ClusterConnectionProxy(client::Connection c) :
- AMQP_AllProxy::ClusterConnection(*static_cast<framing::FrameHandler*>(this)),
- connection(client::ConnectionAccess::getImpl(c)) {}
- ClusterConnectionProxy(client::AsyncSession s) :
- AMQP_AllProxy::ClusterConnection(SessionBase_0_10Access(s).get()->out) {}
-
- void handle(framing::AMQFrame& f)
- {
- assert(connection);
- connection->expand(f.encodedSize(), false);
- connection->handle(f);
- }
-};
-
-// Create a connection with special version that marks it as a catch-up connection.
-client::Connection UpdateClient::catchUpConnection() {
- client::Connection c;
- client::ConnectionAccess::setVersion(c, ProtocolVersion(0x80 , 0x80 + 10));
- return c;
-}
-
-// Send a control body directly to the session.
-void send(client::AsyncSession& s, const AMQBody& body) {
- client::SessionBase_0_10Access sb(s);
- sb.get()->send(body);
-}
-
-// TODO aconway 2008-09-24: optimization: update connections/sessions in parallel.
-
-UpdateClient::UpdateClient(const MemberId& updater, const MemberId& updatee, const Url& url,
- broker::Broker& broker, const ClusterMap& m, ExpiryPolicy& expiry_,
- const Cluster::ConnectionVector& cons, Decoder& decoder_,
- const boost::function<void()>& ok,
- const boost::function<void(const std::exception&)>& fail,
- const client::ConnectionSettings& cs
-)
- : updaterId(updater), updateeId(updatee), updateeUrl(url), updaterBroker(broker), map(m),
- expiry(expiry_), connections(cons), decoder(decoder_),
- connection(catchUpConnection()), shadowConnection(catchUpConnection()),
- done(ok), failed(fail), connectionSettings(cs)
-{}
-
-UpdateClient::~UpdateClient() {}
-
-void UpdateClient::run() {
- try {
- connection.open(updateeUrl, connectionSettings);
- session = connection.newSession(UPDATE);
- session.sync();
- update();
- done();
- } catch (const std::exception& e) {
- failed(e);
- }
- delete this;
-}
-
-void UpdateClient::update() {
- QPID_LOG(debug, *this << " updating state to " << updateeId
- << " at " << updateeUrl);
- Broker& b = updaterBroker;
-
- if(b.getExpiryPolicy()) {
- QPID_LOG(debug, *this << "Updating updatee with cluster time");
- qpid::sys::AbsTime clusterTime = b.getExpiryPolicy()->getCurrentTime();
- int64_t time = qpid::sys::Duration(qpid::sys::EPOCH, clusterTime);
- ClusterConnectionProxy(session).clock(time);
- }
-
- updateManagementSetupState();
-
- b.getExchanges().eachExchange(boost::bind(&UpdateClient::updateExchange, this, _1));
- b.getQueues().eachQueue(boost::bind(&UpdateClient::updateNonExclusiveQueue, this, _1));
-
- // Update queue is used to transfer acquired messages that are no
- // longer on their original queue.
- session.queueDeclare(arg::queue=UPDATE, arg::autoDelete=true);
- session.sync();
-
- std::for_each(connections.begin(), connections.end(),
- boost::bind(&UpdateClient::updateConnection, this, _1));
-
- // some Queue Observers need session state & msgs synced first, so sync observers now
- b.getQueues().eachQueue(boost::bind(&UpdateClient::updateQueueObservers, this, _1));
-
- // Update queue listeners: must come after sessions so consumerNumbering is populated
- b.getQueues().eachQueue(boost::bind(&UpdateClient::updateQueueListeners, this, _1));
-
- updateLinks();
- updateManagementAgent();
- updateDtxManager();
- session.queueDelete(arg::queue=UPDATE);
-
- session.close();
-
- ClusterConnectionMembershipBody membership;
- map.toMethodBody(membership);
- AMQFrame frame(membership);
- client::ConnectionAccess::getImpl(connection)->expand(frame.encodedSize(), false);
- client::ConnectionAccess::getImpl(connection)->handle(frame);
-
- // NOTE: connection will be closed from the other end, don't close
- // it here as that causes a race.
-
- // TODO aconway 2010-03-15: This sleep avoids the race condition
- // described in // https://bugzilla.redhat.com/show_bug.cgi?id=568831.
- // It allows the connection to fully close before destroying the
- // Connection object. Remove when the bug is fixed.
- //
- sys::usleep(10*1000);
-
- QPID_LOG(debug, *this << " update completed to " << updateeId << " at " << updateeUrl);
-}
-
-namespace {
-template <class T> std::string encode(const T& t) {
- std::string encoded;
- encoded.resize(t.encodedSize());
- framing::Buffer buf(const_cast<char*>(encoded.data()), encoded.size());
- t.encode(buf);
- return encoded;
-}
-} // namespace
-
-
-// Propagate the management state
-void UpdateClient::updateManagementSetupState()
-{
- management::ManagementAgent* agent = updaterBroker.getManagementAgent();
- if (!agent) return;
-
- QPID_LOG(debug, *this << " updating management setup-state.");
- std::string vendor, product, instance;
- agent->getName(vendor, product, instance);
- ClusterConnectionProxy(session).managementSetupState(
- agent->getNextObjectId(), agent->getBootSequence(), agent->getUuid(),
- vendor, product, instance);
-}
-
-void UpdateClient::updateManagementAgent()
-{
- management::ManagementAgent* agent = updaterBroker.getManagementAgent();
- if (!agent) return;
- string data;
-
- QPID_LOG(debug, *this << " updating management schemas. ")
- agent->exportSchemas(data);
- session.messageTransfer(
- arg::content=client::Message(data, UpdateDataExchange::MANAGEMENT_SCHEMAS_KEY),
- arg::destination=UpdateDataExchange::EXCHANGE_NAME);
-
- QPID_LOG(debug, *this << " updating management agents. ")
- agent->exportAgents(data);
- session.messageTransfer(
- arg::content=client::Message(data, UpdateDataExchange::MANAGEMENT_AGENTS_KEY),
- arg::destination=UpdateDataExchange::EXCHANGE_NAME);
-
- QPID_LOG(debug, *this << " updating management deleted objects. ")
- typedef management::ManagementAgent::DeletedObjectList DeletedObjectList;
- DeletedObjectList deleted;
- agent->exportDeletedObjects(deleted);
- Variant::List list;
- for (DeletedObjectList::iterator i = deleted.begin(); i != deleted.end(); ++i) {
- string encoded;
- (*i)->encode(encoded);
- list.push_back(encoded);
- }
- ListCodec::encode(list, data);
- session.messageTransfer(
- arg::content=client::Message(data, UpdateDataExchange::MANAGEMENT_DELETED_OBJECTS_KEY),
- arg::destination=UpdateDataExchange::EXCHANGE_NAME);
-}
-
-void UpdateClient::updateExchange(const boost::shared_ptr<Exchange>& ex) {
- QPID_LOG(debug, *this << " updating exchange " << ex->getName());
- ClusterConnectionProxy(session).exchange(encode(*ex));
-}
-
-/** Bind a queue to the update exchange and update messges to it
- * setting the message possition as needed.
- */
-class MessageUpdater {
- std::string queue;
- bool haveLastPos;
- framing::SequenceNumber lastPos;
- client::AsyncSession session;
- ExpiryPolicy& expiry;
-
- public:
-
- MessageUpdater(const string& q, const client::AsyncSession s, ExpiryPolicy& expiry_) : queue(q), haveLastPos(false), session(s), expiry(expiry_) {
- session.exchangeBind(queue, UpdateClient::UPDATE);
- }
-
- ~MessageUpdater() {
- try {
- session.exchangeUnbind(queue, UpdateClient::UPDATE);
- }
- catch (const std::exception& e) {
- // Don't throw in a destructor.
- QPID_LOG(error, "Unbinding update queue " << queue << ": " << e.what());
- }
- }
-
- void updateQueuedMessage(const broker::QueuedMessage& message) {
- // Send the queue position if necessary.
- if (!haveLastPos || message.position - lastPos != 1) {
- ClusterConnectionProxy(session).queuePosition(queue, message.position.getValue()-1);
- haveLastPos = true;
- }
- lastPos = message.position;
-
- // if the ttl > 0, we need to send the calculated expiration time to the updatee
- const DeliveryProperties* dprops =
- message.payload->getProperties<DeliveryProperties>();
- if (dprops && dprops->getTtl() > 0) {
- bool hadMessageProps =
- message.payload->hasProperties<framing::MessageProperties>();
- const framing::MessageProperties* mprops =
- message.payload->getProperties<framing::MessageProperties>();
- bool hadApplicationHeaders = mprops->hasApplicationHeaders();
- message.payload->insertCustomProperty(UpdateClient::X_QPID_EXPIRATION,
- sys::Duration(sys::EPOCH, message.payload->getExpiration()));
- // If message properties or application headers didn't exist
- // prior to us adding data, we want to remove them on the other side.
- if (!hadMessageProps)
- message.payload->insertCustomProperty(UpdateClient::X_QPID_NO_MESSAGE_PROPS, 0);
- else if (!hadApplicationHeaders)
- message.payload->insertCustomProperty(UpdateClient::X_QPID_NO_HEADERS, 0);
- }
-
- // We can't send a broker::Message via the normal client API,
- // and it would be expensive to copy it into a client::Message
- // so we go a bit under the client API covers here.
- //
- SessionBase_0_10Access sb(session);
- // Disable client code that clears the delivery-properties.exchange
- sb.get()->setDoClearDeliveryPropertiesExchange(false);
- framing::MessageTransferBody transfer(
- *message.payload->getFrames().as<framing::MessageTransferBody>());
- transfer.setDestination(UpdateClient::UPDATE);
-
- sb.get()->send(transfer, message.payload->getFrames(),
- !message.payload->isContentReleased());
- if (message.payload->isContentReleased()){
- uint16_t maxFrameSize = sb.get()->getConnection()->getNegotiatedSettings().maxFrameSize;
- uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead();
- bool morecontent = true;
- for (uint64_t offset = 0; morecontent; offset += maxContentSize)
- {
- AMQFrame frame((AMQContentBody()));
- morecontent = message.payload->getContentFrame(
- *(message.queue), frame, maxContentSize, offset);
- sb.get()->sendRawFrame(frame);
- }
- }
- }
-
- void updateMessage(const boost::intrusive_ptr<broker::Message>& message) {
- updateQueuedMessage(broker::QueuedMessage(0, message, haveLastPos? lastPos.getValue()+1 : 1));
- }
-};
-
-void UpdateClient::updateQueue(client::AsyncSession& s, const boost::shared_ptr<Queue>& q) {
- broker::Exchange::shared_ptr alternateExchange = q->getAlternateExchange();
- _qmf::Queue* mgmtQueue = dynamic_cast<_qmf::Queue*>(q->GetManagementObject());
- s.queueDeclare(
- arg::queue = q->getName(),
- arg::durable = q->isDurable(),
- arg::autoDelete = q->isAutoDelete(),
- arg::alternateExchange = alternateExchange ? alternateExchange->getName() : "",
- arg::arguments = q->getSettings(),
- arg::exclusive = mgmtQueue && mgmtQueue->get_exclusive()
- );
- MessageUpdater updater(q->getName(), s, expiry);
- q->eachMessage(boost::bind(&MessageUpdater::updateQueuedMessage, &updater, _1));
- q->eachBinding(boost::bind(&UpdateClient::updateBinding, this, s, q->getName(), _1));
- ClusterConnectionProxy(s).queuePosition(q->getName(), q->getPosition());
- uint priority, count;
- if (qpid::broker::Fairshare::getState(q->getMessages(), priority, count)) {
- ClusterConnectionProxy(s).queueFairshareState(q->getName(), priority, count);
- }
-
- ClusterConnectionProxy(s).queueDequeueSincePurgeState(q->getName(), q->getDequeueSincePurge());
-}
-
-void UpdateClient::updateExclusiveQueue(const boost::shared_ptr<broker::Queue>& q) {
- QPID_LOG(debug, *this << " updating exclusive queue " << q->getName() << " on " << shadowSession.getId());
- updateQueue(shadowSession, q);
-}
-
-void UpdateClient::updateNonExclusiveQueue(const boost::shared_ptr<broker::Queue>& q) {
- if (!q->hasExclusiveOwner()) {
- QPID_LOG(debug, *this << " updating queue " << q->getName());
- updateQueue(session, q);
- }//else queue will be updated as part of session state of owning session
-}
-
-void UpdateClient::updateBinding(client::AsyncSession& s, const std::string& queue, const QueueBinding& binding) {
- if (binding.exchange.size())
- s.exchangeBind(queue, binding.exchange, binding.key, binding.args);
- //else its the default exchange and there is no need to replicate
- //the binding, the creation of the queue will have done so
- //automatically
-}
-
-void UpdateClient::updateOutputTask(const sys::OutputTask* task) {
- const SemanticState::ConsumerImpl* cci =
- boost::polymorphic_downcast<const SemanticState::ConsumerImpl*> (task);
- SemanticState::ConsumerImpl* ci = const_cast<SemanticState::ConsumerImpl*>(cci);
- uint16_t channel = ci->getParent().getSession().getChannel();
- ClusterConnectionProxy(shadowConnection).outputTask(channel, ci->getTag());
- QPID_LOG(debug, *this << " updating output task " << ci->getTag()
- << " channel=" << channel);
-}
-
-void UpdateClient::updateConnection(const boost::intrusive_ptr<Connection>& updateConnection) {
- QPID_LOG(debug, *this << " updating connection " << *updateConnection);
- assert(updateConnection->getBrokerConnection());
- broker::Connection& bc = *updateConnection->getBrokerConnection();
-
- // Send the management ID first on the main connection.
- std::string mgmtId = updateConnection->getBrokerConnection()->getMgmtId();
- ClusterConnectionProxy(session).shadowPrepare(mgmtId);
- // Make sure its received before opening shadow connection
- session.sync();
-
- // Open shadow connection and update it.
- shadowConnection = catchUpConnection();
-
- connectionSettings.maxFrameSize = bc.getFrameMax();
- shadowConnection.open(updateeUrl, connectionSettings);
- ClusterConnectionProxy(shadowConnection).shadowSetUser(bc.getUserId());
-
- bc.eachSessionHandler(boost::bind(&UpdateClient::updateSession, this, _1));
- // Safe to use decoder here because we are stalled for update.
- std::pair<const char*, size_t> fragment = decoder.get(updateConnection->getId()).getFragment();
- bc.getOutputTasks().eachOutput(
- boost::bind(&UpdateClient::updateOutputTask, this, _1));
- ClusterConnectionProxy(shadowConnection).shadowReady(
- updateConnection->getId().getMember(),
- updateConnection->getId().getNumber(),
- bc.getMgmtId(),
- bc.getUserId(),
- string(fragment.first, fragment.second),
- updateConnection->getOutput().getSendMax()
- );
- shadowConnection.close();
- QPID_LOG(debug, *this << " updated connection " << *updateConnection);
-}
-
-void UpdateClient::updateSession(broker::SessionHandler& sh) {
- broker::SessionState* ss = sh.getSession();
- if (!ss) return; // no session.
-
- QPID_LOG(debug, *this << " updating session " << ss->getId());
-
- // Create a client session to update session state.
- boost::shared_ptr<client::ConnectionImpl> cimpl = client::ConnectionAccess::getImpl(shadowConnection);
- boost::shared_ptr<client::SessionImpl> simpl = cimpl->newSession(ss->getId().getName(), ss->getTimeout(), sh.getChannel());
- simpl->disableAutoDetach();
- client::SessionBase_0_10Access(shadowSession).set(simpl);
- AMQP_AllProxy::ClusterConnection proxy(simpl->out);
-
- // Re-create session state on remote connection.
-
- QPID_LOG(debug, *this << " updating exclusive queues.");
- ss->getSessionAdapter().eachExclusiveQueue(boost::bind(&UpdateClient::updateExclusiveQueue, this, _1));
-
- QPID_LOG(debug, *this << " updating consumers.");
- ss->getSemanticState().eachConsumer(
- boost::bind(&UpdateClient::updateConsumer, this, _1));
-
- QPID_LOG(debug, *this << " updating unacknowledged messages.");
- broker::DeliveryRecords& drs = ss->getSemanticState().getUnacked();
- std::for_each(drs.begin(), drs.end(),
- boost::bind(&UpdateClient::updateUnacked, this, _1, shadowSession));
-
- updateTransactionState(ss->getSemanticState());
-
- // Adjust command counter for message in progress, will be sent after state update.
- boost::intrusive_ptr<Message> inProgress = ss->getMessageInProgress();
- SequenceNumber received = ss->receiverGetReceived().command;
- if (inProgress)
- --received;
-
- // Sync the session to ensure all responses from broker have been processed.
- shadowSession.sync();
-
- // Reset command-sequence state.
- proxy.sessionState(
- ss->senderGetReplayPoint().command,
- ss->senderGetCommandPoint().command,
- ss->senderGetIncomplete(),
- std::max(received, ss->receiverGetExpected().command),
- received,
- ss->receiverGetUnknownComplete(),
- ss->receiverGetIncomplete(),
- ss->getSemanticState().getDtxSelected()
- );
-
- // Send frames for partial message in progress.
- if (inProgress) {
- inProgress->getFrames().map(simpl->out);
- }
- QPID_LOG(debug, *this << " updated session " << sh.getSession()->getId());
-}
-
-void UpdateClient::updateConsumer(
- const broker::SemanticState::ConsumerImpl::shared_ptr& ci)
-{
- QPID_LOG(debug, *this << " updating consumer " << ci->getTag() << " on "
- << shadowSession.getId());
-
- using namespace message;
- shadowSession.messageSubscribe(
- arg::queue = ci->getQueue()->getName(),
- arg::destination = ci->getTag(),
- arg::acceptMode = ci->isAckExpected() ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE,
- arg::acquireMode = ci->isAcquire() ? ACQUIRE_MODE_PRE_ACQUIRED : ACQUIRE_MODE_NOT_ACQUIRED,
- arg::exclusive = ci->isExclusive(),
- arg::resumeId = ci->getResumeId(),
- arg::resumeTtl = ci->getResumeTtl(),
- arg::arguments = ci->getArguments()
- );
- shadowSession.messageSetFlowMode(ci->getTag(), ci->getCredit().isWindowMode() ? FLOW_MODE_WINDOW : FLOW_MODE_CREDIT);
- shadowSession.messageFlow(ci->getTag(), CREDIT_UNIT_MESSAGE, ci->getCredit().allocated().messages);
- shadowSession.messageFlow(ci->getTag(), CREDIT_UNIT_BYTE, ci->getCredit().allocated().bytes);
- ClusterConnectionProxy(shadowSession).consumerState(
- ci->getTag(),
- ci->isBlocked(),
- ci->isNotifyEnabled(),
- ci->getPosition(),
- ci->getCredit().used().messages,
- ci->getCredit().used().bytes,
- ci->getDeliveryCount()
- );
- consumerNumbering.add(ci.get());
-
- QPID_LOG(debug, *this << " updated consumer " << ci->getTag()
- << " on " << shadowSession.getId());
-}
-
-void UpdateClient::updateUnacked(const broker::DeliveryRecord& dr,
- client::AsyncSession& updateSession)
-{
- if (!dr.isEnded() && dr.isAcquired()) {
- assert(dr.getMessage().payload);
- // If the message is acquired then it is no longer on the
- // updatees queue, put it on the update queue for updatee to pick up.
- //
- MessageUpdater(UPDATE, updateSession, expiry).updateQueuedMessage(dr.getMessage());
- }
- ClusterConnectionProxy(updateSession).deliveryRecord(
- dr.getQueue()->getName(),
- dr.getMessage().position,
- dr.getTag(),
- dr.getId(),
- dr.isAcquired(),
- dr.isAccepted(),
- dr.isCancelled(),
- dr.isComplete(),
- dr.isEnded(),
- dr.isWindowing(),
- dr.getQueue()->isEnqueued(dr.getMessage()),
- dr.getCredit()
- );
-}
-
-class TxOpUpdater : public broker::TxOpConstVisitor, public MessageUpdater {
- public:
- TxOpUpdater(UpdateClient& dc, client::AsyncSession s, ExpiryPolicy& expiry)
- : MessageUpdater(UpdateClient::UPDATE, s, expiry), parent(dc), session(s), proxy(s) {}
-
- void operator()(const broker::DtxAck& ack) {
- std::for_each(ack.getPending().begin(), ack.getPending().end(),
- boost::bind(&UpdateClient::updateUnacked, &parent, _1, session));
- proxy.dtxAck();
- }
-
- void operator()(const broker::RecoveredDequeue& rdeq) {
- updateMessage(rdeq.getMessage());
- proxy.txEnqueue(rdeq.getQueue()->getName());
- }
-
- void operator()(const broker::RecoveredEnqueue& renq) {
- updateMessage(renq.getMessage());
- proxy.txEnqueue(renq.getQueue()->getName());
- }
-
- void operator()(const broker::TxAccept& txAccept) {
- proxy.txAccept(txAccept.getAcked());
- }
-
- typedef std::list<Queue::shared_ptr> QueueList;
-
- void copy(const QueueList& l, Array& a) {
- for (QueueList::const_iterator i = l.begin(); i!=l.end(); ++i)
- a.push_back(Array::ValuePtr(new Str8Value((*i)->getName())));
- }
-
- void operator()(const broker::TxPublish& txPub) {
- updateMessage(txPub.getMessage());
- assert(txPub.getQueues().empty() || txPub.getPrepared().empty());
- Array qarray(TYPE_CODE_STR8);
- copy(txPub.getQueues().empty() ? txPub.getPrepared() : txPub.getQueues(), qarray);
- proxy.txPublish(qarray, txPub.delivered);
- }
-
- private:
- UpdateClient& parent;
- client::AsyncSession session;
- ClusterConnectionProxy proxy;
-};
-
-void UpdateClient::updateBufferRef(const broker::DtxBuffer::shared_ptr& dtx,bool suspended)
-{
- ClusterConnectionProxy proxy(shadowSession);
- broker::DtxWorkRecord* record =
- updaterBroker.getDtxManager().getWork(dtx->getXid());
- proxy.dtxBufferRef(dtx->getXid(), record->indexOf(dtx), suspended);
-
-}
-
-void UpdateClient::updateTransactionState(broker::SemanticState& s) {
- ClusterConnectionProxy proxy(shadowSession);
- proxy.accumulatedAck(s.getAccumulatedAck());
- broker::TxBuffer::shared_ptr tx = s.getTxBuffer();
- broker::DtxBuffer::shared_ptr dtx = s.getDtxBuffer();
- if (dtx) {
- updateBufferRef(dtx, false); // Current transaction.
- } else if (tx) {
- proxy.txStart();
- TxOpUpdater updater(*this, shadowSession, expiry);
- tx->accept(updater);
- proxy.txEnd();
- }
- for (SemanticState::DtxBufferMap::iterator i = s.getSuspendedXids().begin();
- i != s.getSuspendedXids().end();
- ++i)
- {
- updateBufferRef(i->second, true);
- }
-}
-
-void UpdateClient::updateDtxBuffer(const broker::DtxBuffer::shared_ptr& dtx) {
- ClusterConnectionProxy proxy(session);
- proxy.dtxStart(
- dtx->getXid(), dtx->isEnded(), dtx->isSuspended(), dtx->isFailed(), dtx->isExpired());
- TxOpUpdater updater(*this, session, expiry);
- dtx->accept(updater);
- proxy.dtxEnd();
-}
-
-void UpdateClient::updateQueueListeners(const boost::shared_ptr<broker::Queue>& queue) {
- queue->getListeners().eachListener(
- boost::bind(&UpdateClient::updateQueueListener, this, queue->getName(), _1));
-}
-
-void UpdateClient::updateQueueListener(std::string& q,
- const boost::shared_ptr<broker::Consumer>& c)
-{
- SemanticState::ConsumerImpl* ci = dynamic_cast<SemanticState::ConsumerImpl*>(c.get());
- size_t n = consumerNumbering[ci];
- if (n >= consumerNumbering.size())
- throw Exception(QPID_MSG("Unexpected listener on queue " << q));
- ClusterConnectionProxy(session).addQueueListener(q, n);
-}
-
-void UpdateClient::updateLinks() {
- broker::LinkRegistry& links = updaterBroker.getLinks();
- links.eachLink(boost::bind(&UpdateClient::updateLink, this, _1));
- links.eachBridge(boost::bind(&UpdateClient::updateBridge, this, _1));
-}
-
-void UpdateClient::updateLink(const boost::shared_ptr<broker::Link>& link) {
- QPID_LOG(debug, *this << " updating link "
- << link->getHost() << ":" << link->getPort());
- ClusterConnectionProxy(session).config(encode(*link)); // push the configuration
- // now push the current state
- framing::FieldTable state;
- link->getState(state);
- std::ostringstream os;
- os << qpid::Address(link->getTransport(), link->getHost(), link->getPort());
- ClusterConnectionProxy(session).internalState(std::string("link"),
- os.str(),
- state);
-}
-
-void UpdateClient::updateBridge(const boost::shared_ptr<broker::Bridge>& bridge) {
- QPID_LOG(debug, *this << " updating bridge " << bridge->getName());
- ClusterConnectionProxy(session).config(encode(*bridge));
-}
-
-void UpdateClient::updateQueueObservers(const boost::shared_ptr<broker::Queue>& q)
-{
- q->eachObserver(boost::bind(&UpdateClient::updateObserver, this, q, _1));
-}
-
-void UpdateClient::updateObserver(const boost::shared_ptr<broker::Queue>& q,
- boost::shared_ptr<broker::QueueObserver> o)
-{
- qpid::framing::FieldTable state;
- broker::StatefulQueueObserver *so = dynamic_cast<broker::StatefulQueueObserver *>(o.get());
- if (so) {
- so->getState( state );
- std::string id(so->getId());
- QPID_LOG(debug, *this << " updating queue " << q->getName() << "'s observer " << id);
- ClusterConnectionProxy(session).queueObserverState( q->getName(), id, state );
- }
-}
-
-void UpdateClient::updateDtxManager() {
- broker::DtxManager& dtm = updaterBroker.getDtxManager();
- dtm.each(boost::bind(&UpdateClient::updateDtxWorkRecord, this, _1));
-}
-
-void UpdateClient::updateDtxWorkRecord(const broker::DtxWorkRecord& r) {
- QPID_LOG(debug, *this << " updating DTX transaction: " << r.getXid());
- for (size_t i = 0; i < r.size(); ++i)
- updateDtxBuffer(r[i]);
- ClusterConnectionProxy(session).dtxWorkRecord(
- r.getXid(), r.isPrepared(), r.getTimeout());
-}
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/UpdateClient.h b/cpp/src/qpid/cluster/UpdateClient.h
deleted file mode 100644
index 481ee357c7..0000000000
--- a/cpp/src/qpid/cluster/UpdateClient.h
+++ /dev/null
@@ -1,142 +0,0 @@
-#ifndef QPID_CLUSTER_UPDATECLIENT_H
-#define QPID_CLUSTER_UPDATECLIENT_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/ClusterMap.h"
-#include "qpid/cluster/Numbering.h"
-#include "qpid/client/Connection.h"
-#include "qpid/client/ConnectionSettings.h"
-#include "qpid/client/AsyncSession.h"
-#include "qpid/broker/SemanticState.h"
-#include "qpid/sys/Runnable.h"
-#include <boost/shared_ptr.hpp>
-#include <iosfwd>
-
-namespace qpid {
-
-struct Url;
-
-namespace broker {
-
-class Broker;
-class Queue;
-class Exchange;
-class QueueBindings;
-struct QueueBinding;
-struct QueuedMessage;
-class SessionHandler;
-class DeliveryRecord;
-class SessionState;
-class SemanticState;
-class Decoder;
-class Link;
-class Bridge;
-class QueueObserver;
-class DtxBuffer;
-} // namespace broker
-
-namespace cluster {
-
-class Cluster;
-class Connection;
-class ClusterMap;
-class Decoder;
-class ExpiryPolicy;
-
-/**
- * A client that updates the contents of a local broker to a remote one using AMQP.
- */
-class UpdateClient : public sys::Runnable {
- public:
- static const std::string UPDATE; // Name for special update queue and exchange.
- static const std::string X_QPID_EXPIRATION; // Update message expiration
- // Flag to remove props/headers that were added by the UpdateClient
- static const std::string X_QPID_NO_MESSAGE_PROPS;
- static const std::string X_QPID_NO_HEADERS;
-
- static client::Connection catchUpConnection();
-
- UpdateClient(const MemberId& updater, const MemberId& updatee, const Url&,
- broker::Broker& donor, const ClusterMap& map, ExpiryPolicy& expiry,
- const std::vector<boost::intrusive_ptr<Connection> >&, Decoder&,
- const boost::function<void()>& done,
- const boost::function<void(const std::exception&)>& fail,
- const client::ConnectionSettings&
- );
-
- ~UpdateClient();
- void update();
- void run(); // Will delete this when finished.
-
- void updateUnacked(const broker::DeliveryRecord&, client::AsyncSession&);
-
- private:
- void updateQueue(client::AsyncSession&, const boost::shared_ptr<broker::Queue>&);
- void updateNonExclusiveQueue(const boost::shared_ptr<broker::Queue>&);
- void updateExclusiveQueue(const boost::shared_ptr<broker::Queue>&);
- void updateExchange(const boost::shared_ptr<broker::Exchange>&);
- void updateMessage(const broker::QueuedMessage&);
- void updateMessageTo(const broker::QueuedMessage&, const std::string& queue, client::Session s);
- void updateBinding(client::AsyncSession&, const std::string& queue, const broker::QueueBinding& binding);
- void updateConnection(const boost::intrusive_ptr<Connection>& connection);
- void updateSession(broker::SessionHandler& s);
- void updateBufferRef(const broker::DtxBuffer::shared_ptr& dtx, bool suspended);
- void updateTransactionState(broker::SemanticState& s);
- void updateOutputTask(const sys::OutputTask* task);
- void updateConsumer(const broker::SemanticState::ConsumerImpl::shared_ptr&);
- void updateQueueListeners(const boost::shared_ptr<broker::Queue>&);
- void updateQueueListener(std::string& q, const boost::shared_ptr<broker::Consumer>& c);
- void updateManagementSetupState();
- void updateManagementAgent();
- void updateLinks();
- void updateLink(const boost::shared_ptr<broker::Link>&);
- void updateBridge(const boost::shared_ptr<broker::Bridge>&);
- void updateQueueObservers(const boost::shared_ptr<broker::Queue>&);
- void updateObserver(const boost::shared_ptr<broker::Queue>&, boost::shared_ptr<broker::QueueObserver>);
- void updateDtxManager();
- void updateDtxBuffer(const boost::shared_ptr<broker::DtxBuffer>& );
- void updateDtxWorkRecord(const broker::DtxWorkRecord&);
-
-
- Numbering<broker::SemanticState::ConsumerImpl*> consumerNumbering;
- MemberId updaterId;
- MemberId updateeId;
- Url updateeUrl;
- broker::Broker& updaterBroker;
- ClusterMap map;
- ExpiryPolicy& expiry;
- std::vector<boost::intrusive_ptr<Connection> > connections;
- Decoder& decoder;
- client::Connection connection, shadowConnection;
- client::AsyncSession session, shadowSession;
- boost::function<void()> done;
- boost::function<void(const std::exception& e)> failed;
- client::ConnectionSettings connectionSettings;
-
- friend std::ostream& operator<<(std::ostream&, const UpdateClient&);
-};
-
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_UPDATECLIENT_H*/
diff --git a/cpp/src/qpid/cluster/UpdateDataExchange.cpp b/cpp/src/qpid/cluster/UpdateDataExchange.cpp
deleted file mode 100644
index 31d96c67ca..0000000000
--- a/cpp/src/qpid/cluster/UpdateDataExchange.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "UpdateDataExchange.h"
-#include "Cluster.h"
-#include "qpid/amqp_0_10/Codecs.h"
-#include "qpid/broker/Deliverable.h"
-#include "qpid/broker/Message.h"
-#include "qpid/log/Statement.h"
-#include "qpid/management/ManagementAgent.h"
-#include "qpid/types/Variant.h"
-
-namespace qpid {
-namespace cluster {
-
-const std::string UpdateDataExchange::EXCHANGE_NAME("qpid.cluster-update-data");
-const std::string UpdateDataExchange::EXCHANGE_TYPE("qpid.cluster-update-data");
-const std::string UpdateDataExchange::MANAGEMENT_AGENTS_KEY("management-agents");
-const std::string UpdateDataExchange::MANAGEMENT_SCHEMAS_KEY("management-schemas");
-const std::string UpdateDataExchange::MANAGEMENT_DELETED_OBJECTS_KEY("management-deleted-objects");
-
-UpdateDataExchange::UpdateDataExchange(Cluster& cluster) :
- Exchange(EXCHANGE_NAME, &cluster)
-{}
-
-void UpdateDataExchange::route(broker::Deliverable& msg)
-{
- const std::string& routingKey = msg.getMessage().getRoutingKey();
- std::string data = msg.getMessage().getFrames().getContent();
- if (routingKey == MANAGEMENT_AGENTS_KEY) managementAgents = data;
- else if (routingKey == MANAGEMENT_SCHEMAS_KEY) managementSchemas = data;
- else if (routingKey == MANAGEMENT_DELETED_OBJECTS_KEY) managementDeletedObjects = data;
- else throw Exception(
- QPID_MSG("Cluster update-data exchange received unknown routing-key: "
- << routingKey));
-}
-
-void UpdateDataExchange::updateManagementAgent(management::ManagementAgent* agent) {
- if (!agent) return;
-
- framing::Buffer buf1(const_cast<char*>(managementAgents.data()), managementAgents.size());
- agent->importAgents(buf1);
-
- framing::Buffer buf2(const_cast<char*>(managementSchemas.data()), managementSchemas.size());
- agent->importSchemas(buf2);
-
- using amqp_0_10::ListCodec;
- using types::Variant;
- Variant::List encoded;
- ListCodec::decode(managementDeletedObjects, encoded);
- management::ManagementAgent::DeletedObjectList objects;
- for (Variant::List::iterator i = encoded.begin(); i != encoded.end(); ++i) {
- objects.push_back(management::ManagementAgent::DeletedObject::shared_ptr(
- new management::ManagementAgent::DeletedObject(*i)));
- }
- agent->importDeletedObjects(objects);
-}
-
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/UpdateDataExchange.h b/cpp/src/qpid/cluster/UpdateDataExchange.h
deleted file mode 100644
index f79430f111..0000000000
--- a/cpp/src/qpid/cluster/UpdateDataExchange.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef QPID_CLUSTER_UPDATEDATAEXCHANGE_H
-#define QPID_CLUSTER_UPDATEDATAEXCHANGE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/broker/Exchange.h"
-#include "types.h"
-#include <iosfwd>
-
-namespace qpid {
-
-namespace management {
-class ManagementAgent;
-}
-
-namespace cluster {
-class Cluster;
-
-/**
- * An exchange used to send data that is to large for a control
- * during update. The routing key indicates the type of data.
- */
-class UpdateDataExchange : public broker::Exchange
-{
- public:
- static const std::string EXCHANGE_NAME;
- static const std::string EXCHANGE_TYPE;
- static const std::string MANAGEMENT_AGENTS_KEY;
- static const std::string MANAGEMENT_SCHEMAS_KEY;
- static const std::string MANAGEMENT_DELETED_OBJECTS_KEY;
-
- UpdateDataExchange(Cluster& parent);
-
- void route(broker::Deliverable& msg);
-
- // Not implemented
- std::string getType() const { return EXCHANGE_TYPE; }
-
- bool bind(boost::shared_ptr<broker::Queue>,
- const std::string&,
- const qpid::framing::FieldTable*)
- { return false; }
-
- bool unbind(boost::shared_ptr<broker::Queue>,
- const std::string&,
- const qpid::framing::FieldTable*)
- { return false; }
-
- bool isBound(boost::shared_ptr<broker::Queue>,
- const std::string*,
- const qpid::framing::FieldTable*)
- { return false; }
-
- void updateManagementAgent(management::ManagementAgent* agent);
-
- private:
- std::string managementAgents;
- std::string managementSchemas;
- std::string managementDeletedObjects;
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_UPDATEDATAEXCHANGE_H*/
diff --git a/cpp/src/qpid/cluster/UpdateExchange.cpp b/cpp/src/qpid/cluster/UpdateExchange.cpp
deleted file mode 100644
index cb1376004e..0000000000
--- a/cpp/src/qpid/cluster/UpdateExchange.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/broker/Message.h"
-#include "UpdateExchange.h"
-
-namespace qpid {
-namespace cluster {
-
-using framing::MessageTransferBody;
-using framing::DeliveryProperties;
-using framing::MessageProperties;
-using framing::FieldTable;
-
-UpdateExchange::UpdateExchange(management::Manageable* parent)
- : broker::Exchange(UpdateClient::UPDATE, parent),
- broker::FanOutExchange(UpdateClient::UPDATE, parent) {}
-
-
-void UpdateExchange::setProperties(const boost::intrusive_ptr<broker::Message>& msg) {
- // Copy exchange name to destination property.
- MessageTransferBody* transfer = msg->getMethod<MessageTransferBody>();
- assert(transfer);
- const DeliveryProperties* props = msg->getProperties<DeliveryProperties>();
- assert(props);
- if (props->hasExchange())
- transfer->setDestination(props->getExchange());
- else
- transfer->clearDestinationFlag();
-
- // Copy expiration from x-property if present.
- if (msg->hasProperties<MessageProperties>()) {
- const MessageProperties* mprops = msg->getProperties<MessageProperties>();
- if (mprops->hasApplicationHeaders()) {
- const FieldTable& headers = mprops->getApplicationHeaders();
- if (headers.isSet(UpdateClient::X_QPID_EXPIRATION)) {
- msg->setExpiration(
- sys::AbsTime(sys::EPOCH, headers.getAsInt64(UpdateClient::X_QPID_EXPIRATION)));
- msg->removeCustomProperty(UpdateClient::X_QPID_EXPIRATION);
- // Erase props/headers that were added by the UpdateClient
- if (headers.isSet(UpdateClient::X_QPID_NO_MESSAGE_PROPS))
- msg->eraseProperties<MessageProperties>();
- else if (headers.isSet(UpdateClient::X_QPID_NO_HEADERS))
- msg->clearApplicationHeadersFlag();
- }
- }
- }
-}
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/UpdateExchange.h b/cpp/src/qpid/cluster/UpdateExchange.h
deleted file mode 100644
index 9d7d9ee5fc..0000000000
--- a/cpp/src/qpid/cluster/UpdateExchange.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef QPID_CLUSTER_UPDATEEXCHANGE_H
-#define QPID_CLUSTER_UPDATEEXCHANGE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/cluster/UpdateClient.h"
-#include "qpid/broker/FanOutExchange.h"
-
-
-namespace qpid {
-namespace cluster {
-
-/**
- * A keyless exchange (like fanout exchange) that does not modify
- * delivery-properties.exchange but copies it to the MessageTransfer.
- */
-class UpdateExchange : public broker::FanOutExchange
-{
- public:
- UpdateExchange(management::Manageable* parent);
- void setProperties(const boost::intrusive_ptr<broker::Message>&);
-};
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_UPDATEEXCHANGE_H*/
diff --git a/cpp/src/qpid/cluster/UpdateReceiver.h b/cpp/src/qpid/cluster/UpdateReceiver.h
deleted file mode 100644
index 81ee3a5ffe..0000000000
--- a/cpp/src/qpid/cluster/UpdateReceiver.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef QPID_CLUSTER_UPDATESTATE_H
-#define QPID_CLUSTER_UPDATESTATE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "Numbering.h"
-#include "qpid/broker/SemanticState.h"
-
-namespace qpid {
-namespace cluster {
-
-/**
- * Cluster-wide state used when receiving an update.
- */
-class UpdateReceiver {
- public:
- /** Numbering used to identify Queue listeners as consumers */
- typedef Numbering<boost::shared_ptr<broker::SemanticState::ConsumerImpl> > ConsumerNumbering;
- ConsumerNumbering consumerNumbering;
-
- /** Management-id for the next shadow connection */
- std::string nextShadowMgmtId;
-
- /** Record the position of a DtxBuffer in the DtxManager (xid + index)
- * and the association with a session, either suspended or current.
- */
- struct DtxBufferRef {
- std::string xid;
- uint32_t index; // Index in WorkRecord in DtxManager
- bool suspended; // Is this a suspended or current transaction?
- broker::SemanticState* semanticState; // Associated session
- DtxBufferRef(const std::string& x, uint32_t i, bool s, broker::SemanticState* ss)
- : xid(x), index(i), suspended(s), semanticState(ss) {}
- };
- typedef std::vector<DtxBufferRef> DtxBuffers;
- DtxBuffers dtxBuffers;
-};
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_UPDATESTATE_H*/
diff --git a/cpp/src/qpid/cluster/WatchDogPlugin.cpp b/cpp/src/qpid/cluster/WatchDogPlugin.cpp
deleted file mode 100644
index f919041107..0000000000
--- a/cpp/src/qpid/cluster/WatchDogPlugin.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/**@file
-
- The watchdog plug-in will kill the qpidd broker process if it
- becomes stuck for longer than a configured interval.
-
- If the watchdog plugin is loaded and the --watchdog-interval=N
- option is set then the broker starts a watchdog process and signals
- it every N/2 seconds.
-
- The watchdog process runs a very simple program that starts a timer
- for N seconds, and resets the timer to N seconds whenever it is
- signalled by the broker. If the timer ever reaches 0 the watchdog
- kills the broker process (with kill -9) and exits.
-
- This is useful in a cluster setting because in some insttances
- (e.g. while resolving an error) it's possible for a stuck process
- to hang other cluster members that are waiting for it to send a
- message. Using the watchdog, the stuck process is terminated and
- removed fromt the cluster allowing other members to continue and
- clients of the stuck process to fail over to other members.
-
-*/
-#include "config.h"
-#include "qpid/Plugin.h"
-#include "qpid/Options.h"
-#include "qpid/log/Statement.h"
-#include "qpid/broker/Broker.h"
-#include "qpid/sys/Timer.h"
-#include "qpid/sys/Fork.h"
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-
-namespace qpid {
-namespace cluster {
-
-using broker::Broker;
-
-struct Settings {
- Settings() : interval(0), watchdogExec(QPID_LIBEXEC_DIR "/qpidd_watchdog") {}
- int interval;
- std::string watchdogExec;
-};
-
-struct WatchDogOptions : public qpid::Options {
- Settings& settings;
-
- WatchDogOptions(Settings& s) : settings(s) {
- addOptions()
- ("watchdog-interval", optValue(settings.interval, "N"),
- "broker is automatically killed if it is hung for more than \
- N seconds. 0 disables watchdog.")
- ("watchdog-exec", optValue(settings.watchdogExec, ""),
- "Path to the qpidd_watchdog executable.");
- }
-};
-
-struct WatchDogTask : public sys::TimerTask {
- int pid;
- sys::Timer& timer;
- int interval;
-
- WatchDogTask(int pid_, sys::Timer& t, int _interval)
- : TimerTask(_interval*sys::TIME_SEC/2,"WatchDog"), pid(pid_), timer(t), interval(_interval) {}
-
- void fire() {
- timer.add (new WatchDogTask(pid, timer, interval));
- QPID_LOG(debug, "Sending keepalive signal to watchdog");
- ::kill(pid, SIGUSR1);
- }
-};
-
-struct WatchDogPlugin : public qpid::Plugin, public qpid::sys::Fork {
- Settings settings;
- WatchDogOptions options;
- Broker* broker;
- int watchdogPid;
-
- WatchDogPlugin() : options(settings), broker(0), watchdogPid(0) {}
-
- ~WatchDogPlugin() {
- if (watchdogPid) ::kill(watchdogPid, SIGTERM);
- ::waitpid(watchdogPid, 0, 0);
- }
-
- Options* getOptions() { return &options; }
-
- void earlyInitialize(qpid::Plugin::Target& target) {
- broker = dynamic_cast<Broker*>(&target);
- if (broker && settings.interval) {
- QPID_LOG(notice, "Starting watchdog process with interval of " <<
- settings.interval << " seconds");
- fork();
- }
- }
-
- void initialize(Target&) {}
-
- protected:
-
- void child() { // Child of fork
- std::string interval = boost::lexical_cast<std::string>(settings.interval);
- const char* watchdogExec = settings.watchdogExec.c_str();
- ::execl(watchdogExec, watchdogExec, interval.c_str(), NULL);
- QPID_LOG(critical, "Failed to exec watchdog program " << watchdogExec);
- ::kill(::getppid(), SIGKILL);
- exit(1);
- }
-
- void parent(int pid) { // Parent of fork
- watchdogPid = pid;
- broker->getTimer().add(
- new WatchDogTask(watchdogPid, broker->getTimer(), settings.interval));
- // TODO aconway 2009-08-10: to be extra safe, we could monitor
- // the watchdog child and re-start it if it exits.
- }
-};
-
-static WatchDogPlugin instance; // Static initialization.
-
-}} // namespace qpid::cluster
diff --git a/cpp/src/qpid/cluster/management-schema.xml b/cpp/src/qpid/cluster/management-schema.xml
deleted file mode 100644
index a6292e9113..0000000000
--- a/cpp/src/qpid/cluster/management-schema.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<schema package="org.apache.qpid.cluster">
-
- <!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
- -->
-
- <!-- Type information:
-
-Numeric types with "_wm" suffix are watermarked numbers. These are compound
-values containing a current value, and a low and high water mark for the reporting
-interval. The low and high water marks are set to the current value at the
-beginning of each interval and track the minimum and maximum values of the statistic
-over the interval respectively.
-
-Access rights for configuration elements:
-
-RO => Read Only
-RC => Read/Create, can be set at create time only, read-only thereafter
-RW => Read/Write
-
-If access rights are omitted for a property, they are assumed to be RO.
-
- -->
-
- <class name="Cluster">
- <property name="brokerRef" type="objId" references="Broker" access="RC" index="y" parentRef="y"/>
- <property name="clusterName" type="sstr" access="RC" desc="Name of cluster this server is a member of"/>
- <property name="clusterID" type="sstr" access="RO" desc="Globally unique ID (UUID) for this cluster instance"/>
- <property name="memberID" type="sstr" access="RO" desc="ID of this member of the cluster"/>
- <property name="publishedURL" type="sstr" access="RC" desc="URL this node advertizes itself as"/>
- <property name="clusterSize" type="uint16" access="RO" desc="Number of brokers currently in the cluster"/>
- <property name="status" type="sstr" access="RO" desc="Cluster node status (STALLED,ACTIVE,JOINING)"/>
- <property name="members" type="lstr" access="RO" desc="List of member URLs delimited by ';'"/>
- <property name="memberIDs" type="lstr" access="RO" desc="List of member IDs delimited by ';'"/>
-
- <method name="stopClusterNode">
- <arg name="brokerId" type="sstr" dir="I"/>
- </method>
- <method name="stopFullCluster"/>
-
- </class>
-
-
-
-</schema>
-
diff --git a/cpp/src/qpid/cluster/qpidd_watchdog.cpp b/cpp/src/qpid/cluster/qpidd_watchdog.cpp
deleted file mode 100644
index 51c5ed4b3f..0000000000
--- a/cpp/src/qpid/cluster/qpidd_watchdog.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/** @file helper executable for WatchDogPlugin.cpp */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <signal.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <limits.h>
-
-long timeout;
-
-void killParent(int) {
- ::kill(getppid(), SIGKILL);
- ::fprintf(stderr, "Watchdog killed unresponsive broker, pid=%d\n", ::getppid());
- ::exit(1);
-}
-
-void resetTimer(int) {
- struct ::itimerval itval = { { 0, 0 }, { timeout, 0 } };
- if (::setitimer(ITIMER_REAL, &itval, 0) !=0) {
- ::perror("Watchdog failed to set timer");
- killParent(0);
- ::exit(1);
- }
-}
-
-/** Simple watchdog program: kill parent process if timeout
- * expires without a SIGUSR1.
- * Will be killed with SIGHUP when parent shuts down.
- * Args: timeout in seconds.
- */
-int main(int argc, char** argv) {
- if(argc != 2 || (timeout = atoi(argv[1])) == 0) {
- ::fprintf(stderr, "Usage: %s <timeout_seconds>\n", argv[0]);
- ::exit(1);
- }
- ::signal(SIGUSR1, resetTimer);
- ::signal(SIGALRM, killParent);
- resetTimer(0);
- while (true) { sleep(INT_MAX); }
-}
diff --git a/cpp/src/qpid/cluster/types.h b/cpp/src/qpid/cluster/types.h
deleted file mode 100644
index c8ffb0b804..0000000000
--- a/cpp/src/qpid/cluster/types.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef QPID_CLUSTER_TYPES_H
-#define QPID_CLUSTER_TYPES_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "config.h"
-#include "qpid/Url.h"
-#include "qpid/RefCounted.h"
-#include "qpid/sys/IntegerTypes.h"
-#include <boost/intrusive_ptr.hpp>
-#include <utility>
-#include <iosfwd>
-#include <string>
-
-extern "C" {
-#if defined (HAVE_OPENAIS_CPG_H)
-# include <openais/cpg.h>
-
-// Provide translations back to the deprecated definitions in openais
-typedef cpg_error_t cs_error_t;
-#define CS_DISPATCH_ONE CPG_DISPATCH_ONE
-#define CS_DISPATCH_ALL CPG_DISPATCH_ALL
-#define CS_DISPATCH_BLOCKING CPG_DISPATCH_BLOCKING
-#define CS_FLOW_CONTROL_DISABLED CPG_FLOW_CONTROL_DISABLED
-#define CS_FLOW_CONTROL_ENABLED CPG_FLOW_CONTROL_ENABLED
-#define CS_OK CPG_OK
-#define CS_ERR_LIBRARY CPG_ERR_LIBRARY
-#define CS_ERR_TIMEOUT CPG_ERR_TIMEOUT
-#define CS_ERR_TRY_AGAIN CPG_ERR_TRY_AGAIN
-#define CS_ERR_INVALID_PARAM CPG_ERR_INVALID_PARAM
-#define CS_ERR_NO_MEMORY CPG_ERR_NO_MEMORY
-#define CS_ERR_BAD_HANDLE CPG_ERR_BAD_HANDLE
-#define CS_ERR_BUSY CPG_ERR_BUSY
-#define CS_ERR_ACCESS CPG_ERR_ACCESS
-#define CS_ERR_NOT_EXIST CPG_ERR_NOT_EXIST
-#define CS_ERR_EXIST CPG_ERR_EXIST
-#define CS_ERR_NOT_SUPPORTED CPG_ERR_NOT_SUPPORTED
-#define CS_ERR_SECURITY CPG_ERR_SECURITY
-#define CS_ERR_TOO_MANY_GROUPS CPG_ERR_TOO_MANY_GROUPS
-
-#elif defined (HAVE_COROSYNC_CPG_H)
-# include <corosync/cpg.h>
-#else
-# error "No cpg.h header file available"
-#endif
-}
-
-namespace qpid {
-namespace cluster {
-
-class Connection;
-typedef boost::intrusive_ptr<Connection> ConnectionPtr;
-
-/** Types of cluster event. */
-enum EventType { DATA, CONTROL };
-
-/** first=node-id, second=pid */
-struct MemberId : std::pair<uint32_t, uint32_t> {
- MemberId(uint64_t n=0) : std::pair<uint32_t,uint32_t>( n >> 32, n & 0xffffffff) {}
- MemberId(uint32_t node, uint32_t pid) : std::pair<uint32_t,uint32_t>(node, pid) {}
- MemberId(const cpg_address& caddr) : std::pair<uint32_t,uint32_t>(caddr.nodeid, caddr.pid) {}
- MemberId(const std::string&); // Decode from string.
- uint32_t getNode() const { return first; }
- uint32_t getPid() const { return second; }
- operator uint64_t() const { return (uint64_t(first)<<32ull) + second; }
-
- // MemberId as byte string, network byte order. Not human readable.
- std::string str() const;
-};
-
-inline bool operator==(const cpg_address& caddr, const MemberId& id) { return id == MemberId(caddr); }
-
-std::ostream& operator<<(std::ostream&, const MemberId&);
-
-struct ConnectionId : public std::pair<MemberId, uint64_t> {
- ConnectionId(const MemberId& m=MemberId(), uint64_t c=0) : std::pair<MemberId, uint64_t> (m,c) {}
- ConnectionId(uint64_t m, uint64_t c) : std::pair<MemberId, uint64_t>(MemberId(m), c) {}
- MemberId getMember() const { return first; }
- uint64_t getNumber() const { return second; }
-};
-
-std::ostream& operator<<(std::ostream&, const ConnectionId&);
-
-std::ostream& operator<<(std::ostream&, EventType);
-
-}} // namespace qpid::cluster
-
-#endif /*!QPID_CLUSTER_TYPES_H*/
diff --git a/cpp/src/qpid/ha/Backup.cpp b/cpp/src/qpid/ha/Backup.cpp
index bac6fd23c8..6852a58b0c 100644
--- a/cpp/src/qpid/ha/Backup.cpp
+++ b/cpp/src/qpid/ha/Backup.cpp
@@ -35,6 +35,7 @@
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/sys/SystemInfo.h"
#include "qpid/types/Variant.h"
+#include "qpid/log/Statement.h"
namespace qpid {
namespace ha {
@@ -51,35 +52,15 @@ Backup::Backup(HaBroker& hb, const Settings& s) :
if (!s.brokerUrl.empty()) initialize(Url(s.brokerUrl));
}
-bool Backup::isSelf(const Address& a) const {
- return sys::SystemInfo::isLocalHost(a.host) &&
- a.port == haBroker.getBroker().getPort(a.protocol);
-}
-
-// Remove my own address from the URL if possible.
-// This isn't 100% reliable given the many ways to specify a host,
-// but should work in most cases. We have additional measures to prevent
-// self-connection in ConnectionObserver
-Url Backup::removeSelf(const Url& brokers) const {
- Url url;
- for (Url::const_iterator i = brokers.begin(); i != brokers.end(); ++i)
- if (!isSelf(*i)) url.push_back(*i);
- if (url.empty())
- throw Url::Invalid(logPrefix+"Failover URL is empty");
- QPID_LOG(debug, logPrefix << "Failover URL (excluding self): " << url);
- return url;
-}
-
void Backup::initialize(const Url& brokers) {
if (brokers.empty()) throw Url::Invalid("HA broker URL is empty");
QPID_LOG(info, logPrefix << "Connecting to cluster, broker URL: " << brokers);
- Url url = removeSelf(brokers);
- string protocol = url[0].protocol.empty() ? "tcp" : url[0].protocol;
+ string protocol = brokers[0].protocol.empty() ? "tcp" : brokers[0].protocol;
types::Uuid uuid(true);
// Declare the link
std::pair<Link::shared_ptr, bool> result = broker.getLinks().declare(
broker::QPID_NAME_PREFIX + string("ha.link.") + uuid.str(),
- url[0].host, url[0].port, protocol,
+ brokers[0].host, brokers[0].port, protocol,
false, // durable
settings.mechanism, settings.username, settings.password,
false); // no amq.failover - don't want to use client URL.
@@ -90,7 +71,7 @@ void Backup::initialize(const Url& brokers) {
replicator->initialize();
broker.getExchanges().registerExchange(replicator);
}
- link->setUrl(url); // Outside the lock, once set link doesn't change.
+ link->setUrl(brokers); // Outside the lock, once set link doesn't change.
}
Backup::~Backup() {
@@ -107,10 +88,8 @@ void Backup::setBrokerUrl(const Url& url) {
sys::Mutex::ScopedLock l(lock);
linkSet = link;
}
- if (linkSet) {
- QPID_LOG(info, logPrefix << "Broker URL set to: " << url);
- link->setUrl(removeSelf(url)); // Outside lock, once set link doesn't change
- }
+ if (linkSet)
+ link->setUrl(url); // Outside lock, once set link doesn't change
else
initialize(url); // Deferred initialization
}
diff --git a/cpp/src/qpid/ha/Backup.h b/cpp/src/qpid/ha/Backup.h
index 1233a473ec..4f2d5babde 100644
--- a/cpp/src/qpid/ha/Backup.h
+++ b/cpp/src/qpid/ha/Backup.h
@@ -53,8 +53,6 @@ class Backup
void setStatus(BrokerStatus);
private:
- bool isSelf(const Address& a) const;
- Url removeSelf(const Url&) const;
void initialize(const Url&);
std::string logPrefix;
diff --git a/cpp/src/qpid/ha/BackupConnectionExcluder.h b/cpp/src/qpid/ha/BackupConnectionExcluder.h
index ef537ab90a..5a67cde922 100644
--- a/cpp/src/qpid/ha/BackupConnectionExcluder.h
+++ b/cpp/src/qpid/ha/BackupConnectionExcluder.h
@@ -36,7 +36,7 @@ class BackupConnectionExcluder : public broker::ConnectionObserver
{
public:
void opened(broker::Connection& connection) {
- QPID_LOG(debug, "Backup broker rejected connection "+connection.getMgmtId());
+ QPID_LOG(debug, "Backup: Rejected connection "+connection.getMgmtId());
connection.abort();
}
diff --git a/cpp/src/qpid/ha/BrokerReplicator.cpp b/cpp/src/qpid/ha/BrokerReplicator.cpp
index c8c4a42d72..fe32753b4e 100644
--- a/cpp/src/qpid/ha/BrokerReplicator.cpp
+++ b/cpp/src/qpid/ha/BrokerReplicator.cpp
@@ -24,7 +24,9 @@
#include "qpid/broker/Broker.h"
#include "qpid/broker/Connection.h"
#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueueSettings.h"
#include "qpid/broker/Link.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/log/Statement.h"
#include "qpid/amqp_0_10/Codecs.h"
@@ -117,11 +119,6 @@ const string _QUERY_REQUEST("_query_request");
const string BROKER("broker");
const string MEMBERS("members");
-bool isQMFv2(const Message& message) {
- const framing::MessageProperties* props = message.getProperties<framing::MessageProperties>();
- return props && props->getAppId() == QMF2;
-}
-
template <class T> bool match(Variant::Map& schema) {
return T::match(schema[CLASS_NAME], schema[PACKAGE_NAME]);
}
@@ -219,7 +216,7 @@ void BrokerReplicator::initializeBridge(Bridge& bridge, SessionHandler& sessionH
link->getRemoteAddress(primary);
string queueName = bridge.getQueueName();
- QPID_LOG(info, logPrefix << (initialized ? "Connecting" : "Failing over")
+ QPID_LOG(info, logPrefix << (initialized ? "Failing over" : "Connecting")
<< " to primary " << primary
<< " status:" << printable(haBroker.getStatus()));
initialized = true;
@@ -253,18 +250,15 @@ void BrokerReplicator::route(Deliverable& msg) {
haBroker.setStatus(CATCHUP);
QPID_LOG(notice, logPrefix << "Connected to primary " << primary);
}
-
- const framing::FieldTable* headers = msg.getMessage().getApplicationHeaders();
- const MessageProperties* messageProperties = msg.getMessage().getProperties<MessageProperties>();
Variant::List list;
try {
- if (!isQMFv2(msg.getMessage()) || !headers || !messageProperties)
+ if (!qpid::broker::amqp_0_10::MessageTransfer::isQMFv2(msg.getMessage()))
throw Exception("Unexpected message, not QMF2 event or query response.");
// decode as list
- string content = msg.getMessage().getFrames().getContent();
- amqp_0_10::ListCodec::decode(content, list);
- QPID_LOG(trace, "Broker replicator received: " << *messageProperties);
- if (headers->getAsString(QMF_CONTENT) == EVENT) {
+ string content = msg.getMessage().getContent();
+ qpid::amqp_0_10::ListCodec::decode(content, list);
+
+ if (msg.getMessage().getPropertyAsString(QMF_CONTENT) == EVENT) {
for (Variant::List::iterator i = list.begin(); i != list.end(); ++i) {
Variant::Map& map = i->asMap();
QPID_LOG(trace, "Broker replicator event: " << map);
@@ -278,20 +272,20 @@ void BrokerReplicator::route(Deliverable& msg) {
else if (match<EventUnbind>(schema)) doEventUnbind(values);
else if (match<EventMembersUpdate>(schema)) doEventMembersUpdate(values);
}
- } else if (headers->getAsString(QMF_OPCODE) == QUERY_RESPONSE) {
+ } else if (msg.getMessage().getPropertyAsString(QMF_OPCODE) == QUERY_RESPONSE) {
for (Variant::List::iterator i = list.begin(); i != list.end(); ++i) {
Variant::Map& map = i->asMap();
QPID_LOG(trace, "Broker replicator response: " << map);
string type = map[SCHEMA_ID].asMap()[CLASS_NAME].asString();
Variant::Map& values = map[VALUES].asMap();
framing::FieldTable args;
- amqp_0_10::translate(asMapVoid(values[ARGUMENTS]), args);
+ qpid::amqp_0_10::translate(asMapVoid(values[ARGUMENTS]), args);
if (type == QUEUE) doResponseQueue(values);
else if (type == EXCHANGE) doResponseExchange(values);
else if (type == BINDING) doResponseBind(values);
else if (type == HA_BROKER) doResponseHaBroker(values);
}
- if (messageProperties->getCorrelationId() == EXCHANGE && !headers->isSet(PARTIAL)) {
+ if (qpid::broker::amqp_0_10::MessageTransfer::isLastQMFResponse(msg.getMessage(), EXCHANGE)) {
// We have received all of the exchange response.
alternates.clear();
}
@@ -309,13 +303,11 @@ void BrokerReplicator::doEventQueueDeclare(Variant::Map& values) {
Variant::Map argsMap = asMapVoid(values[ARGS]);
bool autoDel = values[AUTODEL].asBool();
bool excl = values[EXCL].asBool();
- if (values[DISP] == CREATED &&
- replicationTest.isReplicated(CONFIGURATION, argsMap, autoDel, excl))
- {
+ if (values[DISP] == CREATED && replicationTest.isReplicated(CONFIGURATION, argsMap, autoDel, excl)) {
string name = values[QNAME].asString();
- QPID_LOG(debug, logPrefix << "Queue declare event: " << name);
+ QueueSettings settings(values[DURABLE].asBool(), values[AUTODEL].asBool());
framing::FieldTable args;
- amqp_0_10::translate(argsMap, args);
+ qpid::amqp_0_10::translate(argsMap, args);
// If we already have a queue with this name, replace it.
// The queue was definitely created on the primary.
if (broker.getQueues().find(name)) {
@@ -323,10 +315,17 @@ void BrokerReplicator::doEventQueueDeclare(Variant::Map& values) {
broker.getQueues().destroy(name);
stopQueueReplicator(name);
}
- boost::shared_ptr<Queue> queue = createQueue(
- name, values[DURABLE].asBool(), autoDel, args, values[ALTEX].asString());
- assert(queue); // Should be created since we destroed the previous queue above.
- if (queue) startQueueReplicator(queue);
+ settings.populate(args, settings.storeSettings);
+ std::pair<boost::shared_ptr<Queue>, bool> result =
+ broker.createQueue(
+ name,
+ settings,
+ 0 /*i.e. no owner regardless of exclusivity on master*/,
+ values[ALTEX].asString(),
+ userId,
+ remoteHost);
+ assert(result.second); // Should be true since we destroyed existing queue above
+ startQueueReplicator(result.first);
}
}
@@ -343,7 +342,7 @@ void BrokerReplicator::doEventQueueDelete(Variant::Map& values) {
// sessions may be closed by a "queue deleted" exception.
string name = values[QNAME].asString();
boost::shared_ptr<Queue> queue = broker.getQueues().find(name);
- if (queue && replicationTest.replicateLevel(queue->getSettings())) {
+ if (queue && replicationTest.replicateLevel(queue->getSettings().storeSettings)) {
QPID_LOG(debug, logPrefix << "Queue delete event: " << name);
stopQueueReplicator(name);
broker.deleteQueue(name, userId, remoteHost);
@@ -357,7 +356,7 @@ void BrokerReplicator::doEventExchangeDeclare(Variant::Map& values) {
string name = values[EXNAME].asString();
QPID_LOG(debug, logPrefix << "Exchange declare event: " << name);
framing::FieldTable args;
- amqp_0_10::translate(argsMap, args);
+ qpid::amqp_0_10::translate(argsMap, args);
// If we already have a exchange with this name, replace it.
// The exchange was definitely created on the primary.
if (broker.getExchanges().find(name)) {
@@ -391,10 +390,10 @@ void BrokerReplicator::doEventBind(Variant::Map& values) {
// We only replicate binds for a replicated queue to replicated
// exchange that both exist locally.
if (exchange && replicationTest.replicateLevel(exchange->getArgs()) &&
- queue && replicationTest.replicateLevel(queue->getSettings()))
+ queue && replicationTest.replicateLevel(queue->getSettings().storeSettings))
{
framing::FieldTable args;
- amqp_0_10::translate(asMapVoid(values[ARGS]), args);
+ qpid::amqp_0_10::translate(asMapVoid(values[ARGS]), args);
string key = values[KEY].asString();
QPID_LOG(debug, logPrefix << "Bind event: exchange=" << exchange->getName()
<< " queue=" << queue->getName()
@@ -411,10 +410,10 @@ void BrokerReplicator::doEventUnbind(Variant::Map& values) {
// We only replicate unbinds for a replicated queue to replicated
// exchange that both exist locally.
if (exchange && replicationTest.replicateLevel(exchange->getArgs()) &&
- queue && replicationTest.replicateLevel(queue->getSettings()))
+ queue && replicationTest.replicateLevel(queue->getSettings().storeSettings))
{
framing::FieldTable args;
- amqp_0_10::translate(asMapVoid(values[ARGS]), args);
+ qpid::amqp_0_10::translate(asMapVoid(values[ARGS]), args);
string key = values[KEY].asString();
QPID_LOG(debug, logPrefix << "Unbind event: exchange=" << exchange->getName()
<< " queue=" << queue->getName()
@@ -455,7 +454,7 @@ void BrokerReplicator::doResponseQueue(Variant::Map& values) {
string name(values[NAME].asString());
QPID_LOG(debug, logPrefix << "Queue response: " << name);
framing::FieldTable args;
- amqp_0_10::translate(argsMap, args);
+ qpid::amqp_0_10::translate(argsMap, args);
boost::shared_ptr<Queue> queue =
createQueue(name, values[DURABLE].asBool(), values[AUTODELETE].asBool(), args,
getAltExchange(values[ALTEXCHANGE]));
@@ -470,11 +469,12 @@ void BrokerReplicator::doResponseExchange(Variant::Map& values) {
string name = values[NAME].asString();
QPID_LOG(debug, logPrefix << "Exchange response: " << name);
framing::FieldTable args;
- amqp_0_10::translate(argsMap, args);
+ qpid::amqp_0_10::translate(argsMap, args);
boost::shared_ptr<Exchange> exchange = createExchange(
name, values[TYPE].asString(), values[DURABLE].asBool(), args,
getAltExchange(values[ALTEXCHANGE]));
- QPID_LOG_IF(debug, !exchange, logPrefix << "Exchange already exists: " << name);
+ // It is normal for the exchange to already exist if we are failing over.
+ QPID_LOG_IF(debug, !exchange, logPrefix << "Exchange already replicated: " << name);
}
namespace {
@@ -506,14 +506,14 @@ void BrokerReplicator::doResponseBind(Variant::Map& values) {
// Automatically replicate binding if queue and exchange exist and are replicated
if (exchange && replicationTest.replicateLevel(exchange->getArgs()) &&
- queue && replicationTest.replicateLevel(queue->getSettings()))
+ queue && replicationTest.replicateLevel(queue->getSettings().storeSettings))
{
string key = values[KEY].asString();
QPID_LOG(debug, logPrefix << "Bind response: exchange:" << exName
<< " queue:" << qName
<< " key:" << key);
framing::FieldTable args;
- amqp_0_10::translate(asMapVoid(values[ARGUMENTS]), args);
+ qpid::amqp_0_10::translate(asMapVoid(values[ARGUMENTS]), args);
exchange->bind(queue, key, &args);
}
}
@@ -543,7 +543,7 @@ void BrokerReplicator::doResponseHaBroker(Variant::Map& values) {
void BrokerReplicator::startQueueReplicator(const boost::shared_ptr<Queue>& queue)
{
- if (replicationTest.replicateLevel(queue->getSettings()) == ALL) {
+ if (replicationTest.replicateLevel(queue->getSettings().storeSettings) == ALL) {
boost::shared_ptr<QueueReplicator> qr(
new QueueReplicator(haBroker, queue, link));
if (!broker.getExchanges().registerExchange(qr))
@@ -569,14 +569,14 @@ boost::shared_ptr<Queue> BrokerReplicator::createQueue(
const qpid::framing::FieldTable& arguments,
const std::string& alternateExchange)
{
+ QueueSettings settings(durable, autodelete);
+ settings.populate(arguments, settings.storeSettings);
std::pair<boost::shared_ptr<Queue>, bool> result =
broker.createQueue(
name,
- durable,
- autodelete,
- 0, // no owner regardless of exclusivity on primary
+ settings,
+ 0,// no owner regardless of exclusivity on primary
string(), // Set alternate exchange below
- arguments,
userId,
remoteHost);
if (result.second) {
diff --git a/cpp/src/qpid/ha/ConnectionObserver.cpp b/cpp/src/qpid/ha/ConnectionObserver.cpp
index 3f7a1710d9..81ba3e4301 100644
--- a/cpp/src/qpid/ha/ConnectionObserver.cpp
+++ b/cpp/src/qpid/ha/ConnectionObserver.cpp
@@ -32,7 +32,7 @@ namespace ha {
ConnectionObserver::ConnectionObserver(HaBroker& hb, const types::Uuid& uuid)
: haBroker(hb), logPrefix("Connections: "), self(uuid) {}
-bool ConnectionObserver::getBrokerInfo(broker::Connection& connection, BrokerInfo& info) {
+bool ConnectionObserver::getBrokerInfo(const broker::Connection& connection, BrokerInfo& info) {
framing::FieldTable ft;
if (connection.getClientProperties().getTable(ConnectionObserver::BACKUP_TAG, ft)) {
info = BrokerInfo(ft);
@@ -51,21 +51,23 @@ ConnectionObserver::ObserverPtr ConnectionObserver::getObserver() {
return observer;
}
+bool ConnectionObserver::isSelf(const broker::Connection& connection) {
+ BrokerInfo info;
+ return getBrokerInfo(connection, info) && info.getSystemId() == self;
+}
+
void ConnectionObserver::opened(broker::Connection& connection) {
try {
if (connection.isLink()) return; // Allow outgoing links.
if (connection.getClientProperties().isSet(ADMIN_TAG)) {
- QPID_LOG(debug, logPrefix << "Allowing admin connection: "
+ QPID_LOG(debug, logPrefix << "Accepted admin connection: "
<< connection.getMgmtId());
return; // No need to call observer, always allow admins.
}
- BrokerInfo info; // Avoid self connections.
- if (getBrokerInfo(connection, info)) {
- if (info.getSystemId() == self) {
- QPID_LOG(debug, "HA broker rejected self connection "+connection.getMgmtId());
- connection.abort();
- }
-
+ if (isSelf(connection)) { // Reject self connections
+ QPID_LOG(debug, logPrefix << "Rejected self connection "+connection.getMgmtId());
+ connection.abort();
+ return;
}
ObserverPtr o(getObserver());
if (o) o->opened(connection);
@@ -77,8 +79,8 @@ void ConnectionObserver::opened(broker::Connection& connection) {
}
void ConnectionObserver::closed(broker::Connection& connection) {
+ if (isSelf(connection)) return; // Ignore closing of self connections.
try {
- BrokerInfo info;
ObserverPtr o(getObserver());
if (o) o->closed(connection);
}
diff --git a/cpp/src/qpid/ha/ConnectionObserver.h b/cpp/src/qpid/ha/ConnectionObserver.h
index 5c1dabe8f8..e3a6d1154a 100644
--- a/cpp/src/qpid/ha/ConnectionObserver.h
+++ b/cpp/src/qpid/ha/ConnectionObserver.h
@@ -51,7 +51,7 @@ class ConnectionObserver : public broker::ConnectionObserver
static const std::string ADMIN_TAG;
static const std::string BACKUP_TAG;
- static bool getBrokerInfo(broker::Connection& connection, BrokerInfo& info);
+ static bool getBrokerInfo(const broker::Connection& connection, BrokerInfo& info);
ConnectionObserver(HaBroker& haBroker, const types::Uuid& self);
@@ -62,6 +62,8 @@ class ConnectionObserver : public broker::ConnectionObserver
void closed(broker::Connection& connection);
private:
+ bool isSelf(const broker::Connection&);
+
sys::Mutex lock;
HaBroker& haBroker;
std::string logPrefix;
diff --git a/cpp/src/qpid/ha/HaBroker.cpp b/cpp/src/qpid/ha/HaBroker.cpp
index d126639813..ffbcb684bc 100644
--- a/cpp/src/qpid/ha/HaBroker.cpp
+++ b/cpp/src/qpid/ha/HaBroker.cpp
@@ -83,7 +83,11 @@ void HaBroker::initialize() {
// FIXME aconway 2012-07-19: assumes there's a TCP transport with a meaningful port.
brokerInfo = BrokerInfo(
- broker.getSystem()->getNodeName(), broker.getPort(broker::Broker::TCP_TRANSPORT), systemId);
+ broker.getSystem()->getNodeName(),
+ broker.getPort(broker::Broker::TCP_TRANSPORT),
+ systemId);
+
+ QPID_LOG(notice, logPrefix << "Initializing: " << brokerInfo);
// Set up the management object.
ManagementAgent* ma = broker.getManagementAgent();
@@ -111,8 +115,6 @@ void HaBroker::initialize() {
if (!settings.brokerUrl.empty()) setBrokerUrl(Url(settings.brokerUrl));
- QPID_LOG(notice, logPrefix << "Initializing: " << brokerInfo);
-
// NOTE: lock is not needed in a constructor, but create one
// to pass to functions that have a ScopedLock parameter.
Mutex::ScopedLock l(lock);
@@ -226,6 +228,7 @@ void HaBroker::setBrokerUrl(const Url& url) {
if (url.empty()) throw Url::Invalid("HA broker URL is empty");
brokerUrl = url;
mgmtObject->set_brokersUrl(brokerUrl.str());
+ QPID_LOG(info, logPrefix << "Broker URL set to: " << url);
if (backup.get()) backup->setBrokerUrl(brokerUrl);
// Updating broker URL also updates defaulted client URL:
if (clientUrl.empty()) updateClientUrl(l);
@@ -292,6 +295,7 @@ void HaBroker::statusChanged(Mutex::ScopedLock& l) {
}
void HaBroker::membershipUpdated(Mutex::ScopedLock&) {
+ QPID_LOG(info, logPrefix << "Membership changed: " << membership);
Variant::List brokers = membership.asList();
mgmtObject->set_members(brokers);
broker.getManagementAgent()->raiseEvent(_qmf::EventMembersUpdate(brokers));
@@ -321,14 +325,14 @@ void HaBroker::resetMembership(const BrokerInfo& b) {
void HaBroker::addBroker(const BrokerInfo& b) {
Mutex::ScopedLock l(lock);
membership.add(b);
- QPID_LOG(debug, logPrefix << "Membership add: " << b << " now: " << membership);
+ QPID_LOG(debug, logPrefix << "Membership add: " << b);
membershipUpdated(l);
}
void HaBroker::removeBroker(const Uuid& id) {
Mutex::ScopedLock l(lock);
membership.remove(id);
- QPID_LOG(debug, logPrefix << "Membership remove: " << id << " now: " << membership);
+ QPID_LOG(debug, logPrefix << "Membership remove: " << id);
membershipUpdated(l);
}
diff --git a/cpp/src/qpid/ha/HaBroker.h b/cpp/src/qpid/ha/HaBroker.h
index 0ffc152097..7dabe6e35b 100644
--- a/cpp/src/qpid/ha/HaBroker.h
+++ b/cpp/src/qpid/ha/HaBroker.h
@@ -97,6 +97,8 @@ class HaBroker : public management::Manageable
void addBroker(const BrokerInfo& b); // Add a broker to the membership.
void removeBroker(const types::Uuid& id); // Remove a broker from membership.
+ types::Uuid getSystemId() const { return systemId; }
+
private:
void setClientUrl(const Url&);
void setBrokerUrl(const Url&);
diff --git a/cpp/src/qpid/ha/Membership.cpp b/cpp/src/qpid/ha/Membership.cpp
index cc2906dd8f..74580f9b1e 100644
--- a/cpp/src/qpid/ha/Membership.cpp
+++ b/cpp/src/qpid/ha/Membership.cpp
@@ -66,7 +66,7 @@ types::Variant::List Membership::asList() const {
BrokerInfo::Set Membership::otherBackups() const {
BrokerInfo::Set result;
for (BrokerInfo::Map::const_iterator i = brokers.begin(); i != brokers.end(); ++i)
- if (isBackup(i->second.getStatus()) && i->second.getSystemId() != self)
+ if (i->second.getStatus() == READY && i->second.getSystemId() != self)
result.insert(i->second);
return result;
}
diff --git a/cpp/src/qpid/ha/Membership.h b/cpp/src/qpid/ha/Membership.h
index 3bd8653a64..8406dccd5d 100644
--- a/cpp/src/qpid/ha/Membership.h
+++ b/cpp/src/qpid/ha/Membership.h
@@ -47,7 +47,7 @@ class Membership
void add(const BrokerInfo& b);
void remove(const types::Uuid& id);
bool contains(const types::Uuid& id);
- /** Return IDs of all backups other than self */
+ /** Return IDs of all READY backups other than self */
BrokerInfo::Set otherBackups() const;
void assign(const types::Variant::List&);
diff --git a/cpp/src/qpid/ha/Primary.cpp b/cpp/src/qpid/ha/Primary.cpp
index 69c94bfc7d..e4bf9671b8 100644
--- a/cpp/src/qpid/ha/Primary.cpp
+++ b/cpp/src/qpid/ha/Primary.cpp
@@ -180,7 +180,7 @@ void Primary::readyReplica(const ReplicatingSubscription& rs) {
void Primary::queueCreate(const QueuePtr& q) {
// Throw if there is an invalid replication level in the queue settings.
- haBroker.getReplicationTest().replicateLevel(q->getSettings());
+ haBroker.getReplicationTest().replicateLevel(q->getSettings().storeSettings);
Mutex::ScopedLock l(lock);
for (BackupMap::iterator i = backups.begin(); i != backups.end(); ++i) {
i->second->queueCreate(q);
@@ -201,6 +201,7 @@ void Primary::opened(broker::Connection& connection) {
Mutex::ScopedLock l(lock);
BackupMap::iterator i = backups.find(info.getSystemId());
if (i == backups.end()) {
+ QPID_LOG(debug, logPrefix << "New backup connected: " << info);
boost::shared_ptr<RemoteBackup> backup(
new RemoteBackup(info, haBroker.getReplicationTest(), true));
{
@@ -209,7 +210,6 @@ void Primary::opened(broker::Connection& connection) {
backup->setInitialQueues(haBroker.getBroker().getQueues(), false);
}
backups[info.getSystemId()] = backup;
- QPID_LOG(debug, logPrefix << "New backup connected: " << info);
}
else {
QPID_LOG(debug, logPrefix << "Known backup connected: " << info);
@@ -225,6 +225,12 @@ void Primary::opened(broker::Connection& connection) {
}
void Primary::closed(broker::Connection& connection) {
+ // NOTE: It is possible for a backup connection to be rejected while we are
+ // a backup, but closed() is called after we have become primary.
+ //
+ // For this reason we do not remove from the backups map here, the backups
+ // map holds all the backups we know about whether connected or not.
+ //
Mutex::ScopedLock l(lock);
BrokerInfo info;
if (ha::ConnectionObserver::getBrokerInfo(connection, info)) {
@@ -233,12 +239,6 @@ void Primary::closed(broker::Connection& connection) {
BackupMap::iterator i = backups.find(info.getSystemId());
if (i != backups.end()) i->second->setConnected(false);
}
- // NOTE: we do not remove from the backups map here, the backups map holds
- // all the backups we know about whether connected or not.
- //
- // It is possible for a backup connection to be rejected while we are a backup,
- // but the closed is seen after we have become primary. Removing the entry
- // from backups in this case would be incorrect.
}
diff --git a/cpp/src/qpid/ha/QueueGuard.cpp b/cpp/src/qpid/ha/QueueGuard.cpp
index a30ab1f73c..77e1f81a38 100644
--- a/cpp/src/qpid/ha/QueueGuard.cpp
+++ b/cpp/src/qpid/ha/QueueGuard.cpp
@@ -39,10 +39,10 @@ class QueueGuard::QueueObserver : public broker::QueueObserver
{
public:
QueueObserver(QueueGuard& g) : guard(g) {}
- void enqueued(const broker::QueuedMessage& qm) { guard.enqueued(qm); }
- void dequeued(const broker::QueuedMessage& qm) { guard.dequeued(qm); }
- void acquired(const broker::QueuedMessage&) {}
- void requeued(const broker::QueuedMessage&) {}
+ void enqueued(const broker::Message& m) { guard.enqueued(m); }
+ void dequeued(const broker::Message& m) { guard.dequeued(m); }
+ void acquired(const broker::Message&) {}
+ void requeued(const broker::Message&) {}
private:
QueueGuard& guard;
};
@@ -64,39 +64,47 @@ QueueGuard::QueueGuard(broker::Queue& q, const BrokerInfo& info)
QueueGuard::~QueueGuard() { cancel(); }
// NOTE: Called with message lock held.
-void QueueGuard::enqueued(const QueuedMessage& qm) {
- assert(qm.queue == &queue);
+void QueueGuard::enqueued(const Message& m) {
// Delay completion
- QPID_LOG(trace, logPrefix << "Delayed completion of " << qm);
- qm.payload->getIngressCompletion().startCompleter();
+ QPID_LOG(trace, logPrefix << "Delayed completion of " << m);
+ m.getIngressCompletion()->startCompleter();
{
Mutex::ScopedLock l(lock);
- assert(!delayed.contains(qm.position));
- delayed += qm.position;
+ if (!delayed.insert(Delayed::value_type(m.getSequence(), m.getIngressCompletion())).second) {
+ QPID_LOG(critical, logPrefix << "Second enqueue for message with sequence " << m.getSequence());
+ assert(false);
+ }
}
}
// NOTE: Called with message lock held.
-void QueueGuard::dequeued(const QueuedMessage& qm) {
- assert(qm.queue == &queue);
- QPID_LOG(trace, logPrefix << "Dequeued " << qm);
+void QueueGuard::dequeued(const Message& m) {
+ QPID_LOG(trace, logPrefix << "Dequeued " << m);
ReplicatingSubscription* rs=0;
{
Mutex::ScopedLock l(lock);
rs = subscription;
}
- if (rs) rs->dequeued(qm);
- complete(qm);
+ if (rs) rs->dequeued(m);
+ complete(m.getSequence());
+}
+
+void QueueGuard::completeRange(Delayed::iterator begin, Delayed::iterator end) {
+ for (Delayed::iterator i = begin; i != end; ++i) {
+ QPID_LOG(trace, logPrefix << "Completed " << i->first);
+ i->second->finishCompleter();
+ }
}
void QueueGuard::cancel() {
queue.removeObserver(observer);
+ Delayed removed;
{
Mutex::ScopedLock l(lock);
if (delayed.empty()) return; // No need if no delayed messages.
+ delayed.swap(removed);
}
- // FIXME aconway 2012-06-15: optimize, only messages in delayed set.
- queue.eachMessage(boost::bind(&QueueGuard::complete, this, _1));
+ completeRange(removed.begin(), removed.end());
}
void QueueGuard::attach(ReplicatingSubscription& rs) {
@@ -104,36 +112,39 @@ void QueueGuard::attach(ReplicatingSubscription& rs) {
subscription = &rs;
}
-namespace {
-void completeBefore(QueueGuard* guard, SequenceNumber position, const QueuedMessage& qm) {
- if (qm.position <= position) guard->complete(qm);
-}
-}
-
bool QueueGuard::subscriptionStart(SequenceNumber position) {
- // Complete any messages before or at the ReplicatingSubscription start position.
- // Those messages are already on the backup.
- if (!delayed.empty() && delayed.front() <= position) {
- // FIXME aconway 2012-06-15: queue iteration, only messages in delayed
- queue.eachMessage(boost::bind(&completeBefore, this, position, _1));
+ Delayed removed;
+ {
+ Mutex::ScopedLock l(lock);
+ // Complete any messages before or at the ReplicatingSubscription start position.
+ // Those messages are already on the backup.
+ for (Delayed::iterator i = delayed.begin(); i != delayed.end() && i->first <= position;) {
+ removed.insert(*i);
+ delayed.erase(i++);
+ }
}
+ completeRange(removed.begin(), removed.end());
return position >= range.back;
}
-void QueueGuard::complete(const QueuedMessage& qm) {
- assert(qm.queue == &queue);
+void QueueGuard::complete(SequenceNumber sequence) {
+ boost::intrusive_ptr<broker::AsyncCompletion> m;
{
Mutex::ScopedLock l(lock);
// The same message can be completed twice, by
// ReplicatingSubscription::acknowledged and dequeued. Remove it
- // from the set so we only call finishCompleter() once
- if (delayed.contains(qm.position))
- delayed -= qm.position;
- else
- return;
+ // from the map so we only call finishCompleter() once
+ Delayed::iterator i = delayed.find(sequence);
+ if (i != delayed.end()) {
+ m = i->second;
+ delayed.erase(i);
+ }
+
+ }
+ if (m) {
+ QPID_LOG(trace, logPrefix << "Completed " << sequence);
+ m->finishCompleter();
}
- QPID_LOG(trace, logPrefix << "Completed " << qm);
- qm.payload->getIngressCompletion().finishCompleter();
}
}} // namespaces qpid::ha
diff --git a/cpp/src/qpid/ha/QueueGuard.h b/cpp/src/qpid/ha/QueueGuard.h
index bc8f40b65f..3904b3bd3f 100644
--- a/cpp/src/qpid/ha/QueueGuard.h
+++ b/cpp/src/qpid/ha/QueueGuard.h
@@ -63,15 +63,15 @@ class QueueGuard {
/** QueueObserver override. Delay completion of the message.
* NOTE: Called under the queues message lock.
*/
- void enqueued(const broker::QueuedMessage&);
+ void enqueued(const broker::Message&);
/** QueueObserver override: Complete a delayed message.
* NOTE: Called under the queues message lock.
*/
- void dequeued(const broker::QueuedMessage&);
+ void dequeued(const broker::Message&);
/** Complete a delayed message. */
- void complete(const broker::QueuedMessage&);
+ void complete(framing::SequenceNumber);
/** Complete all delayed messages. */
void cancel();
@@ -108,10 +108,13 @@ class QueueGuard {
sys::Mutex lock;
std::string logPrefix;
broker::Queue& queue;
- framing::SequenceSet delayed;
+ typedef std::map<framing::SequenceNumber, boost::intrusive_ptr<broker::AsyncCompletion> > Delayed;
+ Delayed delayed;
ReplicatingSubscription* subscription;
boost::shared_ptr<QueueObserver> observer;
QueueRange range;
+
+ void completeRange(Delayed::iterator begin, Delayed::iterator end);
};
}} // namespace qpid::ha
diff --git a/cpp/src/qpid/ha/QueueReplicator.cpp b/cpp/src/qpid/ha/QueueReplicator.cpp
index be910a087f..ae53f89404 100644
--- a/cpp/src/qpid/ha/QueueReplicator.cpp
+++ b/cpp/src/qpid/ha/QueueReplicator.cpp
@@ -120,8 +120,10 @@ void QueueReplicator::initializeBridge(Bridge& bridge, SessionHandler& sessionHa
settings.setTable(ReplicatingSubscription::QPID_BROKER_INFO,
brokerInfo.asFieldTable());
SequenceNumber front;
- if (ReplicatingSubscription::getFront(*queue, front))
+ if (ReplicatingSubscription::getFront(*queue, front)) {
settings.setInt(ReplicatingSubscription::QPID_FRONT, front);
+ QPID_LOG(debug, "QPID_FRONT for " << queue->getName() << " is " << front);
+ }
peer.getMessage().subscribe(
args.i_src, args.i_dest, 0/*accept-explicit*/, 1/*not-acquired*/,
false/*exclusive*/, "", 0, settings);
@@ -137,8 +139,7 @@ void QueueReplicator::initializeBridge(Bridge& bridge, SessionHandler& sessionHa
namespace {
template <class T> T decodeContent(Message& m) {
- std::string content;
- m.getFrames().getContent(content);
+ std::string content = m.getContent();
Buffer buffer(const_cast<char*>(content.c_str()), content.size());
T result;
result.decode(buffer);
@@ -148,9 +149,7 @@ template <class T> T decodeContent(Message& m) {
void QueueReplicator::dequeue(SequenceNumber n, sys::Mutex::ScopedLock&) {
// Thread safe: only calls thread safe Queue functions.
- QueuedMessage message;
- if (queue->acquireMessageAt(n, message))
- queue->dequeue(0, message);
+ queue->dequeueMessageAt(n);
}
// Called in connection thread of the queues bridge to primary.
diff --git a/cpp/src/qpid/ha/RemoteBackup.cpp b/cpp/src/qpid/ha/RemoteBackup.cpp
index a5693fd14e..3421380940 100644
--- a/cpp/src/qpid/ha/RemoteBackup.cpp
+++ b/cpp/src/qpid/ha/RemoteBackup.cpp
@@ -23,6 +23,7 @@
#include "qpid/broker/Broker.h"
#include "qpid/broker/Queue.h"
#include "qpid/broker/QueueRegistry.h"
+#include "qpid/log/Statement.h"
#include <boost/bind.hpp>
namespace qpid {
@@ -32,7 +33,7 @@ using sys::Mutex;
using boost::bind;
RemoteBackup::RemoteBackup(const BrokerInfo& info, ReplicationTest rt, bool con) :
- logPrefix("Primary remote backup "+info.getLogId()+": "),
+ logPrefix("Primary: Remote backup "+info.getLogId()+": "),
brokerInfo(info), replicationTest(rt), connected(con), reportedReady(false)
{}
diff --git a/cpp/src/qpid/ha/ReplicatingSubscription.cpp b/cpp/src/qpid/ha/ReplicatingSubscription.cpp
index c960758eaf..6f7519cd1f 100644
--- a/cpp/src/qpid/ha/ReplicatingSubscription.cpp
+++ b/cpp/src/qpid/ha/ReplicatingSubscription.cpp
@@ -27,6 +27,7 @@
#include "qpid/broker/Queue.h"
#include "qpid/broker/SessionContext.h"
#include "qpid/broker/ConnectionState.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/log/Statement.h"
@@ -66,10 +67,10 @@ class DequeueScanner
at = front - 1;
}
- void operator()(const QueuedMessage& qm) {
- if (qm.position >= front && qm.position <= back) {
- if (qm.position > at+1) subscription.dequeued(at+1, qm.position-1);
- at = qm.position;
+ void operator()(const Message& m) {
+ if (m.getSequence() >= front && m.getSequence() <= back) {
+ if (m.getSequence() > at+1) subscription.dequeued(at+1, m.getSequence()-1);
+ at = m.getSequence();
}
}
@@ -90,37 +91,23 @@ string mask(const string& in)
return DOLLAR + in + INTERNAL;
}
-
-/** Dummy consumer used to get the front position on the queue */
-class GetPositionConsumer : public Consumer
+namespace {
+bool getSequence(const Message& message, SequenceNumber& result)
{
- public:
- GetPositionConsumer() :
- Consumer("ha.GetPositionConsumer."+types::Uuid(true).str(), false) {}
- bool deliver(broker::QueuedMessage& ) { return true; }
- void notify() {}
- bool filter(boost::intrusive_ptr<broker::Message>) { return true; }
- bool accept(boost::intrusive_ptr<broker::Message>) { return true; }
- void cancel() {}
- void acknowledged(const broker::QueuedMessage&) {}
- bool browseAcquired() const { return true; }
- broker::OwnershipToken* getSession() { return 0; }
-};
-
-
+ result = message.getSequence();
+ return true;
+}
+}
bool ReplicatingSubscription::getNext(
broker::Queue& q, SequenceNumber from, SequenceNumber& result)
{
- boost::shared_ptr<Consumer> c(new GetPositionConsumer);
- c->setPosition(from);
- if (!q.dispatch(c)) return false;
- result = c->getPosition();
- return true;
+ QueueCursor cursor(REPLICATOR);
+ return q.seek(cursor, boost::bind(&getSequence, _1, boost::ref(result)), from);
}
bool ReplicatingSubscription::getFront(broker::Queue& q, SequenceNumber& front) {
- // FIXME aconway 2012-05-23: won't wrap, assumes 0 is < all messages in queue.
- return getNext(q, 0, front);
+ QueueCursor cursor(REPLICATOR);
+ return q.seek(cursor, boost::bind(&getSequence, _1, boost::ref(front)));
}
/* Called by SemanticState::consume to create a consumer */
@@ -152,15 +139,14 @@ ReplicatingSubscription::ReplicatingSubscription(
const string& name,
Queue::shared_ptr queue,
bool ack,
- bool acquire,
+ bool /*acquire*/,
bool exclusive,
const string& tag,
const string& resumeId,
uint64_t resumeTtl,
const framing::FieldTable& arguments
-) : ConsumerImpl(parent, name, queue, ack, acquire, exclusive, tag,
+) : ConsumerImpl(parent, name, queue, ack, REPLICATOR, exclusive, tag,
resumeId, resumeTtl, arguments),
- dummy(new Queue(mask(name))),
ready(false)
{
try {
@@ -213,6 +199,8 @@ ReplicatingSubscription::ReplicatingSubscription(
queue->eachMessage(boost::ref(scan)); // Remove missing messages in between.
scan.finish();
position = backup.back;
+ //move cursor to position
+ queue->seek(*this, position);
}
// NOTE: we are assuming that the messages that are on the backup are
// consistent with those on the primary. If the backup is a replica
@@ -260,32 +248,31 @@ void ReplicatingSubscription::initialize() {
}
// Message is delivered in the subscription's connection thread.
-bool ReplicatingSubscription::deliver(QueuedMessage& qm) {
+bool ReplicatingSubscription::deliver(const qpid::broker::QueueCursor& c, const qpid::broker::Message& m) {
+ position = m.getSequence();
try {
- // Add position events for the subscribed queue, not the internal event queue.
- if (qm.queue == getQueue().get()) {
- QPID_LOG(trace, logPrefix << "Replicating " << qm);
- {
- Mutex::ScopedLock l(lock);
- assert(position == qm.position);
- // qm.position is the position of the newly enqueued qm on local queue.
- // backupPosition is latest position on backup queue before enqueueing
- if (qm.position <= backupPosition)
- throw Exception(
- QPID_MSG("Expected position > " << backupPosition
- << " but got " << qm.position));
- if (qm.position - backupPosition > 1) {
- // Position has advanced because of messages dequeued ahead of us.
- // Send the position before qm was enqueued.
- sendPositionEvent(qm.position-1, l);
- }
- // Backup will automatically advance by 1 on delivery of message.
- backupPosition = qm.position;
+ QPID_LOG(trace, logPrefix << "Replicating " << getQueue()->getName() << "[" << m.getSequence() << "]");
+ {
+ Mutex::ScopedLock l(lock);
+ //FIXME GRS: position is no longer set//assert(position == m.getSequence());
+
+ // m.getSequence() is the position of the newly enqueued message on local queue.
+ // backupPosition is latest position on backup queue before enqueueing
+ if (m.getSequence() <= backupPosition)
+ throw Exception(
+ QPID_MSG("Expected position > " << backupPosition
+ << " but got " << m.getSequence()));
+ if (m.getSequence() - backupPosition > 1) {
+ // Position has advanced because of messages dequeued ahead of us.
+ // Send the position before message was enqueued.
+ sendPositionEvent(m.getSequence()-1, l);
}
+ // Backup will automatically advance by 1 on delivery of message.
+ backupPosition = m.getSequence();
}
- return ConsumerImpl::deliver(qm);
+ return ConsumerImpl::deliver(c, m);
} catch (const std::exception& e) {
- QPID_LOG(critical, logPrefix << "Error replicating " << qm
+ QPID_LOG(critical, logPrefix << "Error replicating " << getQueue()->getName() << "[" << m.getSequence() << "]"
<< ": " << e.what());
throw;
}
@@ -310,15 +297,13 @@ void ReplicatingSubscription::cancel()
}
// Consumer override, called on primary in the backup's IO thread.
-void ReplicatingSubscription::acknowledged(const QueuedMessage& qm) {
- if (qm.queue == getQueue().get()) { // Don't complete messages on the internal queue
- // Finish completion of message, it has been acknowledged by the backup.
- QPID_LOG(trace, logPrefix << "Acknowledged " << qm);
- guard->complete(qm);
- // If next message is protected by the guard then we are ready
- if (qm.position >= guard->getRange().back) setReady();
- }
- ConsumerImpl::acknowledged(qm);
+void ReplicatingSubscription::acknowledged(const broker::DeliveryRecord& r) {
+ // Finish completion of message, it has been acknowledged by the backup.
+ QPID_LOG(trace, logPrefix << "Acknowledged " << getQueue()->getName() << "[" << r.getMessageId() << "]");
+ guard->complete(r.getMessageId());
+ // If next message is protected by the guard then we are ready
+ if (r.getMessageId() >= guard->getRange().back) setReady();
+ ConsumerImpl::acknowledged(r);
}
// Called with lock held. Called in subscription's connection thread.
@@ -341,13 +326,12 @@ void ReplicatingSubscription::sendDequeueEvent(Mutex::ScopedLock&)
// Called after the message has been removed
// from the deque and under the messageLock in the queue. Called in
// arbitrary connection threads.
-void ReplicatingSubscription::dequeued(const QueuedMessage& qm)
+void ReplicatingSubscription::dequeued(const Message& m)
{
- assert (qm.queue == getQueue().get());
- QPID_LOG(trace, logPrefix << "Dequeued " << qm);
+ QPID_LOG(trace, logPrefix << "Dequeued " << getQueue()->getName() << "[" << m.getSequence() << "]");
{
Mutex::ScopedLock l(lock);
- dequeues.add(qm.position);
+ dequeues.add(m.getSequence());
}
notify(); // Ensure a call to doDispatch
}
@@ -379,7 +363,7 @@ void ReplicatingSubscription::sendPositionEvent(SequenceNumber pos, Mutex::Scope
void ReplicatingSubscription::sendEvent(const std::string& key, framing::Buffer& buffer)
{
//generate event message
- boost::intrusive_ptr<Message> event = new Message();
+ boost::intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> event(new qpid::broker::amqp_0_10::MessageTransfer());
AMQFrame method((MessageTransferBody(ProtocolVersion(), string(), 0, 0)));
AMQFrame header((AMQHeaderBody()));
AMQFrame content((AMQContentBody()));
@@ -400,10 +384,8 @@ void ReplicatingSubscription::sendEvent(const std::string& key, framing::Buffer&
event->getFrames().getHeaders()->get<DeliveryProperties>(true);
props->setRoutingKey(key);
// Send the event directly to the base consumer implementation.
- // We don't really need a queue here but we pass a dummy queue
- // to conform to the consumer API.
- QueuedMessage qm(dummy.get(), event);
- ConsumerImpl::deliver(qm);
+ //dummy consumer prevents acknowledgements being handled, which is what we want for events
+ ConsumerImpl::deliver(QueueCursor(), Message(event, 0), boost::shared_ptr<Consumer>());
}
diff --git a/cpp/src/qpid/ha/ReplicatingSubscription.h b/cpp/src/qpid/ha/ReplicatingSubscription.h
index a80141a6c2..8a2984846e 100644
--- a/cpp/src/qpid/ha/ReplicatingSubscription.h
+++ b/cpp/src/qpid/ha/ReplicatingSubscription.h
@@ -101,15 +101,15 @@ class ReplicatingSubscription : public broker::SemanticState::ConsumerImpl
// Called via QueueGuard::dequeued.
//@return true if the message requires completion.
- void dequeued(const broker::QueuedMessage& qm);
+ void dequeued(const broker::Message&);
// Called during initial scan for dequeues.
void dequeued(framing::SequenceNumber first, framing::SequenceNumber last);
// Consumer overrides.
- bool deliver(broker::QueuedMessage& msg);
+ bool deliver(const broker::QueueCursor& cursor, const broker::Message& msg);
void cancel();
- void acknowledged(const broker::QueuedMessage&);
+ void acknowledged(const broker::DeliveryRecord&);
bool browseAcquired() const { return true; }
// Hide the "queue deleted" error for a ReplicatingSubscription when a
// queue is deleted, this is normal and not an error.
@@ -127,8 +127,8 @@ class ReplicatingSubscription : public broker::SemanticState::ConsumerImpl
private:
std::string logPrefix;
- boost::shared_ptr<broker::Queue> dummy; // Used to send event messages
framing::SequenceSet dequeues;
+ framing::SequenceNumber position;
framing::SequenceNumber backupPosition;
bool ready;
BrokerInfo info;
diff --git a/cpp/src/qpid/ha/ReplicationTest.cpp b/cpp/src/qpid/ha/ReplicationTest.cpp
index 18e0953930..88a969dbfd 100644
--- a/cpp/src/qpid/ha/ReplicationTest.cpp
+++ b/cpp/src/qpid/ha/ReplicationTest.cpp
@@ -68,7 +68,7 @@ bool ReplicationTest::isReplicated(
bool ReplicationTest::isReplicated(ReplicateLevel level, const broker::Queue& q)
{
- return isReplicated(level, q.getSettings(), q.isAutoDelete(), q.hasExclusiveOwner());
+ return isReplicated(level, q.getSettings().storeSettings, q.isAutoDelete(), q.hasExclusiveOwner());
}
diff --git a/cpp/src/qpid/management/ManagementAgent.cpp b/cpp/src/qpid/management/ManagementAgent.cpp
index 7d90ed99d0..474c86ed48 100644
--- a/cpp/src/qpid/management/ManagementAgent.cpp
+++ b/cpp/src/qpid/management/ManagementAgent.cpp
@@ -31,6 +31,7 @@
#include <qpid/broker/Message.h>
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/FieldValue.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/sys/Time.h"
#include "qpid/sys/Thread.h"
#include "qpid/broker/ConnectionState.h"
@@ -535,7 +536,7 @@ void ManagementAgent::sendBufferLH(Buffer& buf,
}
if (exchange.get() == 0) return;
- intrusive_ptr<Message> msg(new Message());
+ intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> transfer(new qpid::broker::amqp_0_10::MessageTransfer());
AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange->getName (), 0, 0)));
AMQFrame header((AMQHeaderBody()));
AMQFrame content((AMQContentBody()));
@@ -547,24 +548,26 @@ void ManagementAgent::sendBufferLH(Buffer& buf,
header.setEof(false);
content.setBof(false);
- msg->getFrames().append(method);
- msg->getFrames().append(header);
+ transfer->getFrames().append(method);
+ transfer->getFrames().append(header);
MessageProperties* props =
- msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ transfer->getFrames().getHeaders()->get<MessageProperties>(true);
props->setContentLength(length);
DeliveryProperties* dp =
- msg->getFrames().getHeaders()->get<DeliveryProperties>(true);
+ transfer->getFrames().getHeaders()->get<DeliveryProperties>(true);
dp->setRoutingKey(routingKey);
- msg->getFrames().append(content);
- msg->setIsManagementMessage(true);
+ transfer->getFrames().append(content);
+
+ Message msg(transfer, transfer);
+ msg.setIsManagementMessage(true);
{
sys::Mutex::ScopedUnlock u(userLock);
- DeliverableMessage deliverable (msg);
+ DeliverableMessage deliverable (msg, 0);
try {
exchange->route(deliverable);
} catch(exception&) {}
@@ -602,7 +605,7 @@ void ManagementAgent::sendBufferLH(const string& data,
}
if (exchange.get() == 0) return;
- intrusive_ptr<Message> msg(new Message());
+ intrusive_ptr<qpid::broker::amqp_0_10::MessageTransfer> transfer(new qpid::broker::amqp_0_10::MessageTransfer);
AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange->getName (), 0, 0)));
AMQFrame header((AMQHeaderBody()));
AMQFrame content((AMQContentBody(data)));
@@ -612,11 +615,11 @@ void ManagementAgent::sendBufferLH(const string& data,
header.setEof(false);
content.setBof(false);
- msg->getFrames().append(method);
- msg->getFrames().append(header);
+ transfer->getFrames().append(method);
+ transfer->getFrames().append(header);
MessageProperties* props =
- msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ transfer->getFrames().getHeaders()->get<MessageProperties>(true);
props->setContentLength(data.length());
if (!cid.empty()) {
props->setCorrelationId(cid);
@@ -625,23 +628,25 @@ void ManagementAgent::sendBufferLH(const string& data,
props->setAppId("qmf2");
for (i = headers.begin(); i != headers.end(); ++i) {
- msg->insertCustomProperty(i->first, i->second.asString());
+ props->getApplicationHeaders().setString(i->first, i->second.asString());
}
DeliveryProperties* dp =
- msg->getFrames().getHeaders()->get<DeliveryProperties>(true);
+ transfer->getFrames().getHeaders()->get<DeliveryProperties>(true);
dp->setRoutingKey(routingKey);
if (ttl_msec) {
dp->setTtl(ttl_msec);
- msg->computeExpiration(broker->getExpiryPolicy());
}
- msg->getFrames().append(content);
- msg->setIsManagementMessage(true);
+ transfer->getFrames().append(content);
+ transfer->computeRequiredCredit();
+ Message msg(transfer, transfer);
+ msg.setIsManagementMessage(true);
+ msg.computeExpiration(broker->getExpiryPolicy());
{
sys::Mutex::ScopedUnlock u(userLock);
- DeliverableMessage deliverable (msg);
+ DeliverableMessage deliverable (msg, 0);
try {
exchange->route(deliverable);
} catch(exception&) {}
@@ -2135,19 +2140,20 @@ bool ManagementAgent::authorizeAgentMessageLH(Message& msg)
// authorized or not. In this case, return true (authorized) if there is no ACL in place,
// otherwise return false;
//
- if (msg.encodedSize() > MA_BUFFER_SIZE)
+ if (msg.getContentSize() > MA_BUFFER_SIZE)
return broker->getAcl() == 0;
- msg.encodeContent(inBuffer);
+ inBuffer.putRawData(msg.getContent());
uint32_t bufferLen = inBuffer.getPosition();
inBuffer.reset();
+ qpid::broker::amqp_0_10::MessageTransfer& transfer(qpid::broker::amqp_0_10::MessageTransfer::get(msg));
const framing::MessageProperties* p =
- msg.getFrames().getHeaders()->get<framing::MessageProperties>();
+ transfer.getFrames().getHeaders()->get<framing::MessageProperties>();
- const framing::FieldTable *headers = msg.getApplicationHeaders();
+ const framing::FieldTable *headers = p ? &p->getApplicationHeaders() : 0;
- if (headers && msg.getAppId() == "qmf2")
+ if (headers && p->getAppId() == "qmf2")
{
mapMsg = true;
@@ -2238,8 +2244,9 @@ bool ManagementAgent::authorizeAgentMessageLH(Message& msg)
// authorization failed, send reply if replyTo present
+ qpid::broker::amqp_0_10::MessageTransfer& transfer(qpid::broker::amqp_0_10::MessageTransfer::get(msg));
const framing::MessageProperties* p =
- msg.getFrames().getHeaders()->get<framing::MessageProperties>();
+ transfer.getFrames().getHeaders()->get<framing::MessageProperties>();
if (p && p->hasReplyTo()) {
const framing::ReplyTo& rt = p->getReplyTo();
string rte = rt.getExchange();
@@ -2277,8 +2284,9 @@ void ManagementAgent::dispatchAgentCommandLH(Message& msg, bool viaLocal)
{
string rte;
string rtk;
+ qpid::broker::amqp_0_10::MessageTransfer& transfer(qpid::broker::amqp_0_10::MessageTransfer::get(msg));
const framing::MessageProperties* p =
- msg.getFrames().getHeaders()->get<framing::MessageProperties>();
+ transfer.getFrames().getHeaders()->get<framing::MessageProperties>();
if (p && p->hasReplyTo()) {
const framing::ReplyTo& rt = p->getReplyTo();
rte = rt.getExchange();
@@ -2290,19 +2298,19 @@ void ManagementAgent::dispatchAgentCommandLH(Message& msg, bool viaLocal)
Buffer inBuffer(inputBuffer, MA_BUFFER_SIZE);
uint8_t opcode;
- if (msg.encodedSize() > MA_BUFFER_SIZE) {
+ if (msg.getContentSize() > MA_BUFFER_SIZE) {
QPID_LOG(debug, "ManagementAgent::dispatchAgentCommandLH: Message too large: " <<
- msg.encodedSize());
+ msg.getContentSize());
return;
}
- msg.encodeContent(inBuffer);
+ inBuffer.putRawData(msg.getContent());
uint32_t bufferLen = inBuffer.getPosition();
inBuffer.reset();
ScopedManagementContext context((const qpid::broker::ConnectionState*) msg.getPublisher());
- const framing::FieldTable *headers = msg.getApplicationHeaders();
- if (headers && msg.getAppId() == "qmf2")
+ const framing::FieldTable *headers = p ? &p->getApplicationHeaders() : 0;
+ if (headers && p->getAppId() == "qmf2")
{
string opcode = headers->getAsString("qmf.opcode");
string contentType = headers->getAsString("qmf.content");
diff --git a/cpp/src/qpid/management/ManagementDirectExchange.cpp b/cpp/src/qpid/management/ManagementDirectExchange.cpp
index 9432a21b3a..1c1d6ef3db 100644
--- a/cpp/src/qpid/management/ManagementDirectExchange.cpp
+++ b/cpp/src/qpid/management/ManagementDirectExchange.cpp
@@ -43,11 +43,9 @@ ManagementDirectExchange::ManagementDirectExchange(const std::string& _name,
void ManagementDirectExchange::route(Deliverable& msg)
{
bool routeIt = true;
- const std::string& routingKey = msg.getMessage().getRoutingKey();
- const FieldTable* args = msg.getMessage().getApplicationHeaders();
if (managementAgent)
- routeIt = managementAgent->dispatchCommand(msg, routingKey, args, false, qmfVersion);
+ routeIt = managementAgent->dispatchCommand(msg, msg.getMessage().getRoutingKey(), 0/*args - TODO*/, false, qmfVersion);
if (routeIt)
DirectExchange::route(msg);
diff --git a/cpp/src/qpid/management/ManagementTopicExchange.cpp b/cpp/src/qpid/management/ManagementTopicExchange.cpp
index e5b659f217..c8bfef3785 100644
--- a/cpp/src/qpid/management/ManagementTopicExchange.cpp
+++ b/cpp/src/qpid/management/ManagementTopicExchange.cpp
@@ -42,12 +42,10 @@ ManagementTopicExchange::ManagementTopicExchange(const std::string& _name,
void ManagementTopicExchange::route(Deliverable& msg)
{
bool routeIt = true;
- const std::string& routingKey = msg.getMessage().getRoutingKey();
- const FieldTable* args = msg.getMessage().getApplicationHeaders();
// Intercept management agent commands
if (managementAgent)
- routeIt = managementAgent->dispatchCommand(msg, routingKey, args, true, qmfVersion);
+ routeIt = managementAgent->dispatchCommand(msg, msg.getMessage().getRoutingKey(), 0/*args - TODO*/, true, qmfVersion);
if (routeIt)
TopicExchange::route(msg);
diff --git a/cpp/src/qpid/replication/ReplicatingEventListener.cpp b/cpp/src/qpid/replication/ReplicatingEventListener.cpp
deleted file mode 100644
index 9284bda388..0000000000
--- a/cpp/src/qpid/replication/ReplicatingEventListener.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/replication/ReplicatingEventListener.h"
-#include "qpid/replication/constants.h"
-#include "qpid/broker/Broker.h"
-#include "qpid/broker/DeliverableMessage.h"
-#include "qpid/broker/QueueEvents.h"
-#include "qpid/framing/AMQFrame.h"
-#include "qpid/framing/FrameHandler.h"
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/log/Statement.h"
-
-namespace qpid {
-namespace replication {
-
-using namespace qpid::broker;
-using namespace qpid::framing;
-using namespace qpid::replication::constants;
-
-void ReplicatingEventListener::handle(QueueEvents::Event event)
-{
- switch (event.type) {
- case QueueEvents::ENQUEUE:
- deliverEnqueueMessage(event.msg);
- QPID_LOG(debug, "Queuing 'enqueue' event on " << event.msg.queue->getName() << " for replication");
- break;
- case QueueEvents::DEQUEUE:
- deliverDequeueMessage(event.msg);
- QPID_LOG(debug, "Queuing 'dequeue' event from " << event.msg.queue->getName() << " for replication, (from position "
- << event.msg.position << ")");
- break;
- }
-}
-
-namespace {
-const std::string EMPTY;
-}
-
-void ReplicatingEventListener::deliverDequeueMessage(const QueuedMessage& dequeued)
-{
- FieldTable headers;
- headers.setString(REPLICATION_TARGET_QUEUE, dequeued.queue->getName());
- headers.setInt(REPLICATION_EVENT_TYPE, DEQUEUE);
- headers.setInt(DEQUEUED_MESSAGE_POSITION, dequeued.position);
- boost::intrusive_ptr<Message> msg(createMessage(headers));
- DeliveryProperties* props = msg->getFrames().getHeaders()->get<DeliveryProperties>(true);
- props->setRoutingKey(dequeued.queue->getName());
- route(msg);
-}
-
-void ReplicatingEventListener::deliverEnqueueMessage(const QueuedMessage& enqueued)
-{
- boost::intrusive_ptr<Message> msg(cloneMessage(*(enqueued.queue), enqueued.payload));
- msg->insertCustomProperty(REPLICATION_TARGET_QUEUE, enqueued.queue->getName());
- msg->insertCustomProperty(REPLICATION_EVENT_TYPE, ENQUEUE);
- msg->insertCustomProperty(QUEUE_MESSAGE_POSITION,enqueued.position);
- route(msg);
-}
-
-void ReplicatingEventListener::route(boost::intrusive_ptr<qpid::broker::Message> msg)
-{
- try {
- if (exchange) {
- DeliverableMessage deliverable(msg);
- exchange->route(deliverable);
- } else if (queue) {
- queue->deliver(msg);
- } else {
- QPID_LOG(error, "Cannot route replication event, neither replication queue nor exchange configured");
- }
- } catch (const std::exception& e) {
- QPID_LOG(error, "Error enqueing replication event: " << e.what());
- }
-}
-
-
-boost::intrusive_ptr<Message> ReplicatingEventListener::createMessage(const FieldTable& headers)
-{
- boost::intrusive_ptr<Message> msg(new Message());
- AMQFrame method((MessageTransferBody(ProtocolVersion(), EMPTY, 0, 0)));
- AMQFrame header((AMQHeaderBody()));
- header.setBof(false);
- header.setEof(true);
- header.setBos(true);
- header.setEos(true);
- msg->getFrames().append(method);
- msg->getFrames().append(header);
- MessageProperties* props = msg->getFrames().getHeaders()->get<MessageProperties>(true);
- props->setApplicationHeaders(headers);
- return msg;
-}
-
-struct AppendingHandler : FrameHandler
-{
- boost::intrusive_ptr<Message> msg;
-
- AppendingHandler(boost::intrusive_ptr<Message> m) : msg(m) {}
-
- void handle(AMQFrame& f)
- {
- msg->getFrames().append(f);
- }
-};
-
-boost::intrusive_ptr<Message> ReplicatingEventListener::cloneMessage(Queue& queue, boost::intrusive_ptr<Message> original)
-{
- boost::intrusive_ptr<Message> copy(new Message());
- AMQFrame method((MessageTransferBody(ProtocolVersion(), EMPTY, 0, 0)));
- AppendingHandler handler(copy);
- handler.handle(method);
-
- //To avoid modifying original headers, create new frame with
- //cloned body:
- AMQFrame header(*original->getFrames().getHeaders());
- header.setBof(false);
- header.setEof(!original->getFrames().hasContent());//if there are any content frames then the header is not the end of the frameset
- header.setBos(true);
- header.setEos(true);
- handler.handle(header);
-
- original->sendContent(queue, handler, std::numeric_limits<int16_t>::max());
- return copy;
-}
-
-Options* ReplicatingEventListener::getOptions()
-{
- return &options;
-}
-
-void ReplicatingEventListener::initialize(Plugin::Target& target)
-{
- Broker* broker = dynamic_cast<broker::Broker*>(&target);
- if (broker) {
- broker->addFinalizer(boost::bind(&ReplicatingEventListener::shutdown, this));
- if (!options.exchange.empty()) {
- if (!options.queue.empty()) {
- QPID_LOG(warning, "Replication queue option ignored as replication exchange has been specified");
- }
- try {
- exchange = broker->getExchanges().declare(options.exchange, options.exchangeType).first;
- } catch (const UnknownExchangeTypeException&) {
- QPID_LOG(error, "Replication disabled due to invalid type: " << options.exchangeType);
- }
- } else if (!options.queue.empty()) {
- if (options.createQueue) {
- queue = broker->getQueues().declare(options.queue).first;
- } else {
- queue = broker->getQueues().find(options.queue);
- }
- if (queue) {
- queue->insertSequenceNumbers(REPLICATION_EVENT_SEQNO);
- } else {
- QPID_LOG(error, "Replication queue named '" << options.queue << "' does not exist; replication plugin disabled.");
- }
- }
- if (queue || exchange) {
- QueueEvents::EventListener callback = boost::bind(&ReplicatingEventListener::handle, this, _1);
- broker->getQueueEvents().registerListener(options.name, callback);
- QPID_LOG(info, "Registered replicating queue event listener");
- }
- }
-}
-
-void ReplicatingEventListener::earlyInitialize(Target&) {}
-void ReplicatingEventListener::shutdown() { queue.reset(); exchange.reset(); }
-
-ReplicatingEventListener::PluginOptions::PluginOptions() : Options("Queue Replication Options"),
- exchangeType("direct"),
- name("replicator"),
- createQueue(false)
-{
- addOptions()
- ("replication-exchange-name", optValue(exchange, "EXCHANGE"), "Exchange to which events for other queues are routed")
- ("replication-exchange-type", optValue(exchangeType, "direct|topic etc"), "Type of exchange to use")
- ("replication-queue", optValue(queue, "QUEUE"), "Queue on which events for other queues are recorded")
- ("replication-listener-name", optValue(name, "NAME"), "name by which to register the replicating event listener")
- ("create-replication-queue", optValue(createQueue), "if set, the replication will be created if it does not exist");
-}
-
-static ReplicatingEventListener plugin;
-
-}} // namespace qpid::replication
diff --git a/cpp/src/qpid/replication/ReplicatingEventListener.h b/cpp/src/qpid/replication/ReplicatingEventListener.h
deleted file mode 100644
index 74418d00e6..0000000000
--- a/cpp/src/qpid/replication/ReplicatingEventListener.h
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef QPID_REPLICATION_REPLICATINGEVENTLISTENER_H
-#define QPID_REPLICATION_REPLICATINGEVENTLISTENER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "qpid/Plugin.h"
-#include "qpid/Options.h"
-#include "qpid/broker/Exchange.h"
-#include "qpid/broker/Message.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/QueueEvents.h"
-#include "qpid/framing/FieldTable.h"
-#include "qpid/framing/SequenceNumber.h"
-
-namespace qpid {
-namespace replication {
-
-/**
- * An event listener plugin that records queue events as messages on a
- * replication queue, from where they can be consumed (e.g. by an
- * inter-broker link to the corresponding QueueReplicationExchange
- * plugin.
- */
-class ReplicatingEventListener : public Plugin
-{
- public:
- Options* getOptions();
- void earlyInitialize(Plugin::Target& target);
- void initialize(Plugin::Target& target);
- void handle(qpid::broker::QueueEvents::Event);
- private:
- struct PluginOptions : public Options
- {
- std::string queue;
- std::string exchange;
- std::string exchangeType;
- std::string name;
- bool createQueue;
-
- PluginOptions();
- };
-
- PluginOptions options;
- qpid::broker::Queue::shared_ptr queue;
- qpid::broker::Exchange::shared_ptr exchange;
-
- void deliverDequeueMessage(const qpid::broker::QueuedMessage& enqueued);
- void deliverEnqueueMessage(const qpid::broker::QueuedMessage& enqueued);
- void route(boost::intrusive_ptr<qpid::broker::Message>);
- void shutdown();
-
- boost::intrusive_ptr<qpid::broker::Message> createMessage(const qpid::framing::FieldTable& headers);
- boost::intrusive_ptr<qpid::broker::Message> cloneMessage(qpid::broker::Queue& queue,
- boost::intrusive_ptr<qpid::broker::Message> original);
-};
-
-}} // namespace qpid::replication
-
-#endif /*!QPID_REPLICATION_REPLICATINGEVENTLISTENER_H*/
diff --git a/cpp/src/qpid/replication/ReplicationExchange.cpp b/cpp/src/qpid/replication/ReplicationExchange.cpp
deleted file mode 100644
index bcb7c7f293..0000000000
--- a/cpp/src/qpid/replication/ReplicationExchange.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/replication/ReplicationExchange.h"
-#include "qpid/replication/constants.h"
-#include "qpid/Plugin.h"
-#include "qpid/broker/Broker.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/QueueRegistry.h"
-#include "qpid/broker/ExchangeRegistry.h"
-#include "qpid/framing/reply_exceptions.h"
-#include "qpid/log/Statement.h"
-#include <boost/bind.hpp>
-
-namespace qpid {
-namespace replication {
-
-using namespace qpid::broker;
-using namespace qpid::framing;
-using namespace qpid::replication::constants;
-
-const std::string SEQUENCE_VALUE("qpid.replication-event.sequence");
-ReplicationExchange::ReplicationExchange(const std::string& name, bool durable,
- const FieldTable& _args,
- QueueRegistry& qr,
- Manageable* parent, Broker* broker)
- : Exchange(name, durable, _args, parent, broker), queues(qr), sequence(args.getAsInt64(SEQUENCE_VALUE)), init(false)
-{
- args.setInt64(SEQUENCE_VALUE, sequence);
- if (mgmtExchange != 0)
- mgmtExchange->set_type(typeName);
-}
-
-std::string ReplicationExchange::getType() const { return typeName; }
-
-void ReplicationExchange::route(Deliverable& msg)
-{
- const FieldTable* args = msg.getMessage().getApplicationHeaders();
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgReceives();
- mgmtExchange->inc_byteReceives(msg.contentSize());
- }
- if (args) {
- int eventType = args->getAsInt(REPLICATION_EVENT_TYPE);
- if (eventType) {
- if (isDuplicate(args)) {
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- }
- return;
- }
- switch (eventType) {
- case ENQUEUE:
- handleEnqueueEvent(args, msg);
- return;
- case DEQUEUE:
- handleDequeueEvent(args, msg);
- return;
- default:
- throw IllegalArgumentException(QPID_MSG("Illegal value for " << REPLICATION_EVENT_TYPE << ": " << eventType));
- }
- }
- } else {
- QPID_LOG(warning, "Dropping unexpected message with no headers");
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- }
- }
-}
-
-void ReplicationExchange::handleEnqueueEvent(const FieldTable* args, Deliverable& msg)
-{
- std::string queueName = args->getAsString(REPLICATION_TARGET_QUEUE);
- Queue::shared_ptr queue = queues.find(queueName);
- if (queue) {
-
- SequenceNumber seqno1(args->getAsInt(QUEUE_MESSAGE_POSITION));
-
- // note that queue will ++ before enqueue.
- if (queue->getPosition() > --seqno1) // test queue.pos < seqnumber
- {
- QPID_LOG(error, "Cannot enqueue replicated message. Destination Queue " << queueName << " ahead of source queue");
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- } else {
- queue->setPosition(seqno1);
-
- msg.getMessage().removeCustomProperty(REPLICATION_TARGET_QUEUE);
- msg.getMessage().removeCustomProperty(REPLICATION_EVENT_SEQNO);
- msg.getMessage().removeCustomProperty(REPLICATION_EVENT_TYPE);
- msg.getMessage().removeCustomProperty(QUEUE_MESSAGE_POSITION);
- msg.deliverTo(queue);
- QPID_LOG(debug, "Enqueued replicated message onto " << queueName);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgRoutes();
- mgmtExchange->inc_byteRoutes( msg.contentSize());
- }
- }
- } else {
- QPID_LOG(error, "Cannot enqueue replicated message. Queue " << queueName << " does not exist");
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- }
- }
-}
-
-void ReplicationExchange::handleDequeueEvent(const FieldTable* args, Deliverable& msg)
-{
- std::string queueName = args->getAsString(REPLICATION_TARGET_QUEUE);
- Queue::shared_ptr queue = queues.find(queueName);
- if (queue) {
- SequenceNumber position(args->getAsInt(DEQUEUED_MESSAGE_POSITION));
- QueuedMessage dequeued;
- if (queue->acquireMessageAt(position, dequeued)) {
- queue->dequeue(0, dequeued);
- QPID_LOG(debug, "Processed replicated 'dequeue' event from " << queueName << " at position " << position);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgRoutes();
- mgmtExchange->inc_byteRoutes(msg.contentSize());
- }
- } else {
- QPID_LOG(warning, "Could not acquire message " << position << " from " << queueName);
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- }
- }
- } else {
- QPID_LOG(error, "Cannot process replicated 'dequeue' event. Queue " << queueName << " does not exist");
- if (mgmtExchange != 0) {
- mgmtExchange->inc_msgDrops();
- mgmtExchange->inc_byteDrops(msg.contentSize());
- }
- }
-}
-
-bool ReplicationExchange::isDuplicate(const FieldTable* args)
-{
- if (!args->get(REPLICATION_EVENT_SEQNO)) return false;
- SequenceNumber seqno(args->getAsInt(REPLICATION_EVENT_SEQNO));
- if (!init) {
- init = true;
- sequence = seqno;
- return false;
- } else if (seqno > sequence) {
- if (seqno - sequence > 1) {
- QPID_LOG(error, "Gap in replication event sequence between: " << sequence << " and " << seqno);
- }
- sequence = seqno;
- return false;
- } else {
- QPID_LOG(info, "Duplicate detected: seqno=" << seqno << " (last seqno=" << sequence << ")");
- return true;
- }
-}
-
-bool ReplicationExchange::bind(Queue::shared_ptr /*queue*/, const std::string& /*routingKey*/, const FieldTable* /*args*/)
-{
- throw NotImplementedException("Replication exchange does not support bind operation");
-}
-
-bool ReplicationExchange::unbind(Queue::shared_ptr /*queue*/, const std::string& /*routingKey*/, const FieldTable* /*args*/)
-{
- throw NotImplementedException("Replication exchange does not support unbind operation");
-}
-
-bool ReplicationExchange::isBound(Queue::shared_ptr /*queue*/, const std::string* const /*routingKey*/, const FieldTable* const /*args*/)
-{
- return false;
-}
-
-const std::string ReplicationExchange::typeName("replication");
-
-
-void ReplicationExchange::encode(Buffer& buffer) const
-{
- args.setInt64(std::string(SEQUENCE_VALUE), sequence);
- Exchange::encode(buffer);
-}
-
-
-struct ReplicationExchangePlugin : Plugin
-{
- Broker* broker;
-
- ReplicationExchangePlugin();
- void earlyInitialize(Plugin::Target& target);
- void initialize(Plugin::Target& target);
- Exchange::shared_ptr create(const std::string& name, bool durable,
- const framing::FieldTable& args,
- management::Manageable* parent,
- qpid::broker::Broker* broker);
-};
-
-ReplicationExchangePlugin::ReplicationExchangePlugin() : broker(0) {}
-
-Exchange::shared_ptr ReplicationExchangePlugin::create(const std::string& name, bool durable,
- const framing::FieldTable& args,
- management::Manageable* parent, qpid::broker::Broker* broker)
-{
- Exchange::shared_ptr e(new ReplicationExchange(name, durable, args, broker->getQueues(), parent, broker));
- return e;
-}
-
-
-void ReplicationExchangePlugin::earlyInitialize(Plugin::Target& target)
-{
- broker = dynamic_cast<broker::Broker*>(&target);
- if (broker) {
- ExchangeRegistry::FactoryFunction f = boost::bind(&ReplicationExchangePlugin::create, this, _1, _2, _3, _4, _5);
- broker->getExchanges().registerType(ReplicationExchange::typeName, f);
- QPID_LOG(info, "Registered replication exchange");
- }
-}
-
-void ReplicationExchangePlugin::initialize(Target&) {}
-
-static ReplicationExchangePlugin exchangePlugin;
-
-}} // namespace qpid::replication
diff --git a/cpp/src/qpid/replication/ReplicationExchange.h b/cpp/src/qpid/replication/ReplicationExchange.h
deleted file mode 100644
index ff0a98c48e..0000000000
--- a/cpp/src/qpid/replication/ReplicationExchange.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef QPID_REPLICATION_REPLICATIONEXCHANGE_H
-#define QPID_REPLICATION_REPLICATIONEXCHANGE_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/broker/Exchange.h"
-#include "qpid/framing/Buffer.h"
-#include "qpid/framing/SequenceNumber.h"
-
-namespace qpid {
-
-namespace broker {
-class QueueRegistry;
-}
-
-namespace replication {
-
-/**
- * A custom exchange plugin that processes incoming messages
- * representing enqueue or dequeue events for particular queues and
- * carries out the corresponding action to replicate that on the local
- * broker.
- */
-class ReplicationExchange : public qpid::broker::Exchange
-{
- public:
- static const std::string typeName;
-
- ReplicationExchange(const std::string& name, bool durable,
- const qpid::framing::FieldTable& args,
- qpid::broker::QueueRegistry& queues,
- qpid::management::Manageable* parent = 0,
- qpid::broker::Broker* broker = 0);
-
- std::string getType() const;
-
- void route(qpid::broker::Deliverable& msg);
-
- bool bind(boost::shared_ptr<broker::Queue> queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
- bool unbind(boost::shared_ptr<broker::Queue> queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
- bool isBound(boost::shared_ptr<broker::Queue> queue, const std::string* const routingKey, const qpid::framing::FieldTable* const args);
- private:
- qpid::broker::QueueRegistry& queues;
- qpid::framing::SequenceNumber sequence;
- bool init;
-
- bool isDuplicate(const qpid::framing::FieldTable* args);
- void handleEnqueueEvent(const qpid::framing::FieldTable* args, qpid::broker::Deliverable& msg);
- void handleDequeueEvent(const qpid::framing::FieldTable* args, qpid::broker::Deliverable& msg);
- void encode(framing::Buffer& buffer) const;
-};
-}} // namespace qpid::replication
-
-#endif /*!QPID_REPLICATION_REPLICATIONEXCHANGE_H*/
diff --git a/cpp/src/qpid/replication/constants.h b/cpp/src/qpid/replication/constants.h
deleted file mode 100644
index c5ba7d3d6a..0000000000
--- a/cpp/src/qpid/replication/constants.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-namespace qpid {
-namespace replication {
-namespace constants {
-
-const std::string REPLICATION_EVENT_TYPE("qpid.replication.type");
-const std::string REPLICATION_EVENT_SEQNO("qpid.replication.seqno");
-const std::string REPLICATION_TARGET_QUEUE("qpid.replication.target_queue");
-const std::string DEQUEUED_MESSAGE_POSITION("qpid.replication.message");
-const std::string QUEUE_MESSAGE_POSITION("qpid.replication.queue.position");
-
-const int ENQUEUE(1);
-const int DEQUEUE(2);
-
-}}}
diff --git a/cpp/src/qpid/store/MessageStorePlugin.cpp b/cpp/src/qpid/store/MessageStorePlugin.cpp
index 20231bf910..c6b0e1a53a 100644
--- a/cpp/src/qpid/store/MessageStorePlugin.cpp
+++ b/cpp/src/qpid/store/MessageStorePlugin.cpp
@@ -249,7 +249,7 @@ MessageStorePlugin::destroy(const broker::PersistableConfig& config)
void
MessageStorePlugin::stage(const boost::intrusive_ptr<broker::PersistableMessage>& msg)
{
- if (msg->getPersistenceId() == 0 && !msg->isContentReleased()) {
+ if (msg->getPersistenceId() == 0) {
provider->second->stage(msg);
}
}
diff --git a/cpp/src/qpid/sys/AsynchIO.h b/cpp/src/qpid/sys/AsynchIO.h
index 41f74f7ed0..b2eaaac9de 100644
--- a/cpp/src/qpid/sys/AsynchIO.h
+++ b/cpp/src/qpid/sys/AsynchIO.h
@@ -76,8 +76,8 @@ protected:
};
struct AsynchIOBufferBase {
- char* const bytes;
- const int32_t byteCount;
+ char* bytes;
+ int32_t byteCount;
int32_t dataStart;
int32_t dataCount;
@@ -134,9 +134,21 @@ public:
BuffersEmptyCallback eCb = 0,
IdleCallback iCb = 0);
public:
+ /*
+ * Size of IO buffers - this is the maximum possible frame size + 1
+ */
+ const static uint32_t MaxBufferSize = 65536;
+
+ /*
+ * Number of IO buffers allocated - I think the code can only use 2 -
+ * 1 for reading and 1 for writing, allocate 4 for safety
+ */
+ const static uint32_t BufferCount = 4;
+
virtual void queueForDeletion() = 0;
virtual void start(boost::shared_ptr<Poller> poller) = 0;
+ virtual void createBuffers(uint32_t size = MaxBufferSize) = 0;
virtual void queueReadBuffer(BufferBase* buff) = 0;
virtual void unread(BufferBase* buff) = 0;
virtual void queueWrite(BufferBase* buff) = 0;
diff --git a/cpp/src/qpid/sys/AsynchIOHandler.cpp b/cpp/src/qpid/sys/AsynchIOHandler.cpp
index 8a485db72d..2e117a3fb7 100644
--- a/cpp/src/qpid/sys/AsynchIOHandler.cpp
+++ b/cpp/src/qpid/sys/AsynchIOHandler.cpp
@@ -33,15 +33,6 @@
namespace qpid {
namespace sys {
-// Buffer definition
-struct Buff : public AsynchIO::BufferBase {
- Buff() :
- AsynchIO::BufferBase(new char[65536], 65536)
- {}
- ~Buff()
- { delete [] bytes;}
-};
-
struct ProtocolTimeoutTask : public sys::TimerTask {
AsynchIOHandler& handler;
std::string id;
@@ -79,7 +70,7 @@ AsynchIOHandler::~AsynchIOHandler() {
delete codec;
}
-void AsynchIOHandler::init(qpid::sys::AsynchIO* a, qpid::sys::Timer& timer, uint32_t maxTime, int numBuffs) {
+void AsynchIOHandler::init(qpid::sys::AsynchIO* a, qpid::sys::Timer& timer, uint32_t maxTime) {
aio = a;
// Start timer for this connection
@@ -87,17 +78,14 @@ void AsynchIOHandler::init(qpid::sys::AsynchIO* a, qpid::sys::Timer& timer, uint
timer.add(timeoutTimerTask);
// Give connection some buffers to use
- for (int i = 0; i < numBuffs; i++) {
- aio->queueReadBuffer(new Buff);
- }
+ aio->createBuffers();
}
void AsynchIOHandler::write(const framing::ProtocolInitiation& data)
{
QPID_LOG(debug, "SENT [" << identifier << "]: INIT(" << data << ")");
AsynchIO::BufferBase* buff = aio->getQueuedBuffer();
- if (!buff)
- buff = new Buff;
+ assert(buff);
framing::Buffer out(buff->bytes, buff->byteCount);
data.encode(out);
buff->dataCount = data.encodedSize();
@@ -244,24 +232,24 @@ void AsynchIOHandler::idle(AsynchIO&){
return;
}
if (codec == 0) return;
- try {
- if (codec->canEncode()) {
- // Try and get a queued buffer if not then construct new one
- AsynchIO::BufferBase* buff = aio->getQueuedBuffer();
- if (!buff) buff = new Buff;
+ if (!codec->canEncode()) {
+ return;
+ }
+ AsynchIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (buff) {
+ try {
size_t encoded=codec->encode(buff->bytes, buff->byteCount);
buff->dataCount = encoded;
aio->queueWrite(buff);
+ if (!codec->isClosed()) {
+ return;
+ }
+ } catch (const std::exception& e) {
+ QPID_LOG(error, e.what());
}
- if (codec->isClosed()) {
- readError = true;
- aio->queueWriteClose();
- }
- } catch (const std::exception& e) {
- QPID_LOG(error, e.what());
- readError = true;
- aio->queueWriteClose();
}
+ readError = true;
+ aio->queueWriteClose();
}
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/AsynchIOHandler.h b/cpp/src/qpid/sys/AsynchIOHandler.h
index 307aad5b85..fd0bc140e5 100644
--- a/cpp/src/qpid/sys/AsynchIOHandler.h
+++ b/cpp/src/qpid/sys/AsynchIOHandler.h
@@ -61,7 +61,7 @@ class AsynchIOHandler : public OutputControl {
public:
QPID_COMMON_EXTERN AsynchIOHandler(const std::string& id, qpid::sys::ConnectionCodec::Factory* f );
QPID_COMMON_EXTERN ~AsynchIOHandler();
- QPID_COMMON_EXTERN void init(AsynchIO* a, Timer& timer, uint32_t maxTime, int numBuffs);
+ QPID_COMMON_EXTERN void init(AsynchIO* a, Timer& timer, uint32_t maxTime);
QPID_COMMON_INLINE_EXTERN void setClient() { isClient = true; }
diff --git a/cpp/src/qpid/sys/SslPlugin.cpp b/cpp/src/qpid/sys/SslPlugin.cpp
index 3b50527c0a..069e97758e 100644
--- a/cpp/src/qpid/sys/SslPlugin.cpp
+++ b/cpp/src/qpid/sys/SslPlugin.cpp
@@ -191,7 +191,7 @@ void SslEstablished(Poller::shared_ptr poller, const qpid::sys::SslSocket& s,
boost::bind(&qpid::sys::ssl::SslHandler::nobuffs, async, _1),
boost::bind(&qpid::sys::ssl::SslHandler::idle, async, _1));
- async->init(aio,timer, maxTime, 4);
+ async->init(aio,timer, maxTime);
aio->start(poller);
}
@@ -247,7 +247,7 @@ void SslMuxProtocolFactory::established(Poller::shared_ptr poller, const Socket&
boost::bind(&AsynchIOHandler::nobuffs, async, _1),
boost::bind(&AsynchIOHandler::idle, async, _1));
- async->init(aio, brokerTimer, maxNegotiateTime, 4);
+ async->init(aio, brokerTimer, maxNegotiateTime);
aio->start(poller);
}
diff --git a/cpp/src/qpid/sys/TCPIOPlugin.cpp b/cpp/src/qpid/sys/TCPIOPlugin.cpp
index 551440f954..ed7cc3748d 100644
--- a/cpp/src/qpid/sys/TCPIOPlugin.cpp
+++ b/cpp/src/qpid/sys/TCPIOPlugin.cpp
@@ -166,7 +166,7 @@ void AsynchIOProtocolFactory::established(Poller::shared_ptr poller, const Socke
boost::bind(&AsynchIOHandler::nobuffs, async, _1),
boost::bind(&AsynchIOHandler::idle, async, _1));
- async->init(aio, brokerTimer, maxNegotiateTime, 4);
+ async->init(aio, brokerTimer, maxNegotiateTime);
aio->start(poller);
}
diff --git a/cpp/src/qpid/sys/epoll/EpollPoller.cpp b/cpp/src/qpid/sys/epoll/EpollPoller.cpp
index dcc9d9181c..c23403c66d 100644
--- a/cpp/src/qpid/sys/epoll/EpollPoller.cpp
+++ b/cpp/src/qpid/sys/epoll/EpollPoller.cpp
@@ -221,8 +221,8 @@ class PollerPrivate {
}
};
- static ReadablePipe alwaysReadable;
- static int alwaysReadableFd;
+ ReadablePipe alwaysReadable;
+ int alwaysReadableFd;
class InterruptHandle: public PollerHandle {
std::queue<PollerHandle*> handles;
@@ -290,6 +290,7 @@ class PollerPrivate {
}
PollerPrivate() :
+ alwaysReadableFd(alwaysReadable.getFD()),
epollFd(::epoll_create(DefaultFds)),
isShutdown(false) {
QPID_POSIX_CHECK(epollFd);
@@ -328,9 +329,6 @@ class PollerPrivate {
}
};
-PollerPrivate::ReadablePipe PollerPrivate::alwaysReadable;
-int PollerPrivate::alwaysReadableFd = alwaysReadable.getFD();
-
void Poller::registerHandle(PollerHandle& handle) {
PollerHandlePrivate& eh = *handle.impl;
ScopedLock<Mutex> l(eh.lock);
diff --git a/cpp/src/qpid/sys/posix/AsynchIO.cpp b/cpp/src/qpid/sys/posix/AsynchIO.cpp
index 01ff8b6bfa..31355627cd 100644
--- a/cpp/src/qpid/sys/posix/AsynchIO.cpp
+++ b/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -40,6 +40,7 @@
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/shared_array.hpp>
namespace qpid {
namespace sys {
@@ -239,6 +240,7 @@ public:
virtual void queueForDeletion();
virtual void start(Poller::shared_ptr poller);
+ virtual void createBuffers(uint32_t size);
virtual void queueReadBuffer(BufferBase* buff);
virtual void unread(BufferBase* buff);
virtual void queueWrite(BufferBase* buff);
@@ -270,6 +272,8 @@ private:
const Socket& socket;
std::deque<BufferBase*> bufferQueue;
std::deque<BufferBase*> writeQueue;
+ std::vector<BufferBase> buffers;
+ boost::shared_array<char> bufferMemory;
bool queuedClose;
/**
* This flag is used to detect and handle concurrency between
@@ -309,15 +313,7 @@ AsynchIO::AsynchIO(const Socket& s,
s.setNonblocking();
}
-struct deleter
-{
- template <typename T>
- void operator()(T *ptr){ delete ptr;}
-};
-
AsynchIO::~AsynchIO() {
- std::for_each( bufferQueue.begin(), bufferQueue.end(), deleter());
- std::for_each( writeQueue.begin(), writeQueue.end(), deleter());
}
void AsynchIO::queueForDeletion() {
@@ -328,6 +324,19 @@ void AsynchIO::start(Poller::shared_ptr poller) {
DispatchHandle::startWatch(poller);
}
+void AsynchIO::createBuffers(uint32_t size) {
+ // Allocate all the buffer memory at once
+ bufferMemory.reset(new char[size*BufferCount]);
+
+ // Create the Buffer structs in a vector
+ // And push into the buffer queue
+ buffers.reserve(BufferCount);
+ for (uint32_t i = 0; i < BufferCount; i++) {
+ buffers.push_back(BufferBase(&bufferMemory[i*size], size));
+ queueReadBuffer(&buffers[i]);
+ }
+}
+
void AsynchIO::queueReadBuffer(BufferBase* buff) {
assert(buff);
buff->dataStart = 0;
diff --git a/cpp/src/qpid/sys/posix/SystemInfo.cpp b/cpp/src/qpid/sys/posix/SystemInfo.cpp
index 2b1bbb97df..cfd2c64aee 100755
--- a/cpp/src/qpid/sys/posix/SystemInfo.cpp
+++ b/cpp/src/qpid/sys/posix/SystemInfo.cpp
@@ -91,7 +91,7 @@ void SystemInfo::getLocalIpAddresses (uint16_t port,
// * The scope id is illegal in URL syntax
// * Clients won't be able to use a link local address
// without adding their own (potentially different) scope id
- sockaddr_in6* sa6 = (sockaddr_in6*)(ifap->ifa_addr);
+ sockaddr_in6* sa6 = (sockaddr_in6*)((void*)ifap->ifa_addr);
if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) break;
// Fallthrough
}
diff --git a/cpp/src/qpid/sys/ssl/SslHandler.cpp b/cpp/src/qpid/sys/ssl/SslHandler.cpp
index 8613059f28..eeb8c26a76 100644
--- a/cpp/src/qpid/sys/ssl/SslHandler.cpp
+++ b/cpp/src/qpid/sys/ssl/SslHandler.cpp
@@ -33,15 +33,6 @@ namespace sys {
namespace ssl {
-// Buffer definition
-struct Buff : public SslIO::BufferBase {
- Buff() :
- SslIO::BufferBase(new char[65536], 65536)
- {}
- ~Buff()
- { delete [] bytes;}
-};
-
struct ProtocolTimeoutTask : public sys::TimerTask {
SslHandler& handler;
std::string id;
@@ -78,7 +69,7 @@ SslHandler::~SslHandler() {
delete codec;
}
-void SslHandler::init(SslIO* a, Timer& timer, uint32_t maxTime, int numBuffs) {
+void SslHandler::init(SslIO* a, Timer& timer, uint32_t maxTime) {
aio = a;
// Start timer for this connection
@@ -86,17 +77,14 @@ void SslHandler::init(SslIO* a, Timer& timer, uint32_t maxTime, int numBuffs) {
timer.add(timeoutTimerTask);
// Give connection some buffers to use
- for (int i = 0; i < numBuffs; i++) {
- aio->queueReadBuffer(new Buff);
- }
+ aio->createBuffers();
}
void SslHandler::write(const framing::ProtocolInitiation& data)
{
QPID_LOG(debug, "SENT [" << identifier << "]: INIT(" << data << ")");
SslIO::BufferBase* buff = aio->getQueuedBuffer();
- if (!buff)
- buff = new Buff;
+ assert(buff);
framing::Buffer out(buff->bytes, buff->byteCount);
data.encode(out);
buff->dataCount = data.encodedSize();
@@ -205,10 +193,11 @@ void SslHandler::idle(SslIO&){
return;
}
if (codec == 0) return;
- if (codec->canEncode()) {
- // Try and get a queued buffer if not then construct new one
- SslIO::BufferBase* buff = aio->getQueuedBuffer();
- if (!buff) buff = new Buff;
+ if (!codec->canEncode()) {
+ return;
+ }
+ SslIO::BufferBase* buff = aio->getQueuedBuffer();
+ if (buff) {
size_t encoded=codec->encode(buff->bytes, buff->byteCount);
buff->dataCount = encoded;
aio->queueWrite(buff);
diff --git a/cpp/src/qpid/sys/ssl/SslHandler.h b/cpp/src/qpid/sys/ssl/SslHandler.h
index 74df2b7fb0..14814b0281 100644
--- a/cpp/src/qpid/sys/ssl/SslHandler.h
+++ b/cpp/src/qpid/sys/ssl/SslHandler.h
@@ -60,7 +60,7 @@ class SslHandler : public OutputControl {
public:
SslHandler(std::string id, ConnectionCodec::Factory* f, bool nodict);
~SslHandler();
- void init(SslIO* a, Timer& timer, uint32_t maxTime, int numBuffs);
+ void init(SslIO* a, Timer& timer, uint32_t maxTime);
void setClient() { isClient = true; }
diff --git a/cpp/src/qpid/sys/ssl/SslIo.cpp b/cpp/src/qpid/sys/ssl/SslIo.cpp
index 789c205ead..bbfb703170 100644
--- a/cpp/src/qpid/sys/ssl/SslIo.cpp
+++ b/cpp/src/qpid/sys/ssl/SslIo.cpp
@@ -197,15 +197,7 @@ SslIO::SslIO(const SslSocket& s,
s.setNonblocking();
}
-struct deleter
-{
- template <typename T>
- void operator()(T *ptr){ delete ptr;}
-};
-
SslIO::~SslIO() {
- std::for_each( bufferQueue.begin(), bufferQueue.end(), deleter());
- std::for_each( writeQueue.begin(), writeQueue.end(), deleter());
}
void SslIO::queueForDeletion() {
@@ -216,6 +208,19 @@ void SslIO::start(Poller::shared_ptr poller) {
DispatchHandle::startWatch(poller);
}
+void SslIO::createBuffers(uint32_t size) {
+ // Allocate all the buffer memory at once
+ bufferMemory.reset(new char[size*BufferCount]);
+
+ // Create the Buffer structs in a vector
+ // And push into the buffer queue
+ buffers.reserve(BufferCount);
+ for (uint32_t i = 0; i < BufferCount; i++) {
+ buffers.push_back(BufferBase(&bufferMemory[i*size], size));
+ queueReadBuffer(&buffers[i]);
+ }
+}
+
void SslIO::queueReadBuffer(BufferBase* buff) {
assert(buff);
buff->dataStart = 0;
diff --git a/cpp/src/qpid/sys/ssl/SslIo.h b/cpp/src/qpid/sys/ssl/SslIo.h
index b795594cd9..f3112bfa65 100644
--- a/cpp/src/qpid/sys/ssl/SslIo.h
+++ b/cpp/src/qpid/sys/ssl/SslIo.h
@@ -25,6 +25,7 @@
#include "qpid/sys/SecuritySettings.h"
#include <boost/function.hpp>
+#include <boost/shared_array.hpp>
#include <deque>
namespace qpid {
@@ -87,8 +88,8 @@ private:
};
struct SslIOBufferBase {
- char* const bytes;
- const int32_t byteCount;
+ char* bytes;
+ int32_t byteCount;
int32_t dataStart;
int32_t dataCount;
@@ -127,7 +128,9 @@ public:
typedef boost::function1<void, SslIO&> IdleCallback;
typedef boost::function1<void, SslIO&> RequestCallback;
-
+ SslIO(const SslSocket& s,
+ ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
+ ClosedCallback cCb = 0, BuffersEmptyCallback eCb = 0, IdleCallback iCb = 0);
private:
ReadCallback readCallback;
EofCallback eofCallback;
@@ -138,6 +141,8 @@ private:
const SslSocket& socket;
std::deque<BufferBase*> bufferQueue;
std::deque<BufferBase*> writeQueue;
+ std::vector<BufferBase> buffers;
+ boost::shared_array<char> bufferMemory;
bool queuedClose;
/**
* This flag is used to detect and handle concurrency between
@@ -148,12 +153,21 @@ private:
volatile bool writePending;
public:
- SslIO(const SslSocket& s,
- ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb,
- ClosedCallback cCb = 0, BuffersEmptyCallback eCb = 0, IdleCallback iCb = 0);
+ /*
+ * Size of IO buffers - this is the maximum possible frame size + 1
+ */
+ const static uint32_t MaxBufferSize = 65536;
+
+ /*
+ * Number of IO buffers allocated - I think the code can only use 2 -
+ * 1 for reading and 1 for writing, allocate 4 for safety
+ */
+ const static uint32_t BufferCount = 4;
+
void queueForDeletion();
void start(qpid::sys::Poller::shared_ptr poller);
+ void createBuffers(uint32_t size = MaxBufferSize);
void queueReadBuffer(BufferBase* buff);
void unread(BufferBase* buff);
void queueWrite(BufferBase* buff);
diff --git a/cpp/src/qpid/sys/windows/AsynchIO.cpp b/cpp/src/qpid/sys/windows/AsynchIO.cpp
index ae53414e52..355acbe0e6 100644
--- a/cpp/src/qpid/sys/windows/AsynchIO.cpp
+++ b/cpp/src/qpid/sys/windows/AsynchIO.cpp
@@ -40,6 +40,7 @@
#include <windows.h>
#include <boost/bind.hpp>
+#include <boost/shared_array.hpp>
namespace {
@@ -252,6 +253,7 @@ public:
/// Take any actions needed to prepare for working with the poller.
virtual void start(Poller::shared_ptr poller);
+ virtual void createBuffers(uint32_t size);
virtual void queueReadBuffer(BufferBase* buff);
virtual void unread(BufferBase* buff);
virtual void queueWrite(BufferBase* buff);
@@ -286,6 +288,8 @@ private:
* access to the buffer queue and write queue.
*/
Mutex bufferQueueLock;
+ std::vector<BufferBase> buffers;
+ boost::shared_array<char> bufferMemory;
// Number of outstanding I/O operations.
volatile LONG opsInProgress;
@@ -385,15 +389,7 @@ AsynchIO::AsynchIO(const Socket& s,
working(false) {
}
-struct deleter
-{
- template <typename T>
- void operator()(T *ptr){ delete ptr;}
-};
-
AsynchIO::~AsynchIO() {
- std::for_each( bufferQueue.begin(), bufferQueue.end(), deleter());
- std::for_each( writeQueue.begin(), writeQueue.end(), deleter());
}
void AsynchIO::queueForDeletion() {
@@ -426,6 +422,19 @@ void AsynchIO::start(Poller::shared_ptr poller0) {
startReading();
}
+void AsynchIO::createBuffers(uint32_t size) {
+ // Allocate all the buffer memory at once
+ bufferMemory.reset(new char[size*BufferCount]);
+
+ // Create the Buffer structs in a vector
+ // And push into the buffer queue
+ buffers.reserve(BufferCount);
+ for (uint32_t i = 0; i < BufferCount; i++) {
+ buffers.push_back(BufferBase(&bufferMemory[i*size], size));
+ queueReadBuffer(&buffers[i]);
+ }
+}
+
void AsynchIO::queueReadBuffer(AsynchIO::BufferBase* buff) {
assert(buff);
buff->dataStart = 0;
diff --git a/cpp/src/qpid/sys/windows/SslAsynchIO.cpp b/cpp/src/qpid/sys/windows/SslAsynchIO.cpp
index 25cc94b290..d263f00ab3 100644
--- a/cpp/src/qpid/sys/windows/SslAsynchIO.cpp
+++ b/cpp/src/qpid/sys/windows/SslAsynchIO.cpp
@@ -55,7 +55,7 @@ namespace {
* the frame layer for writing into.
*/
struct SslIoBuff : public qpid::sys::AsynchIO::BufferBase {
- std::auto_ptr<qpid::sys::AsynchIO::BufferBase> aioBuff;
+ qpid::sys::AsynchIO::BufferBase* aioBuff;
SslIoBuff (qpid::sys::AsynchIO::BufferBase *base,
const SecPkgContext_StreamSizes &sizes)
@@ -66,7 +66,6 @@ namespace {
{}
~SslIoBuff() {}
- qpid::sys::AsynchIO::BufferBase* release() { return aioBuff.release(); }
};
}
@@ -101,10 +100,7 @@ SslAsynchIO::SslAsynchIO(const qpid::sys::Socket& s,
}
SslAsynchIO::~SslAsynchIO() {
- if (leftoverPlaintext) {
- delete leftoverPlaintext;
- leftoverPlaintext = 0;
- }
+ leftoverPlaintext = 0;
}
void SslAsynchIO::queueForDeletion() {
@@ -121,6 +117,10 @@ void SslAsynchIO::start(qpid::sys::Poller::shared_ptr poller) {
startNegotiate();
}
+void SslAsynchIO::createBuffers(uint32_t size) {
+ aio->createBuffers(size);
+}
+
void SslAsynchIO::queueReadBuffer(AsynchIO::BufferBase* buff) {
aio->queueReadBuffer(buff);
}
@@ -148,7 +148,7 @@ void SslAsynchIO::queueWrite(AsynchIO::BufferBase* buff) {
// encoding was working on, and adjusting counts for, the SslIoBuff.
// Update the count of the original BufferBase before handing off to
// the I/O layer.
- buff = sslBuff->release();
+ buff = sslBuff->aioBuff;
SecBuffer buffs[4];
buffs[0].cbBuffer = schSizes.cbHeader;
buffs[0].BufferType = SECBUFFER_STREAM_HEADER;
diff --git a/cpp/src/qpid/sys/windows/SslAsynchIO.h b/cpp/src/qpid/sys/windows/SslAsynchIO.h
index edec081ced..e9d9e8d629 100644
--- a/cpp/src/qpid/sys/windows/SslAsynchIO.h
+++ b/cpp/src/qpid/sys/windows/SslAsynchIO.h
@@ -70,6 +70,7 @@ public:
virtual void queueForDeletion();
virtual void start(qpid::sys::Poller::shared_ptr poller);
+ virtual void createBuffers(uint32_t size);
virtual void queueReadBuffer(BufferBase* buff);
virtual void unread(BufferBase* buff);
virtual void queueWrite(BufferBase* buff);
diff --git a/cpp/src/qpid/sys/windows/Time.cpp b/cpp/src/qpid/sys/windows/Time.cpp
index 25c50819cd..700a25391f 100644
--- a/cpp/src/qpid/sys/windows/Time.cpp
+++ b/cpp/src/qpid/sys/windows/Time.cpp
@@ -20,10 +20,12 @@
*/
#include "qpid/sys/Time.h"
+#include <cmath>
#include <ostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread_time.hpp>
#include <windows.h>
+#include <time.h>
using namespace boost::posix_time;
@@ -33,8 +35,16 @@ namespace {
// more or less. Keep track of the start value and the conversion factor to
// seconds.
bool timeInitialized = false;
-LARGE_INTEGER start;
-double freq = 1.0;
+LARGE_INTEGER start_hpc;
+double hpc_freq = 1.0;
+
+double start_time;
+
+/// Static constant to remove time skew between FILETIME and POSIX
+/// time. POSIX and Win32 use different epochs (Jan. 1, 1970 v.s.
+/// Jan. 1, 1601). The following constant defines the difference
+/// in 100ns ticks.
+const DWORDLONG FILETIME_to_timval_skew = 0x19db1ded53e8000;
}
@@ -114,23 +124,59 @@ void outputFormattedNow(std::ostream& o) {
}
void outputHiresNow(std::ostream& o) {
+ ::time_t tv_sec;
+ ::tm timeinfo;
+ char time_string[100];
+
if (!timeInitialized) {
- start.QuadPart = 0;
+ // To start, get the current time from FILETIME which includes
+ // sub-second resolution. However, since FILETIME is updated a bit
+ // "bumpy" every 15 msec or so, future time displays will be the
+ // starting FILETIME plus a delta based on the high-resolution
+ // performance counter.
+ FILETIME file_time;
+ ULARGE_INTEGER start_usec;
+ ::GetSystemTimeAsFileTime(&file_time); // This is in 100ns units
+ start_usec.LowPart = file_time.dwLowDateTime;
+ start_usec.HighPart = file_time.dwHighDateTime;
+ start_usec.QuadPart -= FILETIME_to_timval_skew;
+ start_usec.QuadPart /= 10; // Convert 100ns to usec
+ tv_sec = (time_t)(start_usec.QuadPart / (1000 * 1000));
+ long tv_usec = (long)(start_usec.QuadPart % (1000 * 1000));
+ start_time = static_cast<double>(tv_sec);
+ start_time += tv_usec / 1000000.0;
+
+ start_hpc.QuadPart = 0;
LARGE_INTEGER iFreq;
iFreq.QuadPart = 1;
- QueryPerformanceCounter(&start);
+ QueryPerformanceCounter(&start_hpc);
QueryPerformanceFrequency(&iFreq);
- freq = static_cast<double>(iFreq.QuadPart);
+ hpc_freq = static_cast<double>(iFreq.QuadPart);
timeInitialized = true;
}
- LARGE_INTEGER iNow;
- iNow.QuadPart = 0;
- QueryPerformanceCounter(&iNow);
- iNow.QuadPart -= start.QuadPart;
- if (iNow.QuadPart < 0)
- iNow.QuadPart = 0;
- double now = static_cast<double>(iNow.QuadPart);
- now /= freq; // now is seconds after this
- o << std::fixed << std::setprecision(8) << std::setw(16) << std::setfill('0') << now << "s ";
+ LARGE_INTEGER hpc_now;
+ hpc_now.QuadPart = 0;
+ QueryPerformanceCounter(&hpc_now);
+ hpc_now.QuadPart -= start_hpc.QuadPart;
+ if (hpc_now.QuadPart < 0)
+ hpc_now.QuadPart = 0;
+ double now = static_cast<double>(hpc_now.QuadPart);
+ now /= hpc_freq; // now is seconds after this
+ double fnow = start_time + now;
+ double usec, sec;
+ usec = modf(fnow, &sec);
+ tv_sec = static_cast<time_t>(sec);
+#ifdef _MSC_VER
+ ::localtime_s(&timeinfo, &tv_sec);
+#else
+ timeinfo = *(::localtime(&tv_sec));
+#endif
+ ::strftime(time_string, 100,
+ "%Y-%m-%d %H:%M:%S",
+ &timeinfo);
+ // No way to set "max field width" to cleanly output the double usec so
+ // convert it back to integral number of usecs and print that.
+ unsigned long i_usec = usec * 1000 * 1000;
+ o << time_string << "." << std::setw(6) << std::setfill('0') << i_usec << " ";
}
}}
diff --git a/cpp/src/qpid/xml/XmlExchange.cpp b/cpp/src/qpid/xml/XmlExchange.cpp
index 3fb11394d0..f88acb04ee 100644
--- a/cpp/src/qpid/xml/XmlExchange.cpp
+++ b/cpp/src/qpid/xml/XmlExchange.cpp
@@ -27,6 +27,7 @@
#include "qpid/log/Statement.h"
#include "qpid/broker/FedOps.h"
+#include "qpid/broker/MapHandler.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/framing/FieldValue.h"
#include "qpid/framing/reply_exceptions.h"
@@ -198,7 +199,52 @@ bool XmlExchange::unbind(Queue::shared_ptr queue, const std::string& bindingKey,
}
}
-bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args, bool parse_message_content)
+namespace {
+class DefineExternals : public MapHandler
+{
+ public:
+ DefineExternals(DynamicContext* c) : context(c) { assert(context); }
+ void handleUint8(const MapHandler::CharSequence& key, uint8_t value) { process(std::string(key.data, key.size), (int) value); }
+ void handleUint16(const MapHandler::CharSequence& key, uint16_t value) { process(std::string(key.data, key.size), (int) value); }
+ void handleUint32(const MapHandler::CharSequence& key, uint32_t value) { process(std::string(key.data, key.size), (int) value); }
+ void handleUint64(const MapHandler::CharSequence& key, uint64_t value) { process(std::string(key.data, key.size), (int) value); }
+ void handleInt8(const MapHandler::CharSequence& key, int8_t value) { process(std::string(key.data, key.size), (int) value); }
+ void handleInt16(const MapHandler::CharSequence& key, int16_t value) { process(std::string(key.data, key.size), (int) value); }
+ void handleInt32(const MapHandler::CharSequence& key, int32_t value) { process(std::string(key.data, key.size), (int) value); }
+ void handleInt64(const MapHandler::CharSequence& key, int64_t value) { process(std::string(key.data, key.size), (int) value); }
+ void handleFloat(const MapHandler::CharSequence& key, float value) { process(std::string(key.data, key.size), value); }
+ void handleDouble(const MapHandler::CharSequence& key, double value) { process(std::string(key.data, key.size), value); }
+ void handleString(const MapHandler::CharSequence& key, const MapHandler::CharSequence& value, const MapHandler::CharSequence& /*encoding*/)
+ {
+ process(std::string(key.data, key.size), std::string(value.data, value.size));
+ }
+ void handleVoid(const MapHandler::CharSequence&) {}
+ private:
+ void process(const std::string& key, double value)
+ {
+ QPID_LOG(trace, "XmlExchange, external variable (double): " << key << " = " << value);
+ Item::Ptr item = context->getItemFactory()->createDouble(value, context);
+ context->setExternalVariable(X(key.c_str()), item);
+ }
+ void process(const std::string& key, int value)
+ {
+ QPID_LOG(trace, "XmlExchange, external variable (int):" << key << " = " << value);
+ Item::Ptr item = context->getItemFactory()->createInteger(value, context);
+ context->setExternalVariable(X(key.c_str()), item);
+ }
+ void process(const std::string& key, const std::string& value)
+ {
+ QPID_LOG(trace, "XmlExchange, external variable (string):" << key << " = " << value);
+ Item::Ptr item = context->getItemFactory()->createString(X(value.c_str()), context);
+ context->setExternalVariable(X(key.c_str()), item);
+ }
+
+ DynamicContext* context;
+};
+
+}
+
+bool XmlExchange::matches(Query& query, Deliverable& msg, bool parse_message_content)
{
std::string msgContent;
@@ -212,7 +258,7 @@ bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::F
if (parse_message_content) {
- msg.getMessage().getFrames().getContent(msgContent);
+ msgContent = msg.getMessage().getContent();
QPID_LOG(trace, "matches: message content is [" << msgContent << "]");
@@ -231,28 +277,8 @@ bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::F
}
}
- if (args) {
- FieldTable::ValueMap::const_iterator v = args->begin();
- for(; v != args->end(); ++v) {
-
- if (v->second->convertsTo<double>()) {
- QPID_LOG(trace, "XmlExchange, external variable (double): " << v->first << " = " << v->second->get<double>());
- Item::Ptr value = context->getItemFactory()->createDouble(v->second->get<double>(), context.get());
- context->setExternalVariable(X(v->first.c_str()), value);
- }
- else if (v->second->convertsTo<int>()) {
- QPID_LOG(trace, "XmlExchange, external variable (int):" << v->first << " = " << v->second->getData().getInt());
- Item::Ptr value = context->getItemFactory()->createInteger(v->second->get<int>(), context.get());
- context->setExternalVariable(X(v->first.c_str()), value);
- }
- else if (v->second->convertsTo<std::string>()) {
- QPID_LOG(trace, "XmlExchange, external variable (string):" << v->first << " = " << v->second->getData().getString().c_str());
- Item::Ptr value = context->getItemFactory()->createString(X(v->second->get<std::string>().c_str()), context.get());
- context->setExternalVariable(X(v->first.c_str()), value);
- }
-
- }
- }
+ DefineExternals f(context.get());
+ msg.getMessage().processProperties(f);
Result result = query->execute(context.get());
#ifdef XQ_EFFECTIVE_BOOLEAN_VALUE_HPP
@@ -286,7 +312,6 @@ bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::F
void XmlExchange::route(Deliverable& msg)
{
const std::string& routingKey = msg.getMessage().getRoutingKey();
- const FieldTable* args = msg.getMessage().getApplicationHeaders();
PreRoute pr(msg, this);
try {
XmlBinding::vector::ConstPtr p;
@@ -298,7 +323,7 @@ void XmlExchange::route(Deliverable& msg)
}
for (std::vector<XmlBinding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++) {
- if (matches((*i)->xquery, msg, args, (*i)->parse_message_content)) {
+ if (matches((*i)->xquery, msg, (*i)->parse_message_content)) {
b->push_back(*i);
}
}
diff --git a/cpp/src/qpid/xml/XmlExchange.h b/cpp/src/qpid/xml/XmlExchange.h
index 1d4723f9c4..7b04781ad5 100644
--- a/cpp/src/qpid/xml/XmlExchange.h
+++ b/cpp/src/qpid/xml/XmlExchange.h
@@ -65,7 +65,7 @@ class XmlExchange : public virtual Exchange {
qpid::sys::RWlock lock;
- bool matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args, bool parse_message_content);
+ bool matches(Query& query, Deliverable& msg, bool parse_message_content);
public:
static const std::string typeName;
diff --git a/cpp/src/replication.mk b/cpp/src/replication.mk
deleted file mode 100644
index e5da32f88b..0000000000
--- a/cpp/src/replication.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-# Make file for building two plugins for asynchronously replicating
-# queues.
-
-dmoduleexec_LTLIBRARIES += replicating_listener.la replication_exchange.la
-
-# a queue event listener plugin that creates messages on a replication
-# queue corresponding to enqueue and dequeue events:
-replicating_listener_la_SOURCES = \
- qpid/replication/constants.h \
- qpid/replication/ReplicatingEventListener.cpp \
- qpid/replication/ReplicatingEventListener.h
-
-replicating_listener_la_LIBADD = libqpidbroker.la
-if SUNOS
- replicating_listener_la_LIBADD += libqpidcommon.la -lboost_program_options -luuid $(SUNCC_RUNTIME_LIBS)
-endif
-replicating_listener_la_LDFLAGS = $(PLUGINLDFLAGS)
-
-# a custom exchange plugin that allows an exchange to be created that
-# can process the messages from a replication queue (populated on the
-# source system by the replicating listener plugin above) and take the
-# corresponding action on the local queues
-replication_exchange_la_SOURCES = \
- qpid/replication/constants.h \
- qpid/replication/ReplicationExchange.cpp \
- qpid/replication/ReplicationExchange.h
-
-replication_exchange_la_LIBADD = libqpidbroker.la
-
-if SUNOS
- replication_exchange_la_LIBADD += libqpidcommon.la -lboost_program_options $(SUNCC_RUNTIME_LIBS) -luuid
-endif
-replication_exchange_la_LDFLAGS = $(PLUGINLDFLAGS)
-
diff --git a/cpp/src/tests/CMakeLists.txt b/cpp/src/tests/CMakeLists.txt
index 29dfe3634f..be7864fcb4 100644
--- a/cpp/src/tests/CMakeLists.txt
+++ b/cpp/src/tests/CMakeLists.txt
@@ -126,6 +126,7 @@ set(unit_tests_to_build
ExchangeTest
HeadersExchangeTest
MessageTest
+ QueueDepth
QueueRegistryTest
QueuePolicyTest
QueueFlowLimitTest
@@ -135,16 +136,12 @@ set(unit_tests_to_build
TimerTest
TopicExchangeTest
TxBufferTest
- TxPublishTest
- MessageBuilderTest
ManagementTest
MessageReplayTracker
ConsoleTest
- QueueEvents
ProxyTest
RetryList
FrameDecoder
- ReplicationTest
ClientMessageTest
PollableCondition
Variant
@@ -165,10 +162,6 @@ remember_location(unit_test)
add_library (shlibtest MODULE shlibtest.cpp)
-if (BUILD_CLUSTER)
- include (cluster.cmake)
-endif (BUILD_CLUSTER)
-
# FIXME aconway 2009-11-30: enable SSL
#if SSL
#include ssl.mk
diff --git a/cpp/src/tests/ClientSessionTest.cpp b/cpp/src/tests/ClientSessionTest.cpp
index 1905219bf2..1f07d2b83f 100644
--- a/cpp/src/tests/ClientSessionTest.cpp
+++ b/cpp/src/tests/ClientSessionTest.cpp
@@ -621,7 +621,7 @@ QPID_AUTO_TEST_CASE(testQueueDeleted)
fix.session.queueDeclare(arg::queue="my-queue");
LocalQueue queue;
fix.subs.subscribe(queue, "my-queue");
-
+
ScopedSuppressLogging sl;
fix.session.queueDelete(arg::queue="my-queue");
BOOST_CHECK_THROW(queue.get(1*qpid::sys::TIME_SEC), qpid::framing::ResourceDeletedException);
diff --git a/cpp/src/tests/DeliveryRecordTest.cpp b/cpp/src/tests/DeliveryRecordTest.cpp
index fb7bd2f727..c83bd9a6a4 100644
--- a/cpp/src/tests/DeliveryRecordTest.cpp
+++ b/cpp/src/tests/DeliveryRecordTest.cpp
@@ -49,7 +49,7 @@ QPID_AUTO_TEST_CASE(testSort)
list<DeliveryRecord> records;
for (list<SequenceNumber>::iterator i = ids.begin(); i != ids.end(); i++) {
- DeliveryRecord r(QueuedMessage(0), Queue::shared_ptr(), "tag", Consumer::shared_ptr(), false, false, false);
+ DeliveryRecord r(QueueCursor(CONSUMER), framing::SequenceNumber(), Queue::shared_ptr(), "tag", Consumer::shared_ptr(), false, false, false);
r.setId(*i);
records.push_back(r);
}
diff --git a/cpp/src/tests/ExchangeTest.cpp b/cpp/src/tests/ExchangeTest.cpp
index 66a16b9178..4f18b91b5a 100644
--- a/cpp/src/tests/ExchangeTest.cpp
+++ b/cpp/src/tests/ExchangeTest.cpp
@@ -35,7 +35,6 @@
using std::string;
-using boost::intrusive_ptr;
using namespace qpid::broker;
using namespace qpid::framing;
using namespace qpid::sys;
@@ -62,11 +61,9 @@ QPID_AUTO_TEST_CASE(testMe)
queue.reset();
queue2.reset();
- intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "abc", false, "id"));
- DeliverableMessage msg(msgPtr);
+ DeliverableMessage msg(MessageUtils::createMessage("exchange", "abc"), 0);
topic.route(msg);
direct.route(msg);
-
}
QPID_AUTO_TEST_CASE(testIsBound)
@@ -170,16 +167,6 @@ QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
BOOST_CHECK_EQUAL(string("direct"), response.first->getType());
}
-intrusive_ptr<Message> cmessage(std::string exchange, std::string routingKey) {
- intrusive_ptr<Message> msg(new Message());
- AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
- AMQFrame header((AMQHeaderBody()));
- msg->getFrames().append(method);
- msg->getFrames().append(header);
- msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
- return msg;
-}
-
QPID_AUTO_TEST_CASE(testSequenceOptions)
{
FieldTable args;
@@ -189,46 +176,35 @@ QPID_AUTO_TEST_CASE(testSequenceOptions)
{
DirectExchange direct("direct1", false, args);
- intrusive_ptr<Message> msg1 = cmessage("e", "abc");
- intrusive_ptr<Message> msg2 = cmessage("e", "abc");
- intrusive_ptr<Message> msg3 = cmessage("e", "abc");
-
- DeliverableMessage dmsg1(msg1);
- DeliverableMessage dmsg2(msg2);
- DeliverableMessage dmsg3(msg3);
+ DeliverableMessage msg1(MessageUtils::createMessage("e", "abc"), 0);
+ DeliverableMessage msg2(MessageUtils::createMessage("e", "abc"), 0);
+ DeliverableMessage msg3(MessageUtils::createMessage("e", "abc"), 0);
- direct.route(dmsg1);
- direct.route(dmsg2);
- direct.route(dmsg3);
+ direct.route(msg1);
+ direct.route(msg2);
+ direct.route(msg3);
- BOOST_CHECK_EQUAL(1, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
- BOOST_CHECK_EQUAL(2, msg2->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
- BOOST_CHECK_EQUAL(3, msg3->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ BOOST_CHECK_EQUAL(1, msg1.getMessage().getAnnotation("qpid.msg_sequence").asInt64());
+ BOOST_CHECK_EQUAL(2, msg2.getMessage().getAnnotation("qpid.msg_sequence").asInt64());
+ BOOST_CHECK_EQUAL(3, msg3.getMessage().getAnnotation("qpid.msg_sequence").asInt64());
FanOutExchange fanout("fanout1", false, args);
HeadersExchange header("headers1", false, args);
TopicExchange topic ("topic1", false, args);
// check other exchanges, that they preroute
- intrusive_ptr<Message> msg4 = cmessage("e", "abc");
- intrusive_ptr<Message> msg5 = cmessage("e", "abc");
+ DeliverableMessage msg4(MessageUtils::createMessage("e", "abc"), 0);
+ DeliverableMessage msg5(MessageUtils::createMessage("e", "abc"), 0);
+ DeliverableMessage msg6(MessageUtils::createMessage("e", "abc"), 0);
- // Need at least empty header for the HeadersExchange to route at all
- msg5->insertCustomProperty("", "");
- intrusive_ptr<Message> msg6 = cmessage("e", "abc");
+ fanout.route(msg4);
+ BOOST_CHECK_EQUAL(1, msg4.getMessage().getAnnotation("qpid.msg_sequence").asInt64());
- DeliverableMessage dmsg4(msg4);
- DeliverableMessage dmsg5(msg5);
- DeliverableMessage dmsg6(msg6);
+ header.route(msg5);
+ BOOST_CHECK_EQUAL(1, msg5.getMessage().getAnnotation("qpid.msg_sequence").asInt64());
- fanout.route(dmsg4);
- BOOST_CHECK_EQUAL(1, msg4->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
-
- header.route(dmsg5);
- BOOST_CHECK_EQUAL(1, msg5->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
-
- topic.route(dmsg6);
- BOOST_CHECK_EQUAL(1, msg6->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ topic.route(msg6);
+ BOOST_CHECK_EQUAL(1, msg6.getMessage().getAnnotation("qpid.msg_sequence").asInt64());
direct.encode(buffer);
}
{
@@ -237,11 +213,10 @@ QPID_AUTO_TEST_CASE(testSequenceOptions)
buffer.reset();
DirectExchange::shared_ptr exch_dec = Exchange::decode(exchanges, buffer);
- intrusive_ptr<Message> msg1 = cmessage("e", "abc");
- DeliverableMessage dmsg1(msg1);
- exch_dec->route(dmsg1);
+ DeliverableMessage msg1(MessageUtils::createMessage("e", "abc"), 0);
+ exch_dec->route(msg1);
- BOOST_CHECK_EQUAL(4, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ BOOST_CHECK_EQUAL(4, msg1.getMessage().getAnnotation("qpid.msg_sequence").asInt64());
}
delete [] buff;
@@ -256,9 +231,11 @@ QPID_AUTO_TEST_CASE(testIVEOption)
HeadersExchange header("headers1", false, args);
TopicExchange topic ("topic1", false, args);
- intrusive_ptr<Message> msg1 = cmessage("direct1", "abc");
- msg1->insertCustomProperty("a", "abc");
- DeliverableMessage dmsg1(msg1);
+ qpid::types::Variant::Map properties;
+ properties["routing-key"] = "abc";
+ properties["a"] = "abc";
+ Message msg1 = MessageUtils::createMessage(properties, "my-message", "direct1");
+ DeliverableMessage dmsg1(msg1, 0);
FieldTable args2;
args2.setString("x-match", "any");
@@ -273,8 +250,6 @@ QPID_AUTO_TEST_CASE(testIVEOption)
Queue::shared_ptr queue2(new Queue("queue2", true));
Queue::shared_ptr queue3(new Queue("queue3", true));
- BOOST_CHECK(HeadersExchange::match(args2, msg1->getProperties<MessageProperties>()->getApplicationHeaders()));
-
BOOST_CHECK(direct.bind(queue, "abc", 0));
BOOST_CHECK(fanout.bind(queue1, "abc", 0));
BOOST_CHECK(header.bind(queue2, "", &args2));
@@ -287,7 +262,6 @@ QPID_AUTO_TEST_CASE(testIVEOption)
}
-
QPID_AUTO_TEST_SUITE_END()
}} // namespace qpid::tests
diff --git a/cpp/src/tests/Makefile.am b/cpp/src/tests/Makefile.am
index cdc7429f3b..f9eed9270b 100644
--- a/cpp/src/tests/Makefile.am
+++ b/cpp/src/tests/Makefile.am
@@ -96,6 +96,7 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \
ExchangeTest.cpp \
HeadersExchangeTest.cpp \
MessageTest.cpp \
+ QueueDepth.cpp \
QueueRegistryTest.cpp \
QueuePolicyTest.cpp \
QueueFlowLimitTest.cpp \
@@ -105,19 +106,15 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \
TimerTest.cpp \
TopicExchangeTest.cpp \
TxBufferTest.cpp \
- TxPublishTest.cpp \
- MessageBuilderTest.cpp \
ConnectionOptions.h \
ForkedBroker.h \
ForkedBroker.cpp \
ManagementTest.cpp \
MessageReplayTracker.cpp \
ConsoleTest.cpp \
- QueueEvents.cpp \
ProxyTest.cpp \
RetryList.cpp \
FrameDecoder.cpp \
- ReplicationTest.cpp \
ClientMessageTest.cpp \
PollableCondition.cpp \
Variant.cpp \
@@ -142,7 +139,6 @@ test_store_la_SOURCES = test_store.cpp
test_store_la_LIBADD = $(lib_broker)
test_store_la_LDFLAGS = -module
-include cluster.mk
include sasl.mk
if SSL
include ssl.mk
@@ -338,7 +334,6 @@ EXTRA_DIST += \
dynamic_log_level_test \
qpid-ctrl \
CMakeLists.txt \
- cluster.cmake \
windows/DisableWin32ErrorWindows.cpp \
background.ps1 \
find_prog.ps1 \
@@ -372,14 +367,6 @@ LONG_TESTS+=start_broker \
stop_broker \
run_long_federation_sys_tests
-if HAVE_LIBCPG
-
-LONG_TESTS+= federated_cluster_test_with_node_failure \
- run_failover_soak \
- reliable_replication_test
-
-endif HAVE_LIBCPG
-
EXTRA_DIST+= \
fanout_perftest \
shared_perftest \
diff --git a/cpp/src/tests/MessageBuilderTest.cpp b/cpp/src/tests/MessageBuilderTest.cpp
deleted file mode 100644
index 9adb133d40..0000000000
--- a/cpp/src/tests/MessageBuilderTest.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/broker/Message.h"
-#include "qpid/broker/MessageBuilder.h"
-#include "qpid/broker/NullMessageStore.h"
-#include "qpid/framing/frame_functors.h"
-#include "qpid/framing/MessageTransferBody.h"
-#include "qpid/framing/TypeFilter.h"
-#include "unit_test.h"
-#include <list>
-
-using namespace qpid::broker;
-using namespace qpid::framing;
-using namespace qpid::sys;
-
-namespace qpid {
-namespace tests {
-
-class MockMessageStore : public NullMessageStore
-{
- enum Op {STAGE=1, APPEND=2};
-
- uint64_t id;
- boost::intrusive_ptr<PersistableMessage> expectedMsg;
- std::string expectedData;
- std::list<Op> ops;
-
- void checkExpectation(Op actual)
- {
- BOOST_CHECK_EQUAL(ops.front(), actual);
- ops.pop_front();
- }
-
- public:
- MockMessageStore() : id(0), expectedMsg(0) {}
-
- void expectStage(PersistableMessage& msg)
- {
- expectedMsg = &msg;
- ops.push_back(STAGE);
- }
-
- void expectAppendContent(PersistableMessage& msg, const std::string& data)
- {
- expectedMsg = &msg;
- expectedData = data;
- ops.push_back(APPEND);
- }
-
- void stage(const boost::intrusive_ptr<PersistableMessage>& msg)
- {
- checkExpectation(STAGE);
- BOOST_CHECK_EQUAL(expectedMsg, msg);
- msg->setPersistenceId(++id);
- }
-
- void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg,
- const std::string& data)
- {
- checkExpectation(APPEND);
- BOOST_CHECK_EQUAL(boost::static_pointer_cast<const PersistableMessage>(expectedMsg), msg);
- BOOST_CHECK_EQUAL(expectedData, data);
- }
-
- bool expectationsMet()
- {
- return ops.empty();
- }
-
- //don't treat this store as a null impl
- bool isNull() const
- {
- return false;
- }
-
-};
-
-QPID_AUTO_TEST_SUITE(MessageBuilderTestSuite)
-
-QPID_AUTO_TEST_CASE(testHeaderOnly)
-{
- MessageBuilder builder(0);
- builder.start(SequenceNumber());
-
- std::string exchange("builder-exchange");
- std::string key("builder-exchange");
-
- AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
- AMQFrame header((AMQHeaderBody()));
-
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(0);
- header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
-
- builder.handle(method);
- builder.handle(header);
-
- BOOST_CHECK(builder.getMessage());
- BOOST_CHECK_EQUAL(exchange, builder.getMessage()->getExchangeName());
- BOOST_CHECK_EQUAL(key, builder.getMessage()->getRoutingKey());
- BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
-}
-
-QPID_AUTO_TEST_CASE(test1ContentFrame)
-{
- MessageBuilder builder(0);
- builder.start(SequenceNumber());
-
- std::string data("abcdefg");
- std::string exchange("builder-exchange");
- std::string key("builder-exchange");
-
- AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
- AMQFrame header((AMQHeaderBody()));
- AMQFrame content((AMQContentBody(data)));
- method.setEof(false);
- header.setBof(false);
- header.setEof(false);
- content.setBof(false);
-
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data.size());
- header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
-
- builder.handle(method);
- BOOST_CHECK(builder.getMessage());
- BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
-
- builder.handle(header);
- BOOST_CHECK(builder.getMessage());
- BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
-
- builder.handle(content);
- BOOST_CHECK(builder.getMessage());
- BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
-}
-
-QPID_AUTO_TEST_CASE(test2ContentFrames)
-{
- MessageBuilder builder(0);
- builder.start(SequenceNumber());
-
- std::string data1("abcdefg");
- std::string data2("hijklmn");
- std::string exchange("builder-exchange");
- std::string key("builder-exchange");
-
- AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
- AMQFrame header((AMQHeaderBody()));
- AMQFrame content1((AMQContentBody(data1)));
- AMQFrame content2((AMQContentBody(data2)));
- method.setEof(false);
- header.setBof(false);
- header.setEof(false);
- content1.setBof(false);
- content1.setEof(false);
- content2.setBof(false);
-
- header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
- header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
-
- builder.handle(method);
- builder.handle(header);
- builder.handle(content1);
- BOOST_CHECK(builder.getMessage());
- BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
-
- builder.handle(content2);
- BOOST_CHECK(builder.getMessage());
- BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
-}
-QPID_AUTO_TEST_SUITE_END()
-
-}} // namespace qpid::tests
diff --git a/cpp/src/tests/MessageTest.cpp b/cpp/src/tests/MessageTest.cpp
index 3a3ed061f9..fe670a274e 100644
--- a/cpp/src/tests/MessageTest.cpp
+++ b/cpp/src/tests/MessageTest.cpp
@@ -24,6 +24,7 @@
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/FieldValue.h"
#include "qpid/framing/Uuid.h"
+#include "MessageUtils.h"
#include "unit_test.h"
@@ -43,49 +44,29 @@ QPID_AUTO_TEST_CASE(testEncodeDecode)
{
string exchange = "MyExchange";
string routingKey = "MyRoutingKey";
+ uint64_t ttl(60);
Uuid messageId(true);
- string data1("abcdefg");
- string data2("hijklmn");
+ string data("abcdefghijklmn");
- boost::intrusive_ptr<Message> msg(new Message());
+ qpid::types::Variant::Map properties;
+ properties["routing-key"] = routingKey;
+ properties["ttl"] = ttl;
+ properties["durable"] = true;
+ properties["message-id"] = qpid::types::Uuid(messageId.data());
+ properties["abc"] = "xyz";
+ Message msg = MessageUtils::createMessage(properties, data);
- AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
- AMQFrame header((AMQHeaderBody()));
- AMQFrame content1((AMQContentBody(data1)));
- AMQFrame content2((AMQContentBody(data2)));
+ std::string buffer;
+ encode(msg, buffer);
+ msg = Message();
+ decode(buffer, msg);
- msg->getFrames().append(method);
- msg->getFrames().append(header);
- msg->getFrames().append(content1);
- msg->getFrames().append(content2);
-
- MessageProperties* mProps = msg->getFrames().getHeaders()->get<MessageProperties>(true);
- mProps->setContentLength(data1.size() + data2.size());
- mProps->setMessageId(messageId);
- FieldTable applicationHeaders;
- applicationHeaders.setString("abc", "xyz");
- mProps->setApplicationHeaders(applicationHeaders);
- DeliveryProperties* dProps = msg->getFrames().getHeaders()->get<DeliveryProperties>(true);
- dProps->setRoutingKey(routingKey);
- dProps->setDeliveryMode(PERSISTENT);
- BOOST_CHECK(msg->isPersistent());
-
- std::vector<char> buff(msg->encodedSize());
- Buffer wbuffer(&buff[0], msg->encodedSize());
- msg->encode(wbuffer);
-
- Buffer rbuffer(&buff[0], msg->encodedSize());
- msg = new Message();
- msg->decodeHeader(rbuffer);
- msg->decodeContent(rbuffer);
- BOOST_CHECK_EQUAL(exchange, msg->getExchangeName());
- BOOST_CHECK_EQUAL(routingKey, msg->getRoutingKey());
- BOOST_CHECK_EQUAL((uint64_t) data1.size() + data2.size(), msg->contentSize());
- BOOST_CHECK_EQUAL((uint64_t) data1.size() + data2.size(), msg->getProperties<MessageProperties>()->getContentLength());
- BOOST_CHECK_EQUAL(messageId, msg->getProperties<MessageProperties>()->getMessageId());
- BOOST_CHECK_EQUAL(string("xyz"), msg->getProperties<MessageProperties>()->getApplicationHeaders().getAsString("abc"));
- BOOST_CHECK_EQUAL((uint8_t) PERSISTENT, msg->getProperties<DeliveryProperties>()->getDeliveryMode());
- BOOST_CHECK(msg->isPersistent());
+ BOOST_CHECK_EQUAL(routingKey, msg.getRoutingKey());
+ BOOST_CHECK_EQUAL((uint64_t) data.size(), msg.getContentSize());
+ BOOST_CHECK_EQUAL(data, msg.getContent());
+ //BOOST_CHECK_EQUAL(messageId, msg->getProperties<MessageProperties>()->getMessageId());
+ BOOST_CHECK_EQUAL(string("xyz"), msg.getPropertyAsString("abc"));
+ BOOST_CHECK(msg.isPersistent());
}
QPID_AUTO_TEST_SUITE_END()
diff --git a/cpp/src/tests/MessageUtils.h b/cpp/src/tests/MessageUtils.h
index 991e2a2714..c2eabd804d 100644
--- a/cpp/src/tests/MessageUtils.h
+++ b/cpp/src/tests/MessageUtils.h
@@ -20,9 +20,11 @@
*/
#include "qpid/broker/Message.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/Uuid.h"
+#include "qpid/types/Variant.h"
using namespace qpid;
using namespace broker;
@@ -33,11 +35,46 @@ namespace tests {
struct MessageUtils
{
- static boost::intrusive_ptr<Message> createMessage(const std::string& exchange="", const std::string& routingKey="",
- const bool durable = false, const Uuid& messageId=Uuid(true),
- uint64_t contentSize = 0)
+ static Message createMessage(const qpid::types::Variant::Map& properties, const std::string& content="", const std::string& destination = "")
{
- boost::intrusive_ptr<broker::Message> msg(new broker::Message());
+ boost::intrusive_ptr<broker::amqp_0_10::MessageTransfer> msg(new broker::amqp_0_10::MessageTransfer());
+
+ AMQFrame method(( MessageTransferBody(ProtocolVersion(), destination, 0, 0)));
+ AMQFrame header((AMQHeaderBody()));
+
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ if (content.size()) {
+ msg->getFrames().getHeaders()->get<MessageProperties>(true)->setContentLength(content.size());
+ AMQFrame data((AMQContentBody(content)));
+ msg->getFrames().append(data);
+ }
+ for (qpid::types::Variant::Map::const_iterator i = properties.begin(); i != properties.end(); ++i) {
+ if (i->first == "routing-key" && !i->second.isVoid()) {
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(i->second);
+ } else if (i->first == "message-id" && !i->second.isVoid()) {
+ qpid::types::Uuid id = i->second;
+ qpid::framing::Uuid id2(id.data());
+ msg->getFrames().getHeaders()->get<MessageProperties>(true)->setMessageId(id2);
+ } else if (i->first == "ttl" && !i->second.isVoid()) {
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setTtl(i->second);
+ } else if (i->first == "priority" && !i->second.isVoid()) {
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setPriority(i->second);
+ } else if (i->first == "durable" && !i->second.isVoid()) {
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setDeliveryMode(i->second.asBool() ? 2 : 1);
+ } else {
+ msg->getFrames().getHeaders()->get<MessageProperties>(true)->getApplicationHeaders().setString(i->first, i->second);
+ }
+ }
+ return Message(msg, msg);
+ }
+
+
+ static Message createMessage(const std::string& exchange="", const std::string& routingKey="",
+ uint64_t ttl = 0, bool durable = false, const Uuid& messageId=Uuid(true),
+ const std::string& content="")
+ {
+ boost::intrusive_ptr<broker::amqp_0_10::MessageTransfer> msg(new broker::amqp_0_10::MessageTransfer());
AMQFrame method(( MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
AMQFrame header((AMQHeaderBody()));
@@ -45,18 +82,18 @@ struct MessageUtils
msg->getFrames().append(method);
msg->getFrames().append(header);
MessageProperties* props = msg->getFrames().getHeaders()->get<MessageProperties>(true);
- props->setContentLength(contentSize);
+ props->setContentLength(content.size());
props->setMessageId(messageId);
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
if (durable)
msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setDeliveryMode(2);
- return msg;
- }
-
- static void addContent(boost::intrusive_ptr<Message> msg, const std::string& data)
- {
- AMQFrame content((AMQContentBody(data)));
- msg->getFrames().append(content);
+ if (ttl)
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setTtl(ttl);
+ if (content.size()) {
+ AMQFrame data((AMQContentBody(content)));
+ msg->getFrames().append(data);
+ }
+ return Message(msg, msg);
}
};
diff --git a/cpp/src/tests/QueueDepth.cpp b/cpp/src/tests/QueueDepth.cpp
new file mode 100644
index 0000000000..09b221b3a8
--- /dev/null
+++ b/cpp/src/tests/QueueDepth.cpp
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/broker/QueueDepth.h"
+
+#include "unit_test.h"
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(QueueDepthTestSuite)
+
+using namespace qpid::broker;
+
+QPID_AUTO_TEST_CASE(testCompare)
+{
+ QueueDepth a(0, 0);
+ QueueDepth b(1, 1);
+ QueueDepth c(2, 2);
+ QueueDepth d(1, 1);
+
+ BOOST_CHECK(a < b);
+ BOOST_CHECK(b < c);
+ BOOST_CHECK(a < c);
+
+ BOOST_CHECK(b > a);
+ BOOST_CHECK(c > b);
+ BOOST_CHECK(c > a);
+
+ BOOST_CHECK(b == d);
+ BOOST_CHECK(d == b);
+ BOOST_CHECK(a != b);
+ BOOST_CHECK(b != a);
+
+ QueueDepth e; e.setCount(1);
+ QueueDepth f; f.setCount(2);
+ BOOST_CHECK(e < f);
+ BOOST_CHECK(f > e);
+
+ QueueDepth g; g.setSize(1);
+ QueueDepth h; h.setSize(2);
+ BOOST_CHECK(g < h);
+ BOOST_CHECK(h > g);
+}
+
+QPID_AUTO_TEST_CASE(testIncrement)
+{
+ QueueDepth a(5, 10);
+ QueueDepth b(3, 6);
+ QueueDepth c(8, 16);
+ a += b;
+ BOOST_CHECK(a == c);
+ BOOST_CHECK_EQUAL(8u, a.getCount());
+ BOOST_CHECK_EQUAL(16u, a.getSize());
+}
+
+QPID_AUTO_TEST_CASE(testDecrement)
+{
+ QueueDepth a(5, 10);
+ QueueDepth b(3, 6);
+ QueueDepth c(2, 4);
+ a -= b;
+ BOOST_CHECK(a == c);
+ BOOST_CHECK_EQUAL(2u, a.getCount());
+ BOOST_CHECK_EQUAL(4u, a.getSize());
+}
+
+QPID_AUTO_TEST_CASE(testAddition)
+{
+ QueueDepth a(5, 10);
+ QueueDepth b(3, 6);
+
+ QueueDepth c = a + b;
+ BOOST_CHECK_EQUAL(8u, c.getCount());
+ BOOST_CHECK_EQUAL(16u, c.getSize());
+}
+
+QPID_AUTO_TEST_CASE(testSubtraction)
+{
+ QueueDepth a(5, 10);
+ QueueDepth b(3, 6);
+
+ QueueDepth c = a - b;
+ BOOST_CHECK_EQUAL(2u, c.getCount());
+ BOOST_CHECK_EQUAL(4u, c.getSize());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}} // namespace qpid::tests
diff --git a/cpp/src/tests/QueueEvents.cpp b/cpp/src/tests/QueueEvents.cpp
deleted file mode 100644
index cea8bbf0db..0000000000
--- a/cpp/src/tests/QueueEvents.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "MessageUtils.h"
-#include "unit_test.h"
-#include "BrokerFixture.h"
-#include "qpid/broker/Message.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/QueueEvents.h"
-#include "qpid/client/QueueOptions.h"
-#include "qpid/framing/SequenceNumber.h"
-#include "qpid/sys/Dispatcher.h"
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-
-namespace qpid {
-namespace tests {
-
-QPID_AUTO_TEST_SUITE(QueueEventsSuite)
-
-using namespace qpid::client;
-using namespace qpid::broker;
-using namespace qpid::sys;
-using qpid::framing::SequenceNumber;
-
-struct EventChecker
-{
- typedef std::deque<QueueEvents::Event> Events;
-
- Events events;
- boost::shared_ptr<Poller> poller;
-
- void handle(QueueEvents::Event e)
- {
- if (events.empty()) {
- BOOST_FAIL("Unexpected event received");
- } else {
- BOOST_CHECK_EQUAL(events.front().type, e.type);
- BOOST_CHECK_EQUAL(events.front().msg.queue, e.msg.queue);
- BOOST_CHECK_EQUAL(events.front().msg.payload, e.msg.payload);
- BOOST_CHECK_EQUAL(events.front().msg.position, e.msg.position);
- events.pop_front();
- }
- if (events.empty() && poller) poller->shutdown();
- }
-
- void expect(QueueEvents::Event e)
- {
- events.push_back(e);
- }
-};
-
-QPID_AUTO_TEST_CASE(testBasicEventProcessing)
-{
- boost::shared_ptr<Poller> poller(new Poller());
- sys::Dispatcher dispatcher(poller);
- Thread dispatchThread(dispatcher);
- QueueEvents events(poller);
- EventChecker listener;
- listener.poller = poller;
- events.registerListener("dummy", boost::bind(&EventChecker::handle, &listener, _1));
- //signal occurence of some events:
- Queue queue("queue1");
- SequenceNumber id;
- QueuedMessage event1(&queue, MessageUtils::createMessage(), id);
- QueuedMessage event2(&queue, MessageUtils::createMessage(), ++id);
-
- //define events expected by listener:
- listener.expect(QueueEvents::Event(QueueEvents::ENQUEUE, event1));
- listener.expect(QueueEvents::Event(QueueEvents::ENQUEUE, event2));
- listener.expect(QueueEvents::Event(QueueEvents::DEQUEUE, event1));
-
- events.enqueued(event1);
- events.enqueued(event2);
- events.dequeued(event1);
-
- dispatchThread.join();
- events.shutdown();
- events.unregisterListener("dummy");
-}
-
-
-struct EventRecorder
-{
- struct EventRecord
- {
- QueueEvents::EventType type;
- std::string queue;
- std::string content;
- SequenceNumber position;
- };
-
- typedef std::deque<EventRecord> Events;
-
- Events events;
-
- void handle(QueueEvents::Event event)
- {
- EventRecord record;
- record.type = event.type;
- record.queue = event.msg.queue->getName();
- event.msg.payload->getFrames().getContent(record.content);
- record.position = event.msg.position;
- events.push_back(record);
- }
-
- void check(QueueEvents::EventType type, const std::string& queue, const std::string& content, const SequenceNumber& position)
- {
- if (events.empty()) {
- BOOST_FAIL("Missed event");
- } else {
- BOOST_CHECK_EQUAL(events.front().type, type);
- BOOST_CHECK_EQUAL(events.front().queue, queue);
- BOOST_CHECK_EQUAL(events.front().content, content);
- BOOST_CHECK_EQUAL(events.front().position, position);
- events.pop_front();
- }
- }
- void checkEnqueue(const std::string& queue, const std::string& data, const SequenceNumber& position)
- {
- check(QueueEvents::ENQUEUE, queue, data, position);
- }
-
- void checkDequeue(const std::string& queue, const std::string& data, const SequenceNumber& position)
- {
- check(QueueEvents::DEQUEUE, queue, data, position);
- }
-};
-
-QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing)
-{
- SessionFixture fixture;
- //register dummy event listener to broker
- EventRecorder listener;
- fixture.broker->getQueueEvents().registerListener("recorder", boost::bind(&EventRecorder::handle, &listener, _1));
-
- //declare queue with event options specified
- QueueOptions options;
- options.enableQueueEvents(false);
- std::string q("queue-events-test");
- fixture.session.queueDeclare(arg::queue=q, arg::arguments=options);
- //send and consume some messages
- LocalQueue incoming;
- Subscription sub = fixture.subs.subscribe(incoming, q);
- for (int i = 0; i < 5; i++) {
- fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
- }
- for (int i = 0; i < 3; i++) {
- BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
- }
- for (int i = 5; i < 10; i++) {
- fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
- }
- for (int i = 3; i < 10; i++) {
- BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
- }
- fixture.connection.close();
- fixture.broker->getQueueEvents().shutdown();
-
- //check listener was notified of all events, and in correct order
- SequenceNumber enqueueId(1);
- SequenceNumber dequeueId(1);
- for (int i = 0; i < 5; i++) {
- listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
- }
- for (int i = 0; i < 3; i++) {
- listener.checkDequeue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), dequeueId++);
- }
- for (int i = 5; i < 10; i++) {
- listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
- }
- for (int i = 3; i < 10; i++) {
- listener.checkDequeue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), dequeueId++);
- }
-}
-
-QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing_enqueuesOnly)
-{
- SessionFixture fixture;
- //register dummy event listener to broker
- EventRecorder listener;
- fixture.broker->getQueueEvents().registerListener("recorder", boost::bind(&EventRecorder::handle, &listener, _1));
-
- //declare queue with event options specified
- QueueOptions options;
- options.enableQueueEvents(true);
- std::string q("queue-events-test");
- fixture.session.queueDeclare(arg::queue=q, arg::arguments=options);
- //send and consume some messages
- LocalQueue incoming;
- Subscription sub = fixture.subs.subscribe(incoming, q);
- for (int i = 0; i < 5; i++) {
- fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
- }
- for (int i = 0; i < 3; i++) {
- BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
- }
- for (int i = 5; i < 10; i++) {
- fixture.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
- }
- for (int i = 3; i < 10; i++) {
- BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
- }
- fixture.connection.close();
- fixture.broker->getQueueEvents().shutdown();
-
- //check listener was notified of all events, and in correct order
- SequenceNumber enqueueId(1);
- SequenceNumber dequeueId(1);
- for (int i = 0; i < 5; i++) {
- listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
- }
- for (int i = 5; i < 10; i++) {
- listener.checkEnqueue(q, (boost::format("%1%_%2%") % "Message" % (i+1)).str(), enqueueId++);
- }
-}
-
-QPID_AUTO_TEST_SUITE_END()
-
-}} // namespace qpid::tests
diff --git a/cpp/src/tests/QueueFlowLimitTest.cpp b/cpp/src/tests/QueueFlowLimitTest.cpp
index bd868398f8..d305ca452b 100644
--- a/cpp/src/tests/QueueFlowLimitTest.cpp
+++ b/cpp/src/tests/QueueFlowLimitTest.cpp
@@ -23,8 +23,8 @@
#include "unit_test.h"
#include "test_tools.h"
-#include "qpid/broker/QueuePolicy.h"
#include "qpid/broker/QueueFlowLimit.h"
+#include "qpid/broker/QueueSettings.h"
#include "qpid/sys/Time.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/FieldValue.h"
@@ -66,21 +66,19 @@ public:
return new TestFlow(flowStopCount, flowResumeCount, flowStopSize, flowResumeSize);
}
- static QueueFlowLimit *getQueueFlowLimit(const qpid::framing::FieldTable& settings)
+ static QueueFlowLimit *getQueueFlowLimit(const qpid::framing::FieldTable& arguments)
{
+ QueueSettings settings;
+ settings.populate(arguments, settings.storeSettings);
return QueueFlowLimit::createLimit(0, settings);
}
};
-
-
-QueuedMessage createMessage(uint32_t size)
+Message createMessage(uint32_t size)
{
static uint32_t seqNum;
- QueuedMessage msg;
- msg.payload = MessageUtils::createMessage();
- msg.position = ++seqNum;
- MessageUtils::addContent(msg.payload, std::string (size, 'x'));
+ Message msg = MessageUtils::createMessage(qpid::types::Variant::Map(), std::string (size, 'x'));
+ msg.setSequence(++seqNum);
return msg;
}
}
@@ -100,7 +98,7 @@ QPID_AUTO_TEST_CASE(testFlowCount)
BOOST_CHECK(!flow->isFlowControlActive());
BOOST_CHECK(flow->monitorFlowControl());
- std::deque<QueuedMessage> msgs;
+ std::deque<Message> msgs;
for (size_t i = 0; i < 6; i++) {
msgs.push_back(createMessage(10));
flow->enqueued(msgs.back());
@@ -135,7 +133,6 @@ QPID_AUTO_TEST_CASE(testFlowCount)
BOOST_CHECK(!flow->isFlowControlActive()); // 4 on queue, OFF
}
-
QPID_AUTO_TEST_CASE(testFlowSize)
{
FieldTable args;
@@ -151,7 +148,7 @@ QPID_AUTO_TEST_CASE(testFlowSize)
BOOST_CHECK(!flow->isFlowControlActive());
BOOST_CHECK(flow->monitorFlowControl());
- std::deque<QueuedMessage> msgs;
+ std::deque<Message> msgs;
for (size_t i = 0; i < 6; i++) {
msgs.push_back(createMessage(10));
flow->enqueued(msgs.back());
@@ -161,14 +158,14 @@ QPID_AUTO_TEST_CASE(testFlowSize)
BOOST_CHECK_EQUAL(6u, flow->getFlowCount());
BOOST_CHECK_EQUAL(60u, flow->getFlowSize());
- QueuedMessage msg_9 = createMessage(9);
+ Message msg_9 = createMessage(9);
flow->enqueued(msg_9);
BOOST_CHECK(!flow->isFlowControlActive()); // 69 on queue
- QueuedMessage tinyMsg_1 = createMessage(1);
+ Message tinyMsg_1 = createMessage(1);
flow->enqueued(tinyMsg_1);
BOOST_CHECK(!flow->isFlowControlActive()); // 70 on queue
- QueuedMessage tinyMsg_2 = createMessage(1);
+ Message tinyMsg_2 = createMessage(1);
flow->enqueued(tinyMsg_2);
BOOST_CHECK(flow->isFlowControlActive()); // 71 on queue, ON
msgs.push_back(createMessage(10));
@@ -233,12 +230,12 @@ QPID_AUTO_TEST_CASE(testFlowCombo)
args.setUInt64(QueueFlowLimit::flowStopSizeKey, 200);
args.setUInt64(QueueFlowLimit::flowResumeSizeKey, 100);
- std::deque<QueuedMessage> msgs_1;
- std::deque<QueuedMessage> msgs_10;
- std::deque<QueuedMessage> msgs_50;
- std::deque<QueuedMessage> msgs_100;
+ std::deque<Message> msgs_1;
+ std::deque<Message> msgs_10;
+ std::deque<Message> msgs_50;
+ std::deque<Message> msgs_100;
- QueuedMessage msg;
+ Message msg;
std::auto_ptr<TestFlow> flow(TestFlow::createTestFlow(args));
BOOST_CHECK(!flow->isFlowControlActive()); // count:0 size:0
@@ -458,7 +455,6 @@ QPID_AUTO_TEST_CASE(testFlowDisable)
}
}
-
QPID_AUTO_TEST_SUITE_END()
}} // namespace qpid::tests
diff --git a/cpp/src/tests/QueuePolicyTest.cpp b/cpp/src/tests/QueuePolicyTest.cpp
index f735e09449..00e964602a 100644
--- a/cpp/src/tests/QueuePolicyTest.cpp
+++ b/cpp/src/tests/QueuePolicyTest.cpp
@@ -22,12 +22,10 @@
#include "unit_test.h"
#include "test_tools.h"
-#include "qpid/broker/QueuePolicy.h"
#include "qpid/broker/QueueFlowLimit.h"
#include "qpid/client/QueueOptions.h"
#include "qpid/sys/Time.h"
#include "qpid/framing/reply_exceptions.h"
-#include "MessageUtils.h"
#include "BrokerFixture.h"
using namespace qpid::broker;
@@ -39,118 +37,10 @@ namespace tests {
QPID_AUTO_TEST_SUITE(QueuePolicyTestSuite)
-namespace {
-QueuedMessage createMessage(uint32_t size)
-{
- QueuedMessage msg;
- msg.payload = MessageUtils::createMessage();
- MessageUtils::addContent(msg.payload, std::string (size, 'x'));
- return msg;
-}
-}
-
-QPID_AUTO_TEST_CASE(testCount)
-{
- std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 5, 0));
- BOOST_CHECK_EQUAL((uint64_t) 0, policy->getMaxSize());
- BOOST_CHECK_EQUAL((uint32_t) 5, policy->getMaxCount());
-
- QueuedMessage msg = createMessage(10);
- for (size_t i = 0; i < 5; i++) {
- policy->tryEnqueue(msg.payload);
- }
- try {
- policy->tryEnqueue(msg.payload);
- BOOST_FAIL("Policy did not fail on enqueuing sixth message");
- } catch (const ResourceLimitExceededException&) {}
-
- policy->dequeued(msg);
- policy->tryEnqueue(msg.payload);
-
- try {
- policy->tryEnqueue(msg.payload);
- BOOST_FAIL("Policy did not fail on enqueuing sixth message (after dequeue)");
- } catch (const ResourceLimitExceededException&) {}
-}
-
-QPID_AUTO_TEST_CASE(testSize)
-{
- std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 0, 50));
- QueuedMessage msg = createMessage(10);
-
- for (size_t i = 0; i < 5; i++) {
- policy->tryEnqueue(msg.payload);
- }
- try {
- policy->tryEnqueue(msg.payload);
- BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
- } catch (const ResourceLimitExceededException&) {}
-
- policy->dequeued(msg);
- policy->tryEnqueue(msg.payload);
-
- try {
- policy->tryEnqueue(msg.payload);
- BOOST_FAIL("Policy did not fail on aggregate size exceeding 50 (after dequeue). " << *policy);
- } catch (const ResourceLimitExceededException&) {}
-}
-
-QPID_AUTO_TEST_CASE(testBoth)
-{
- std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy("test", 5, 50));
- try {
- QueuedMessage msg = createMessage(51);
- policy->tryEnqueue(msg.payload);
- BOOST_FAIL("Policy did not fail on single message exceeding 50. " << *policy);
- } catch (const ResourceLimitExceededException&) {}
-
- std::vector<QueuedMessage> messages;
- messages.push_back(createMessage(15));
- messages.push_back(createMessage(10));
- messages.push_back(createMessage(11));
- messages.push_back(createMessage(2));
- messages.push_back(createMessage(7));
- for (size_t i = 0; i < messages.size(); i++) {
- policy->tryEnqueue(messages[i].payload);
- }
- //size = 45 at this point, count = 5
- try {
- QueuedMessage msg = createMessage(5);
- policy->tryEnqueue(msg.payload);
- BOOST_FAIL("Policy did not fail on count exceeding 6. " << *policy);
- } catch (const ResourceLimitExceededException&) {}
- try {
- QueuedMessage msg = createMessage(10);
- policy->tryEnqueue(msg.payload);
- BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
- } catch (const ResourceLimitExceededException&) {}
-
-
- policy->dequeued(messages[0]);
- try {
- QueuedMessage msg = createMessage(20);
- policy->tryEnqueue(msg.payload);
- } catch (const ResourceLimitExceededException&) {
- BOOST_FAIL("Policy failed incorrectly after dequeue. " << *policy);
- }
-}
-
-QPID_AUTO_TEST_CASE(testSettings)
-{
- //test reading and writing the policy from/to field table
- std::auto_ptr<QueuePolicy> a(QueuePolicy::createQueuePolicy("test", 101, 303));
- FieldTable settings;
- a->update(settings);
- std::auto_ptr<QueuePolicy> b(QueuePolicy::createQueuePolicy("test", settings));
- BOOST_CHECK_EQUAL(a->getMaxCount(), b->getMaxCount());
- BOOST_CHECK_EQUAL(a->getMaxSize(), b->getMaxSize());
-}
-
QPID_AUTO_TEST_CASE(testRingPolicyCount)
{
- FieldTable args;
- std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING);
- policy->update(args);
+ QueueOptions args;
+ args.setSizePolicy(RING, 0, 5);
SessionFixture f;
std::string q("my-ring-queue");
@@ -183,9 +73,8 @@ QPID_AUTO_TEST_CASE(testRingPolicySize)
// Ring queue, 500 bytes maxSize
- FieldTable args;
- std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 0, 500, QueuePolicy::RING);
- policy->update(args);
+ QueueOptions args;
+ args.setSizePolicy(RING, 500, 0);
SessionFixture f;
std::string q("my-ring-queue");
@@ -255,9 +144,9 @@ QPID_AUTO_TEST_CASE(testRingPolicySize)
QPID_AUTO_TEST_CASE(testStrictRingPolicy)
{
- FieldTable args;
- std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING_STRICT);
- policy->update(args);
+ QueueOptions args;
+ args.setSizePolicy(RING_STRICT, 0, 5);
+ args.setString("qpid.flow_stop_count", "0");
SessionFixture f;
std::string q("my-ring-queue");
@@ -281,9 +170,8 @@ QPID_AUTO_TEST_CASE(testStrictRingPolicy)
QPID_AUTO_TEST_CASE(testPolicyWithDtx)
{
- FieldTable args;
- std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT);
- policy->update(args);
+ QueueOptions args;
+ args.setSizePolicy(REJECT, 0, 5);
SessionFixture f;
std::string q("my-policy-queue");
@@ -367,9 +255,8 @@ QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
QPID_AUTO_TEST_CASE(testPolicyFailureOnCommit)
{
- FieldTable args;
- std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT);
- policy->update(args);
+ QueueOptions args;
+ args.setSizePolicy(REJECT, 0, 5);
SessionFixture f;
std::string q("q");
diff --git a/cpp/src/tests/QueueRegistryTest.cpp b/cpp/src/tests/QueueRegistryTest.cpp
index ae555539a4..364d66c525 100644
--- a/cpp/src/tests/QueueRegistryTest.cpp
+++ b/cpp/src/tests/QueueRegistryTest.cpp
@@ -19,6 +19,7 @@
#include "qpid/broker/QueueRegistry.h"
#include "qpid/broker/Queue.h"
+#include "qpid/broker/QueueSettings.h"
#include "unit_test.h"
#include <string>
@@ -36,33 +37,23 @@ QPID_AUTO_TEST_CASE(testDeclare)
QueueRegistry reg;
std::pair<Queue::shared_ptr, bool> qc;
- qc = reg.declare(foo, false, 0, 0);
+ qc = reg.declare(foo, QueueSettings());
Queue::shared_ptr q = qc.first;
BOOST_CHECK(q);
BOOST_CHECK(qc.second); // New queue
BOOST_CHECK_EQUAL(foo, q->getName());
- qc = reg.declare(foo, false, 0, 0);
+ qc = reg.declare(foo, QueueSettings());
BOOST_CHECK_EQUAL(q, qc.first);
BOOST_CHECK(!qc.second);
- qc = reg.declare(bar, false, 0, 0);
+ qc = reg.declare(bar, QueueSettings());
q = qc.first;
BOOST_CHECK(q);
BOOST_CHECK_EQUAL(true, qc.second);
BOOST_CHECK_EQUAL(bar, q->getName());
}
-QPID_AUTO_TEST_CASE(testDeclareTmp)
-{
- QueueRegistry reg;
- std::pair<Queue::shared_ptr, bool> qc;
-
- qc = reg.declare(std::string(), false, 0, 0);
- BOOST_CHECK(qc.second);
- BOOST_CHECK_EQUAL(std::string("tmp_1"), qc.first->getName());
-}
-
QPID_AUTO_TEST_CASE(testFind)
{
std::string foo("foo");
@@ -72,8 +63,8 @@ QPID_AUTO_TEST_CASE(testFind)
BOOST_CHECK(reg.find(foo) == 0);
- reg.declare(foo, false, 0, 0);
- reg.declare(bar, false, 0, 0);
+ reg.declare(foo, QueueSettings());
+ reg.declare(bar, QueueSettings());
Queue::shared_ptr q = reg.find(bar);
BOOST_CHECK(q);
BOOST_CHECK_EQUAL(bar, q->getName());
@@ -85,7 +76,7 @@ QPID_AUTO_TEST_CASE(testDestroy)
QueueRegistry reg;
std::pair<Queue::shared_ptr, bool> qc;
- qc = reg.declare(foo, false, 0, 0);
+ qc = reg.declare(foo, QueueSettings());
reg.destroy(foo);
// Queue is gone from the registry.
BOOST_CHECK(reg.find(foo) == 0);
diff --git a/cpp/src/tests/QueueTest.cpp b/cpp/src/tests/QueueTest.cpp
index 3b4f74620f..3dfe3863f4 100644
--- a/cpp/src/tests/QueueTest.cpp
+++ b/cpp/src/tests/QueueTest.cpp
@@ -38,8 +38,8 @@
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/MessageTransferBody.h"
#include "qpid/framing/reply_exceptions.h"
-#include "qpid/broker/QueuePolicy.h"
#include "qpid/broker/QueueFlowLimit.h"
+#include "qpid/broker/QueueSettings.h"
#include <iostream>
#include <vector>
@@ -56,196 +56,47 @@ using namespace qpid::sys;
namespace qpid {
namespace tests {
-
class TestConsumer : public virtual Consumer{
public:
typedef boost::shared_ptr<TestConsumer> shared_ptr;
- QueuedMessage last;
+ QueueCursor lastCursor;
+ Message lastMessage;
bool received;
- TestConsumer(std::string name="test", bool acquire = true):Consumer(name, acquire), received(false) {};
+ TestConsumer(std::string name="test", bool acquire = true) : Consumer(name, acquire ? CONSUMER : BROWSER), received(false) {};
- virtual bool deliver(QueuedMessage& msg){
- last = msg;
+ virtual bool deliver(const QueueCursor& cursor, const Message& message){
+ lastCursor = cursor;
+ lastMessage = message;
received = true;
return true;
};
void notify() {}
void cancel() {}
- void acknowledged(const QueuedMessage&) {}
+ void acknowledged(const DeliveryRecord&) {}
OwnershipToken* getSession() { return 0; }
};
class FailOnDeliver : public Deliverable
{
- boost::intrusive_ptr<Message> msg;
+ Message msg;
public:
FailOnDeliver() : msg(MessageUtils::createMessage()) {}
void deliverTo(const boost::shared_ptr<Queue>& queue)
{
throw Exception(QPID_MSG("Invalid delivery to " << queue->getName()));
}
- Message& getMessage() { return *(msg.get()); }
+ Message& getMessage() { return msg; }
};
-intrusive_ptr<Message> createMessage(std::string exchange, std::string routingKey, uint64_t ttl = 0) {
- intrusive_ptr<Message> msg(new Message());
- AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0)));
- AMQFrame header((AMQHeaderBody()));
- msg->getFrames().append(method);
- msg->getFrames().append(header);
- msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
- if (ttl) msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setTtl(ttl);
- return msg;
-}
-
-intrusive_ptr<Message> contentMessage(string content) {
- intrusive_ptr<Message> m(MessageUtils::createMessage());
- MessageUtils::addContent(m, content);
- return m;
-}
-
-string getContent(intrusive_ptr<Message> m) {
- return m->getFrames().getContent();
-}
-
QPID_AUTO_TEST_SUITE(QueueTestSuite)
-QPID_AUTO_TEST_CASE(testAsyncMessage) {
- Queue::shared_ptr queue(new Queue("my_test_queue", true));
- intrusive_ptr<Message> received;
-
- TestConsumer::shared_ptr c1(new TestConsumer());
- queue->consume(c1);
-
-
- //Test basic delivery:
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- msg1->enqueueAsync(queue, (MessageStore*)0);//this is done on enqueue which is not called from process
- queue->process(msg1);
- sleep(2);
-
- BOOST_CHECK(!c1->received);
- msg1->enqueueComplete();
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg1.get(), received.get());
-}
-
-
-QPID_AUTO_TEST_CASE(testAsyncMessageCount){
- Queue::shared_ptr queue(new Queue("my_test_queue", true));
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- msg1->enqueueAsync(queue, (MessageStore*)0);//this is done on enqueue which is not called from process
-
- queue->process(msg1);
- sleep(2);
- uint32_t compval=0;
- BOOST_CHECK_EQUAL(compval, queue->getEnqueueCompleteMessageCount());
- msg1->enqueueComplete();
- compval=1;
- BOOST_CHECK_EQUAL(compval, queue->getEnqueueCompleteMessageCount());
- BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
-}
-
-QPID_AUTO_TEST_CASE(testConsumers){
- Queue::shared_ptr queue(new Queue("my_queue", true));
-
- //Test adding consumers:
- TestConsumer::shared_ptr c1(new TestConsumer());
- TestConsumer::shared_ptr c2(new TestConsumer());
- queue->consume(c1);
- queue->consume(c2);
-
- BOOST_CHECK_EQUAL(uint32_t(2), queue->getConsumerCount());
-
- //Test basic delivery:
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
- intrusive_ptr<Message> msg3 = createMessage("e", "C");
-
- queue->deliver(msg1);
- BOOST_CHECK(queue->dispatch(c1));
- BOOST_CHECK_EQUAL(msg1.get(), c1->last.payload.get());
-
- queue->deliver(msg2);
- BOOST_CHECK(queue->dispatch(c2));
- BOOST_CHECK_EQUAL(msg2.get(), c2->last.payload.get());
-
- c1->received = false;
- queue->deliver(msg3);
- BOOST_CHECK(queue->dispatch(c1));
- BOOST_CHECK_EQUAL(msg3.get(), c1->last.payload.get());
-
- //Test cancellation:
- queue->cancel(c1);
- BOOST_CHECK_EQUAL(uint32_t(1), queue->getConsumerCount());
- queue->cancel(c2);
- BOOST_CHECK_EQUAL(uint32_t(0), queue->getConsumerCount());
-}
-
-QPID_AUTO_TEST_CASE(testRegistry){
- //Test use of queues in registry:
- QueueRegistry registry;
- registry.declare("queue1", true, true);
- registry.declare("queue2", true, true);
- registry.declare("queue3", true, true);
-
- BOOST_CHECK(registry.find("queue1"));
- BOOST_CHECK(registry.find("queue2"));
- BOOST_CHECK(registry.find("queue3"));
-
- registry.destroy("queue1");
- registry.destroy("queue2");
- registry.destroy("queue3");
-
- BOOST_CHECK(!registry.find("queue1"));
- BOOST_CHECK(!registry.find("queue2"));
- BOOST_CHECK(!registry.find("queue3"));
-}
-
-QPID_AUTO_TEST_CASE(testDequeue){
- Queue::shared_ptr queue(new Queue("my_queue", true));
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
- intrusive_ptr<Message> msg3 = createMessage("e", "C");
- intrusive_ptr<Message> received;
-
- queue->deliver(msg1);
- queue->deliver(msg2);
- queue->deliver(msg3);
-
- BOOST_CHECK_EQUAL(uint32_t(3), queue->getMessageCount());
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg1.get(), received.get());
- BOOST_CHECK_EQUAL(uint32_t(2), queue->getMessageCount());
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg2.get(), received.get());
- BOOST_CHECK_EQUAL(uint32_t(1), queue->getMessageCount());
-
- TestConsumer::shared_ptr consumer(new TestConsumer());
- queue->consume(consumer);
- queue->dispatch(consumer);
- if (!consumer->received)
- sleep(2);
-
- BOOST_CHECK_EQUAL(msg3.get(), consumer->last.payload.get());
- BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
-
- received = queue->get().payload;
- BOOST_CHECK(!received);
- BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
-
-}
-
QPID_AUTO_TEST_CASE(testBound){
//test the recording of bindings, and use of those to allow a queue to be unbound
string key("my-key");
FieldTable args;
- Queue::shared_ptr queue(new Queue("my-queue", true));
+ Queue::shared_ptr queue(new Queue("my-queue"));
ExchangeRegistry exchanges;
//establish bindings from exchange->queue and notify the queue as it is bound:
Exchange::shared_ptr exchange1 = exchanges.declare("my-exchange-1", "direct").first;
@@ -273,423 +124,69 @@ QPID_AUTO_TEST_CASE(testBound){
exchange3->route(deliverable);
}
-QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){
- client::QueueOptions args;
- args.setPersistLastNode();
-
- Queue::shared_ptr queue(new Queue("my-queue", true));
- queue->configure(args);
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
- intrusive_ptr<Message> msg3 = createMessage("e", "C");
-
- //enqueue 2 messages
- queue->deliver(msg1);
- queue->deliver(msg2);
-
- //change mode
- queue->setLastNodeFailure();
-
- //enqueue 1 message
- queue->deliver(msg3);
-
- //check all have persistent ids.
- BOOST_CHECK(msg1->isPersistent());
- BOOST_CHECK(msg2->isPersistent());
- BOOST_CHECK(msg3->isPersistent());
-
-}
-
-
-QPID_AUTO_TEST_CASE(testSeek){
-
- Queue::shared_ptr queue(new Queue("my-queue", true));
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
- intrusive_ptr<Message> msg3 = createMessage("e", "C");
-
- //enqueue 2 messages
- queue->deliver(msg1);
- queue->deliver(msg2);
- queue->deliver(msg3);
-
- TestConsumer::shared_ptr consumer(new TestConsumer("test", false));
- SequenceNumber seq(2);
- consumer->setPosition(seq);
-
- QueuedMessage qm;
- queue->dispatch(consumer);
-
- BOOST_CHECK_EQUAL(msg3.get(), consumer->last.payload.get());
- queue->dispatch(consumer);
- queue->dispatch(consumer); // make sure over-run is safe
-
-}
-
-QPID_AUTO_TEST_CASE(testSearch){
-
- Queue::shared_ptr queue(new Queue("my-queue", true));
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
- intrusive_ptr<Message> msg3 = createMessage("e", "C");
-
- //enqueue 2 messages
- queue->deliver(msg1);
- queue->deliver(msg2);
- queue->deliver(msg3);
-
- SequenceNumber seq(2);
- QueuedMessage qm;
- TestConsumer::shared_ptr c1(new TestConsumer());
-
- BOOST_CHECK(queue->find(seq, qm));
+QPID_AUTO_TEST_CASE(testLVQ){
- BOOST_CHECK_EQUAL(seq.getValue(), qm.position.getValue());
-
- queue->acquire(qm, c1->getName());
- BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
- SequenceNumber seq1(3);
- QueuedMessage qm1;
- BOOST_CHECK(queue->find(seq1, qm1));
- BOOST_CHECK_EQUAL(seq1.getValue(), qm1.position.getValue());
-
-}
-const std::string nullxid = "";
-
-class SimpleDummyCtxt : public TransactionContext {};
+ QueueSettings settings;
+ string key="key";
+ settings.lvqKey = key;
+ QueueFactory factory;
+ Queue::shared_ptr q(factory.create("my-queue", settings));
-class DummyCtxt : public TPCTransactionContext
-{
- const std::string xid;
- public:
- DummyCtxt(const std::string& _xid) : xid(_xid) {}
- static std::string getXid(TransactionContext& ctxt)
- {
- DummyCtxt* c(dynamic_cast<DummyCtxt*>(&ctxt));
- return c ? c->xid : nullxid;
+ const char* values[] = { "a", "b", "c", "a"};
+ for (size_t i = 0; i < sizeof(values)/sizeof(values[0]); ++i) {
+ qpid::types::Variant::Map properties;
+ properties[key] = values[i];
+ q->deliver(MessageUtils::createMessage(properties, boost::lexical_cast<string>(i+1)));
}
-};
-
-class TestMessageStoreOC : public MessageStore
-{
- std::set<std::string> prepared;
- uint64_t nextPersistenceId;
- public:
-
- uint enqCnt;
- uint deqCnt;
- bool error;
-
- TestMessageStoreOC() : MessageStore(),nextPersistenceId(1),enqCnt(0),deqCnt(0),error(false) {}
- ~TestMessageStoreOC(){}
+ BOOST_CHECK_EQUAL(q->getMessageCount(), 3u);
- virtual void dequeue(TransactionContext*,
- const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
- const PersistableQueue& /*queue*/)
- {
- if (error) throw Exception("Dequeue error test");
- deqCnt++;
- }
+ TestConsumer::shared_ptr c(new TestConsumer("test", true));
+ BOOST_CHECK(q->dispatch(c));
+ BOOST_CHECK_EQUAL(std::string("2"), c->lastMessage.getContent());
+ BOOST_CHECK(q->dispatch(c));
+ BOOST_CHECK_EQUAL(std::string("3"), c->lastMessage.getContent());
+ BOOST_CHECK(q->dispatch(c));
+ BOOST_CHECK_EQUAL(std::string("4"), c->lastMessage.getContent());
- virtual void enqueue(TransactionContext*,
- const boost::intrusive_ptr<PersistableMessage>& msg,
- const PersistableQueue& /* queue */)
- {
- if (error) throw Exception("Enqueue error test");
- enqCnt++;
- msg->enqueueComplete();
- }
- void createError()
- {
- error=true;
+ const char* values2[] = { "a", "b", "c"};
+ for (size_t i = 0; i < sizeof(values2)/sizeof(values2[0]); ++i) {
+ qpid::types::Variant::Map properties;
+ properties[key] = values[i];
+ q->deliver(MessageUtils::createMessage(properties, boost::lexical_cast<string>(i+5)));
}
+ BOOST_CHECK_EQUAL(q->getMessageCount(), 3u);
- bool init(const Options*) { return true; }
- void truncateInit(const bool) {}
- void create(PersistableQueue& queue, const framing::FieldTable&) { queue.setPersistenceId(nextPersistenceId++); }
- void destroy(PersistableQueue&) {}
- void create(const PersistableExchange& exchange, const framing::FieldTable&) { exchange.setPersistenceId(nextPersistenceId++); }
- void destroy(const PersistableExchange&) {}
- void bind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&) {}
- void unbind(const PersistableExchange&, const PersistableQueue&, const std::string&, const framing::FieldTable&) {}
- void create(const PersistableConfig& config) { config.setPersistenceId(nextPersistenceId++); }
- void destroy(const PersistableConfig&) {}
- void stage(const boost::intrusive_ptr<PersistableMessage>&) {}
- void destroy(PersistableMessage&) {}
- void appendContent(const boost::intrusive_ptr<const PersistableMessage>&, const std::string&) {}
- void loadContent(const qpid::broker::PersistableQueue&, const boost::intrusive_ptr<const PersistableMessage>&,
- std::string&, uint64_t, uint32_t) { throw qpid::framing::InternalErrorException("Can't load content; persistence not enabled"); }
- void flush(const qpid::broker::PersistableQueue&) {}
- uint32_t outstandingQueueAIO(const PersistableQueue&) { return 0; }
-
- std::auto_ptr<TransactionContext> begin() { return std::auto_ptr<TransactionContext>(new SimpleDummyCtxt()); }
- std::auto_ptr<TPCTransactionContext> begin(const std::string& xid) { return std::auto_ptr<TPCTransactionContext>(new DummyCtxt(xid)); }
- void prepare(TPCTransactionContext& ctxt) { prepared.insert(DummyCtxt::getXid(ctxt)); }
- void commit(TransactionContext& ctxt) { prepared.erase(DummyCtxt::getXid(ctxt)); }
- void abort(TransactionContext& ctxt) { prepared.erase(DummyCtxt::getXid(ctxt)); }
- void collectPreparedXids(std::set<std::string>& out) { out.insert(prepared.begin(), prepared.end()); }
-
- void recover(RecoveryManager&) {}
-};
-
-
-QPID_AUTO_TEST_CASE(testLVQOrdering){
-
- client::QueueOptions args;
- // set queue mode
- args.setOrdering(client::LVQ);
-
- Queue::shared_ptr queue(new Queue("my-queue", true ));
- queue->configure(args);
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
- intrusive_ptr<Message> msg3 = createMessage("e", "C");
- intrusive_ptr<Message> msg4 = createMessage("e", "D");
- intrusive_ptr<Message> received;
-
- //set deliever match for LVQ a,b,c,a
-
- string key;
- args.getLVQKey(key);
- BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
-
-
- msg1->insertCustomProperty(key,"a");
- msg2->insertCustomProperty(key,"b");
- msg3->insertCustomProperty(key,"c");
- msg4->insertCustomProperty(key,"a");
-
- //enqueue 4 message
- queue->deliver(msg1);
- queue->deliver(msg2);
- queue->deliver(msg3);
- queue->deliver(msg4);
-
- BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg4.get(), received.get());
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg2.get(), received.get());
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg3.get(), received.get());
-
- intrusive_ptr<Message> msg5 = createMessage("e", "A");
- intrusive_ptr<Message> msg6 = createMessage("e", "B");
- intrusive_ptr<Message> msg7 = createMessage("e", "C");
- msg5->insertCustomProperty(key,"a");
- msg6->insertCustomProperty(key,"b");
- msg7->insertCustomProperty(key,"c");
- queue->deliver(msg5);
- queue->deliver(msg6);
- queue->deliver(msg7);
-
- BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg5.get(), received.get());
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg6.get(), received.get());
-
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg7.get(), received.get());
-
+ BOOST_CHECK(q->dispatch(c));
+ BOOST_CHECK_EQUAL(std::string("5"), c->lastMessage.getContent());
+ BOOST_CHECK(q->dispatch(c));
+ BOOST_CHECK_EQUAL(std::string("6"), c->lastMessage.getContent());
+ BOOST_CHECK(q->dispatch(c));
+ BOOST_CHECK_EQUAL(std::string("7"), c->lastMessage.getContent());
}
QPID_AUTO_TEST_CASE(testLVQEmptyKey){
- client::QueueOptions args;
- // set queue mode
- args.setOrdering(client::LVQ);
-
- Queue::shared_ptr queue(new Queue("my-queue", true ));
- queue->configure(args);
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
-
- string key;
- args.getLVQKey(key);
- BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
-
-
- msg1->insertCustomProperty(key,"a");
- queue->deliver(msg1);
- queue->deliver(msg2);
- BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
-
-}
-
-QPID_AUTO_TEST_CASE(testLVQAcquire){
-
- client::QueueOptions args;
- // set queue mode
- args.setOrdering(client::LVQ);
- // disable flow control, as this test violates the enqueue/dequeue sequence.
- args.setInt(QueueFlowLimit::flowStopCountKey, 0);
-
- Queue::shared_ptr queue(new Queue("my-queue", true ));
- queue->configure(args);
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
- intrusive_ptr<Message> msg3 = createMessage("e", "C");
- intrusive_ptr<Message> msg4 = createMessage("e", "D");
- intrusive_ptr<Message> msg5 = createMessage("e", "F");
- intrusive_ptr<Message> msg6 = createMessage("e", "G");
-
- //set deliever match for LVQ a,b,c,a
-
- string key;
- args.getLVQKey(key);
- BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
-
-
- msg1->insertCustomProperty(key,"a");
- msg2->insertCustomProperty(key,"b");
- msg3->insertCustomProperty(key,"c");
- msg4->insertCustomProperty(key,"a");
- msg5->insertCustomProperty(key,"b");
- msg6->insertCustomProperty(key,"c");
-
- //enqueue 4 message
- queue->deliver(msg1);
- queue->deliver(msg2);
- queue->deliver(msg3);
- queue->deliver(msg4);
-
- BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
-
- framing::SequenceNumber sequence(1);
- QueuedMessage qmsg(queue.get(), msg1, sequence);
- QueuedMessage qmsg2(queue.get(), msg2, ++sequence);
- framing::SequenceNumber sequence1(10);
- QueuedMessage qmsg3(queue.get(), 0, sequence1);
- TestConsumer::shared_ptr dummy(new TestConsumer());
-
- BOOST_CHECK(!queue->acquire(qmsg, dummy->getName()));
- BOOST_CHECK(queue->acquire(qmsg2, dummy->getName()));
- // Acquire the massage again to test failure case.
- BOOST_CHECK(!queue->acquire(qmsg2, dummy->getName()));
- BOOST_CHECK(!queue->acquire(qmsg3, dummy->getName()));
-
- BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
-
- queue->deliver(msg5);
- BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
-
- // set mode to no browse and check
- args.setOrdering(client::LVQ_NO_BROWSE);
- queue->configure(args);
- TestConsumer::shared_ptr c1(new TestConsumer("test", false));
-
- queue->dispatch(c1);
- queue->dispatch(c1);
- queue->dispatch(c1);
-
- queue->deliver(msg6);
- BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
-
- intrusive_ptr<Message> received;
- received = queue->get().payload;
- BOOST_CHECK_EQUAL(msg4.get(), received.get());
-
-}
-
-QPID_AUTO_TEST_CASE(testLVQMultiQueue){
-
- client::QueueOptions args;
- // set queue mode
- args.setOrdering(client::LVQ);
-
- Queue::shared_ptr queue1(new Queue("my-queue", true ));
- Queue::shared_ptr queue2(new Queue("my-queue", true ));
- intrusive_ptr<Message> received;
- queue1->configure(args);
- queue2->configure(args);
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "A");
-
- string key;
- args.getLVQKey(key);
- BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
-
- msg1->insertCustomProperty(key,"a");
- msg2->insertCustomProperty(key,"a");
-
- queue1->deliver(msg1);
- queue2->deliver(msg1);
- queue1->deliver(msg2);
-
- received = queue1->get().payload;
- BOOST_CHECK_EQUAL(msg2.get(), received.get());
-
- received = queue2->get().payload;
- BOOST_CHECK_EQUAL(msg1.get(), received.get());
+ QueueSettings settings;
+ string key="key";
+ settings.lvqKey = key;
+ QueueFactory factory;
+ Queue::shared_ptr q(factory.create("my-queue", settings));
-}
-QPID_AUTO_TEST_CASE(testLVQRecover){
-
-/* simulate this
- 1. start 2 nodes
- 2. create cluster durable lvq
- 3. send a transient message to the queue
- 4. kill one of the nodes (to trigger force persistent behaviour)...
- 5. then restart it (to turn off force persistent behaviour)
- 6. send another transient message with same lvq key as in 3
- 7. kill the second node again (retrigger force persistent)
- 8. stop and recover the first node
-*/
- TestMessageStoreOC testStore;
- client::QueueOptions args;
- // set queue mode
- args.setOrdering(client::LVQ);
- args.setPersistLastNode();
-
- Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
- intrusive_ptr<Message> received;
- queue1->create(args);
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
- intrusive_ptr<Message> msg2 = createMessage("e", "A");
- // 2
- string key;
- args.getLVQKey(key);
- BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
-
- msg1->insertCustomProperty(key,"a");
- msg2->insertCustomProperty(key,"a");
- // 3
- queue1->deliver(msg1);
- // 4
- queue1->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
- // 5
- queue1->clearLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
- // 6
- queue1->deliver(msg2);
- BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
- queue1->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 2u);
- BOOST_CHECK_EQUAL(testStore.deqCnt, 1u);
+ qpid::types::Variant::Map properties;
+ properties["key"] = "a";
+ q->deliver(MessageUtils::createMessage(properties, "one"));
+ properties.clear();
+ q->deliver(MessageUtils::createMessage(properties, "two"));
+ BOOST_CHECK_EQUAL(q->getMessageCount(), 2u);
}
void addMessagesToQueue(uint count, Queue& queue, uint oddTtl = 200, uint evenTtl = 0)
{
for (uint i = 0; i < count; i++) {
- intrusive_ptr<Message> m = createMessage("exchange", "key", i % 2 ? oddTtl : evenTtl);
- m->computeExpiration(new broker::ExpiryPolicy);
+ Message m = MessageUtils::createMessage("exchange", "key", i % 2 ? oddTtl : evenTtl);
+ m.computeExpiration(new broker::ExpiryPolicy);
queue.deliver(m);
}
}
@@ -706,7 +203,7 @@ QPID_AUTO_TEST_CASE(testPurgeExpired) {
QPID_AUTO_TEST_CASE(testQueueCleaner) {
Timer timer;
QueueRegistry queues;
- Queue::shared_ptr queue = queues.declare("my-queue").first;
+ Queue::shared_ptr queue = queues.declare("my-queue", QueueSettings()).first;
addMessagesToQueue(10, *queue, 200, 400);
BOOST_CHECK_EQUAL(queue->getMessageCount(), 10u);
@@ -717,44 +214,57 @@ QPID_AUTO_TEST_CASE(testQueueCleaner) {
::usleep(300*1000);
BOOST_CHECK_EQUAL(queue->getMessageCount(), 0u);
}
-
-
namespace {
- // helper for group tests
- void verifyAcquire( Queue::shared_ptr queue,
- TestConsumer::shared_ptr c,
- std::deque<QueuedMessage>& results,
- const std::string& expectedGroup,
- const int expectedId )
- {
- BOOST_CHECK(queue->dispatch(c));
- results.push_back(c->last);
- std::string group = c->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsString("GROUP-ID");
- int id = c->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsInt("MY-ID");
+int getIntProperty(const Message& message, const std::string& key)
+{
+ qpid::types::Variant v = message.getProperty(key);
+ int i(0);
+ if (!v.isVoid()) i = v;
+ return i;
+}
+// helper for group tests
+void verifyAcquire( Queue::shared_ptr queue,
+ TestConsumer::shared_ptr c,
+ std::deque<QueueCursor>& results,
+ const std::string& expectedGroup,
+ const int expectedId )
+{
+ bool success = queue->dispatch(c);
+ BOOST_CHECK(success);
+ if (success) {
+ results.push_back(c->lastCursor);
+ std::string group = c->lastMessage.getPropertyAsString("GROUP-ID");
+ int id = getIntProperty(c->lastMessage, "MY-ID");
BOOST_CHECK_EQUAL( group, expectedGroup );
BOOST_CHECK_EQUAL( id, expectedId );
}
}
+Message createGroupMessage(int id, const std::string& group)
+{
+ qpid::types::Variant::Map properties;
+ properties["GROUP-ID"] = group;
+ properties["MY-ID"] = id;
+ return MessageUtils::createMessage(properties);
+}
+}
+
QPID_AUTO_TEST_CASE(testGroupsMultiConsumer) {
//
// Verify that consumers of grouped messages own the groups once a message is acquired,
// and release the groups once all acquired messages have been dequeued or requeued
//
- FieldTable args;
- Queue::shared_ptr queue(new Queue("my_queue", true));
- args.setString("qpid.group_header_key", "GROUP-ID");
- args.setInt("qpid.shared_msg_group", 1);
- queue->configure(args);
+ QueueSettings settings;
+ settings.shareGroups = 1;
+ settings.groupKey = "GROUP-ID";
+ QueueFactory factory;
+ Queue::shared_ptr queue(factory.create("my_queue", settings));
std::string groups[] = { std::string("a"), std::string("a"), std::string("a"),
std::string("b"), std::string("b"), std::string("b"),
std::string("c"), std::string("c"), std::string("c") };
for (int i = 0; i < 9; ++i) {
- intrusive_ptr<Message> msg = createMessage("e", "A");
- msg->insertCustomProperty("GROUP-ID", groups[i]);
- msg->insertCustomProperty("MY-ID", i);
- queue->deliver(msg);
+ queue->deliver(createGroupMessage(i, groups[i]));
}
// Queue = a-0, a-1, a-2, b-3, b-4, b-5, c-6, c-7, c-8...
@@ -768,8 +278,8 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumer) {
queue->consume(c1);
queue->consume(c2);
- std::deque<QueuedMessage> dequeMeC1;
- std::deque<QueuedMessage> dequeMeC2;
+ std::deque<QueueCursor> dequeMeC1;
+ std::deque<QueueCursor> dequeMeC2;
verifyAcquire(queue, c1, dequeMeC1, "a", 0 ); // c1 now owns group "a" (acquire a-0)
@@ -828,9 +338,9 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumer) {
// Owners= ^C2, ^C2, ^C1, ^C1, ^C2, ^C2
// what happens if C-2 "requeues" a-1 and a-2?
- queue->requeue( dequeMeC2.front() );
+ queue->release( dequeMeC2.front() );
dequeMeC2.pop_front();
- queue->requeue( dequeMeC2.front() );
+ queue->release( dequeMeC2.front() );
dequeMeC2.pop_front(); // now just has c-7 acquired
// Queue = a-1, a-2, b-4, b-5, c-7, c-8...
@@ -855,9 +365,9 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumer) {
gotOne = queue->dispatch(c2);
BOOST_CHECK( !gotOne );
- // requeue all of C1's acquired messages, then cancel C1
+ // release all of C1's acquired messages, then cancel C1
while (!dequeMeC1.empty()) {
- queue->requeue(dequeMeC1.front());
+ queue->release(dequeMeC1.front());
dequeMeC1.pop_front();
}
queue->cancel(c1);
@@ -877,7 +387,7 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumer) {
// Owners= ---, ---, ---
TestConsumer::shared_ptr c3(new TestConsumer("C3"));
- std::deque<QueuedMessage> dequeMeC3;
+ std::deque<QueueCursor> dequeMeC3;
verifyAcquire(queue, c3, dequeMeC3, "a", 2 );
verifyAcquire(queue, c2, dequeMeC2, "b", 4 );
@@ -897,11 +407,7 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumer) {
// Queue = a-2,
// Owners= ^C3,
-
- intrusive_ptr<Message> msg = createMessage("e", "A");
- msg->insertCustomProperty("GROUP-ID", "a");
- msg->insertCustomProperty("MY-ID", 9);
- queue->deliver(msg);
+ queue->deliver(createGroupMessage(9, "a"));
// Queue = a-2, a-9
// Owners= ^C3, ^C3
@@ -909,10 +415,7 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumer) {
gotOne = queue->dispatch(c2);
BOOST_CHECK( !gotOne );
- msg = createMessage("e", "A");
- msg->insertCustomProperty("GROUP-ID", "b");
- msg->insertCustomProperty("MY-ID", 10);
- queue->deliver(msg);
+ queue->deliver(createGroupMessage(10, "b"));
// Queue = a-2, a-9, b-10
// Owners= ^C3, ^C3, ----
@@ -933,17 +436,17 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumerDefaults) {
// Verify that the same default group name is automatically applied to messages that
// do not specify a group name.
//
- FieldTable args;
- Queue::shared_ptr queue(new Queue("my_queue", true));
- args.setString("qpid.group_header_key", "GROUP-ID");
- args.setInt("qpid.shared_msg_group", 1);
- queue->configure(args);
+ QueueSettings settings;
+ settings.shareGroups = 1;
+ settings.groupKey = "GROUP-ID";
+ QueueFactory factory;
+ Queue::shared_ptr queue(factory.create("my_queue", settings));
for (int i = 0; i < 3; ++i) {
- intrusive_ptr<Message> msg = createMessage("e", "A");
+ qpid::types::Variant::Map properties;
// no "GROUP-ID" header
- msg->insertCustomProperty("MY-ID", i);
- queue->deliver(msg);
+ properties["MY-ID"] = i;
+ queue->deliver(MessageUtils::createMessage(properties));
}
// Queue = 0, 1, 2
@@ -956,20 +459,20 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumerDefaults) {
queue->consume(c1);
queue->consume(c2);
- std::deque<QueuedMessage> dequeMeC1;
- std::deque<QueuedMessage> dequeMeC2;
+ std::deque<QueueCursor> dequeMeC1;
+ std::deque<QueueCursor> dequeMeC2;
queue->dispatch(c1); // c1 now owns default group (acquired 0)
- dequeMeC1.push_back(c1->last);
- int id = c1->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsInt("MY-ID");
+ dequeMeC1.push_back(c1->lastCursor);
+ int id = getIntProperty(c1->lastMessage, "MY-ID");
BOOST_CHECK_EQUAL( id, 0 );
bool gotOne = queue->dispatch(c2); // c2 should get nothing
BOOST_CHECK( !gotOne );
queue->dispatch(c1); // c1 now acquires 1
- dequeMeC1.push_back(c1->last);
- id = c1->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsInt("MY-ID");
+ dequeMeC1.push_back(c1->lastCursor);
+ id = getIntProperty(c1->lastMessage, "MY-ID");
BOOST_CHECK_EQUAL( id, 1 );
gotOne = queue->dispatch(c2); // c2 should still get nothing
@@ -982,7 +485,7 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumerDefaults) {
// now default group should be available...
queue->dispatch(c2); // c2 now owns default group (acquired 2)
- id = c2->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsInt("MY-ID");
+ id = c2->lastMessage.getProperty("MY-ID");
BOOST_CHECK_EQUAL( id, 2 );
gotOne = queue->dispatch(c1); // c1 should get nothing
@@ -992,556 +495,128 @@ QPID_AUTO_TEST_CASE(testGroupsMultiConsumerDefaults) {
queue->cancel(c2);
}
-QPID_AUTO_TEST_CASE(testMultiQueueLastNode){
-
- TestMessageStoreOC testStore;
- client::QueueOptions args;
- args.setPersistLastNode();
-
- Queue::shared_ptr queue1(new Queue("queue1", true, &testStore ));
- queue1->create(args);
- Queue::shared_ptr queue2(new Queue("queue2", true, &testStore ));
- queue2->create(args);
-
- intrusive_ptr<Message> msg1 = createMessage("e", "A");
-
- queue1->deliver(msg1);
- queue2->deliver(msg1);
-
- //change mode
- queue1->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
- queue2->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 2u);
-
- // check they don't get stored twice
- queue1->setLastNodeFailure();
- queue2->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 2u);
-
- intrusive_ptr<Message> msg2 = createMessage("e", "B");
- queue1->deliver(msg2);
- queue2->deliver(msg2);
-
- queue1->clearLastNodeFailure();
- queue2->clearLastNodeFailure();
- // check only new messages get forced
- queue1->setLastNodeFailure();
- queue2->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 4u);
-
- // check no failure messages are stored
- queue1->clearLastNodeFailure();
- queue2->clearLastNodeFailure();
-
- intrusive_ptr<Message> msg3 = createMessage("e", "B");
- queue1->deliver(msg3);
- queue2->deliver(msg3);
- BOOST_CHECK_EQUAL(testStore.enqCnt, 4u);
- queue1->setLastNodeFailure();
- queue2->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 6u);
-
- /**
- * TODO: Fix or replace the following test which incorrectly requeues a
- * message that was never on the queue in the first place. This relied on
- * internal details not part of the queue abstraction.
-
- // check requeue 1
- intrusive_ptr<Message> msg4 = createMessage("e", "C");
- intrusive_ptr<Message> msg5 = createMessage("e", "D");
-
- framing::SequenceNumber sequence(1);
- QueuedMessage qmsg1(queue1.get(), msg4, sequence);
- QueuedMessage qmsg2(queue2.get(), msg5, ++sequence);
-
- queue1->requeue(qmsg1);
- BOOST_CHECK_EQUAL(testStore.enqCnt, 7u);
-
- // check requeue 2
- queue2->clearLastNodeFailure();
- queue2->requeue(qmsg2);
- BOOST_CHECK_EQUAL(testStore.enqCnt, 7u);
- queue2->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 8u);
-
- queue2->clearLastNodeFailure();
- queue2->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 8u);
- */
-}
-
-QPID_AUTO_TEST_CASE(testLastNodeRecoverAndFail){
-/*
-simulate this:
- 1. start two nodes
- 2. create cluster durable queue and add some messages
- 3. kill one node (trigger force-persistent behaviour)
- 4. stop and recover remaining node
- 5. add another node
- 6. kill that new node again
-make sure that an attempt to re-enqueue a message does not happen which will
-result in the last man standing exiting with an error.
-
-we need to make sure that recover is safe, i.e. messages are
-not requeued to the store.
-*/
- TestMessageStoreOC testStore;
- client::QueueOptions args;
- // set queue mode
- args.setPersistLastNode();
-
- Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
- intrusive_ptr<Message> received;
- queue1->create(args);
-
- // check requeue 1
- intrusive_ptr<Message> msg1 = createMessage("e", "C");
- intrusive_ptr<Message> msg2 = createMessage("e", "D");
-
- queue1->recover(msg1);
-
- queue1->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
-
- queue1->clearLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
-
- queue1->deliver(msg2);
- BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
- queue1->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 1u);
-
-}
-
-QPID_AUTO_TEST_CASE(testLastNodeJournalError){
-/*
-simulate store exception going into last node standing
-
-*/
- TestMessageStoreOC testStore;
- client::QueueOptions args;
- // set queue mode
- args.setPersistLastNode();
-
- Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore));
- intrusive_ptr<Message> received;
- queue1->configure(args);
-
- // check requeue 1
- intrusive_ptr<Message> msg1 = createMessage("e", "C");
-
- queue1->deliver(msg1);
- testStore.createError();
-
- ScopedSuppressLogging sl; // Suppress messages for expected errors.
- queue1->setLastNodeFailure();
- BOOST_CHECK_EQUAL(testStore.enqCnt, 0u);
-
-}
-
-intrusive_ptr<Message> mkMsg(MessageStore& store, std::string content = "", bool durable = false)
-{
- intrusive_ptr<Message> msg = MessageUtils::createMessage("", "", durable);
- if (content.size()) MessageUtils::addContent(msg, content);
- msg->setStore(&store);
- return msg;
-}
-
-QPID_AUTO_TEST_CASE(testFlowToDiskBlocking){
-
- TestMessageStoreOC testStore;
- client::QueueOptions args0; // No size policy
- client::QueueOptions args1;
- args1.setSizePolicy(FLOW_TO_DISK, 0, 1);
- client::QueueOptions args2;
- args2.setSizePolicy(FLOW_TO_DISK, 0, 2);
-
- // --- Fanout exchange bound to single transient queue -------------------------------------------------------------
-
- FanOutExchange sbtFanout1("sbtFanout1", false, args0); // single binding to transient queue
- Queue::shared_ptr tq1(new Queue("tq1", true)); // transient w/ limit
- tq1->configure(args1);
- sbtFanout1.bind(tq1, "", 0);
-
- intrusive_ptr<Message> msg01 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg01(msg01);
- sbtFanout1.route(dmsg01); // Brings queue 1 to capacity limit
- msg01->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg01->isContentReleased(), false);
- BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
-
- intrusive_ptr<Message> msg02 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg02(msg02);
- {
- ScopedSuppressLogging sl; // suppress expected error messages.
- BOOST_CHECK_THROW(sbtFanout1.route(dmsg02), ResourceLimitExceededException);
- }
- msg02->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg02->isContentReleased(), false);
- BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
-
- intrusive_ptr<Message> msg03 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
- DeliverableMessage dmsg03(msg03);
- {
- ScopedSuppressLogging sl; // suppress expected error messages.
- BOOST_CHECK_THROW(sbtFanout1.route(dmsg03), ResourceLimitExceededException);
- }
- msg03->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg03->isContentReleased(), false);
- BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
-
- intrusive_ptr<Message> msg04 = mkMsg(testStore); // transient no content
- DeliverableMessage dmsg04(msg04);
- {
- ScopedSuppressLogging sl; // suppress expected error messages.
- BOOST_CHECK_THROW(sbtFanout1.route(dmsg04), ResourceLimitExceededException);
- }
- msg04->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg04->isContentReleased(), false);
- BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
-
- intrusive_ptr<Message> msg05 = mkMsg(testStore, "", true); // durable no content
- DeliverableMessage dmsg05(msg05);
- {
- ScopedSuppressLogging sl; // suppress expected error messages.
- BOOST_CHECK_THROW(sbtFanout1.route(dmsg05), ResourceLimitExceededException);
- }
- msg05->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg05->isContentReleased(), false);
- BOOST_CHECK_EQUAL(1u, tq1->getMessageCount());
-
- // --- Fanout exchange bound to single durable queue ---------------------------------------------------------------
-
- FanOutExchange sbdFanout2("sbdFanout2", false, args0); // single binding to durable queue
- Queue::shared_ptr dq2(new Queue("dq2", true, &testStore)); // durable w/ limit
- dq2->configure(args1);
- sbdFanout2.bind(dq2, "", 0);
-
- intrusive_ptr<Message> msg06 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg06(msg06);
- sbdFanout2.route(dmsg06); // Brings queue 2 to capacity limit
- msg06->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg06->isContentReleased(), false);
- BOOST_CHECK_EQUAL(1u, dq2->getMessageCount());
-
- intrusive_ptr<Message> msg07 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg07(msg07);
- sbdFanout2.route(dmsg07);
- msg07->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg07->isContentReleased(), true);
- BOOST_CHECK_EQUAL(2u, dq2->getMessageCount());
-
- intrusive_ptr<Message> msg08 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
- DeliverableMessage dmsg08(msg08);
- sbdFanout2.route(dmsg08);
- msg08->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg08->isContentReleased(), true);
- BOOST_CHECK_EQUAL(3u, dq2->getMessageCount());
-
- intrusive_ptr<Message> msg09 = mkMsg(testStore); // transient no content
- DeliverableMessage dmsg09(msg09);
- sbdFanout2.route(dmsg09);
- msg09->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg09->isContentReleased(), true);
- BOOST_CHECK_EQUAL(4u, dq2->getMessageCount());
-
- intrusive_ptr<Message> msg10 = mkMsg(testStore, "", true); // durable no content
- DeliverableMessage dmsg10(msg10);
- sbdFanout2.route(dmsg10);
- msg10->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg10->isContentReleased(), true);
- BOOST_CHECK_EQUAL(5u, dq2->getMessageCount());
-
- // --- Fanout exchange bound to multiple durable queues ------------------------------------------------------------
-
- FanOutExchange mbdFanout3("mbdFanout3", false, args0); // multiple bindings to durable queues
- Queue::shared_ptr dq3(new Queue("dq3", true, &testStore)); // durable w/ limit 2
- dq3->configure(args2);
- mbdFanout3.bind(dq3, "", 0);
- Queue::shared_ptr dq4(new Queue("dq4", true, &testStore)); // durable w/ limit 1
- dq4->configure(args1);
- mbdFanout3.bind(dq4, "", 0);
- Queue::shared_ptr dq5(new Queue("dq5", true, &testStore)); // durable no limit
- dq5->configure(args0);
- mbdFanout3.bind(dq5, "", 0);
-
- intrusive_ptr<Message> msg11 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg11(msg11);
- mbdFanout3.route(dmsg11); // Brings queues 3 and 4 to capacity limit
- msg11->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg11->isContentReleased(), false);
- BOOST_CHECK_EQUAL(1u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(1u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(1u, dq5->getMessageCount());
-
- intrusive_ptr<Message> msg12 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg12(msg12);
- mbdFanout3.route(dmsg12);
- msg12->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg12->isContentReleased(), false); // XXXX - consequence of transient msg multi-queue ftd policy-handling limitations, fix in broker at some point!
- BOOST_CHECK_EQUAL(2u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(2u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(2u, dq5->getMessageCount());
-
- intrusive_ptr<Message> msg13 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
- DeliverableMessage dmsg13(msg13);
- mbdFanout3.route(dmsg13);
- msg13->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg13->isContentReleased(), true);
- BOOST_CHECK_EQUAL(3u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(3u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(3u, dq5->getMessageCount());
-
- intrusive_ptr<Message> msg14 = mkMsg(testStore); // transient no content
- DeliverableMessage dmsg14(msg14);
- mbdFanout3.route(dmsg14);
- msg14->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg14->isContentReleased(), false); // XXXX - consequence of transient msg multi-queue ftd policy-handling limitations, fix in broker at some point!
- BOOST_CHECK_EQUAL(4u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(4u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(4u, dq5->getMessageCount());
-
- intrusive_ptr<Message> msg15 = mkMsg(testStore, "", true); // durable no content
- DeliverableMessage dmsg15(msg15);
- mbdFanout3.route(dmsg15);
- msg15->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg15->isContentReleased(), true);
- BOOST_CHECK_EQUAL(5u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(5u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(5u, dq5->getMessageCount());
-
- // Bind a transient queue, this should block the release of any further messages.
- // Note: this will result in a violation of the count policy of dq3 and dq4 - but this
- // is expected until a better overall multi-queue design is implemented. Similarly
- // for the other tests in this section.
-
- Queue::shared_ptr tq6(new Queue("tq6", true)); // transient no limit
- tq6->configure(args0);
- mbdFanout3.bind(tq6, "", 0);
-
- intrusive_ptr<Message> msg16 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg16(msg16);
- mbdFanout3.route(dmsg16);
- msg16->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg16->isContentReleased(), false);
- BOOST_CHECK_EQUAL(6u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(6u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(6u, dq5->getMessageCount());
-
- intrusive_ptr<Message> msg17 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
- DeliverableMessage dmsg17(msg17);
- mbdFanout3.route(dmsg17);
- msg17->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg17->isContentReleased(), false);
- BOOST_CHECK_EQUAL(7u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(7u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(7u, dq5->getMessageCount());
-
- intrusive_ptr<Message> msg18 = mkMsg(testStore); // transient no content
- DeliverableMessage dmsg18(msg18);
- mbdFanout3.route(dmsg18);
- msg18->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg18->isContentReleased(), false);
- BOOST_CHECK_EQUAL(8u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(8u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(8u, dq5->getMessageCount());
-
- intrusive_ptr<Message> msg19 = mkMsg(testStore, "", true); // durable no content
- DeliverableMessage dmsg19(msg19);
- mbdFanout3.route(dmsg19);
- msg19->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg19->isContentReleased(), false);
- BOOST_CHECK_EQUAL(9u, dq3->getMessageCount());
- BOOST_CHECK_EQUAL(9u, dq4->getMessageCount());
- BOOST_CHECK_EQUAL(9u, dq5->getMessageCount());
-
-
- // --- Fanout exchange bound to multiple durable and transient queues ----------------------------------------------
-
- FanOutExchange mbmFanout4("mbmFanout4", false, args0); // multiple bindings to durable/transient queues
- Queue::shared_ptr dq7(new Queue("dq7", true, &testStore)); // durable no limit
- dq7->configure(args0);
- mbmFanout4.bind(dq7, "", 0);
- Queue::shared_ptr dq8(new Queue("dq8", true, &testStore)); // durable w/ limit
- dq8->configure(args1);
- mbmFanout4.bind(dq8, "", 0);
- Queue::shared_ptr tq9(new Queue("tq9", true)); // transient no limit
- tq9->configure(args0);
- mbmFanout4.bind(tq9, "", 0);
-
- intrusive_ptr<Message> msg20 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg20(msg20);
- mbmFanout4.route(dmsg20); // Brings queue 7 to capacity limit
- msg20->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg20->isContentReleased(), false);
- BOOST_CHECK_EQUAL(1u, dq7->getMessageCount());
- BOOST_CHECK_EQUAL(1u, dq8->getMessageCount());
- BOOST_CHECK_EQUAL(1u, tq9->getMessageCount());
-
- intrusive_ptr<Message> msg21 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content
- DeliverableMessage dmsg21(msg21);
- mbmFanout4.route(dmsg21);
- msg21->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg21->isContentReleased(), false);
- BOOST_CHECK_EQUAL(2u, dq7->getMessageCount()); // over limit
- BOOST_CHECK_EQUAL(2u, dq8->getMessageCount());
- BOOST_CHECK_EQUAL(2u, tq9->getMessageCount());
-
- intrusive_ptr<Message> msg22 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content
- DeliverableMessage dmsg22(msg22);
- mbmFanout4.route(dmsg22);
- msg22->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg22->isContentReleased(), false);
- BOOST_CHECK_EQUAL(3u, dq7->getMessageCount()); // over limit
- BOOST_CHECK_EQUAL(3u, dq8->getMessageCount()); // over limit
- BOOST_CHECK_EQUAL(3u, tq9->getMessageCount());
-
- intrusive_ptr<Message> msg23 = mkMsg(testStore); // transient no content
- DeliverableMessage dmsg23(msg23);
- mbmFanout4.route(dmsg23);
- msg23->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg23->isContentReleased(), false);
- BOOST_CHECK_EQUAL(4u, dq7->getMessageCount()); // over limit
- BOOST_CHECK_EQUAL(4u, dq8->getMessageCount()); // over limit
- BOOST_CHECK_EQUAL(4u, tq9->getMessageCount());
-
- intrusive_ptr<Message> msg24 = mkMsg(testStore, "", true); // durable no content
- DeliverableMessage dmsg24(msg24);
- mbmFanout4.route(dmsg24);
- msg24->tryReleaseContent();
- BOOST_CHECK_EQUAL(msg24->isContentReleased(), false);
- BOOST_CHECK_EQUAL(5u, dq7->getMessageCount()); // over limit
- BOOST_CHECK_EQUAL(5u, dq8->getMessageCount()); // over limit
- BOOST_CHECK_EQUAL(5u, tq9->getMessageCount());
-}
-
QPID_AUTO_TEST_CASE(testSetPositionFifo) {
Queue::shared_ptr q(new Queue("my-queue", true));
BOOST_CHECK_EQUAL(q->getPosition(), SequenceNumber(0));
for (int i = 0; i < 10; ++i)
- q->deliver(contentMessage(boost::lexical_cast<string>(i+1)));
+ q->deliver(MessageUtils::createMessage(qpid::types::Variant::Map(), boost::lexical_cast<string>(i+1)));
// Verify the front of the queue
TestConsumer::shared_ptr c(new TestConsumer("test", false)); // Don't acquire
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(1u, c->last.position); // Numbered from 1
- BOOST_CHECK_EQUAL("1", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(1u, c->lastMessage.getSequence()); // Numbered from 1
+ BOOST_CHECK_EQUAL("1", c->lastMessage.getContent());
+
// Verify the back of the queue
- QueuedMessage qm;
BOOST_CHECK_EQUAL(10u, q->getPosition());
- BOOST_CHECK(q->find(q->getPosition(), qm)); // Back of the queue
- BOOST_CHECK_EQUAL("10", getContent(qm.payload));
BOOST_CHECK_EQUAL(10u, q->getMessageCount());
// Using setPosition to introduce a gap in sequence numbers.
q->setPosition(15);
BOOST_CHECK_EQUAL(10u, q->getMessageCount());
BOOST_CHECK_EQUAL(15u, q->getPosition());
- BOOST_CHECK(q->find(10, qm)); // Back of the queue
- BOOST_CHECK_EQUAL("10", getContent(qm.payload));
- q->deliver(contentMessage("16"));
- c->setPosition(9);
+ q->deliver(MessageUtils::createMessage(qpid::types::Variant::Map(), "16"));
+
+ q->seek(*c, Queue::MessagePredicate(), 9);
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(10u, c->last.position);
- BOOST_CHECK_EQUAL("10", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(10u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("10", c->lastMessage.getContent());
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(16u, c->last.position);
- BOOST_CHECK_EQUAL("16", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(16u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("16", c->lastMessage.getContent());
// Using setPosition to trunkcate the queue
q->setPosition(5);
BOOST_CHECK_EQUAL(5u, q->getMessageCount());
- q->deliver(contentMessage("6a"));
- c->setPosition(4);
+ q->deliver(MessageUtils::createMessage(qpid::types::Variant::Map(), "6a"));
+ c = boost::shared_ptr<TestConsumer>(new TestConsumer("test", false)); // Don't acquire
+ q->seek(*c, Queue::MessagePredicate(), 4);
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(5u, c->last.position);
- BOOST_CHECK_EQUAL("5", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(5u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("5", c->lastMessage.getContent());
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(6u, c->last.position);
- BOOST_CHECK_EQUAL("6a", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(6u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("6a", c->lastMessage.getContent());
BOOST_CHECK(!q->dispatch(c)); // No more messages.
}
QPID_AUTO_TEST_CASE(testSetPositionLvq) {
- Queue::shared_ptr q(new Queue("my-queue", true));
+ QueueSettings settings;
string key="key";
- framing::FieldTable args;
- args.setString("qpid.last_value_queue_key", "key");
- q->configure(args);
+ settings.lvqKey = key;
+ QueueFactory factory;
+ Queue::shared_ptr q(factory.create("my-queue", settings));
const char* values[] = { "a", "b", "c", "a", "b", "c" };
for (size_t i = 0; i < sizeof(values)/sizeof(values[0]); ++i) {
- intrusive_ptr<Message> m = contentMessage(boost::lexical_cast<string>(i+1));
- m->insertCustomProperty(key, values[i]);
- q->deliver(m);
+ qpid::types::Variant::Map properties;
+ properties[key] = values[i];
+ q->deliver(MessageUtils::createMessage(properties, boost::lexical_cast<string>(i+1)));
}
BOOST_CHECK_EQUAL(3u, q->getMessageCount());
// Verify the front of the queue
TestConsumer::shared_ptr c(new TestConsumer("test", false)); // Don't acquire
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(4u, c->last.position); // Numbered from 1
- BOOST_CHECK_EQUAL("4", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(4u, c->lastMessage.getSequence()); // Numbered from 1
+ BOOST_CHECK_EQUAL("4", c->lastMessage.getContent());
// Verify the back of the queue
- QueuedMessage qm;
BOOST_CHECK_EQUAL(6u, q->getPosition());
- BOOST_CHECK(q->find(q->getPosition(), qm)); // Back of the queue
- BOOST_CHECK_EQUAL("6", getContent(qm.payload));
q->setPosition(5);
- c->setPosition(4);
+
+ c = boost::shared_ptr<TestConsumer>(new TestConsumer("test", false)); // Don't acquire
+ q->seek(*c, Queue::MessagePredicate(), 4);
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(5u, c->last.position); // Numbered from 1
+ BOOST_CHECK_EQUAL(5u, c->lastMessage.getSequence()); // Numbered from 1
BOOST_CHECK(!q->dispatch(c));
}
QPID_AUTO_TEST_CASE(testSetPositionPriority) {
- Queue::shared_ptr q(new Queue("my-queue", true));
- framing::FieldTable args;
- args.setInt("qpid.priorities", 10);
- q->configure(args);
+ QueueSettings settings;
+ settings.priorities = 10;
+ QueueFactory factory;
+ Queue::shared_ptr q(factory.create("my-queue", settings));
const int priorities[] = { 1, 2, 3, 2, 1, 3 };
for (size_t i = 0; i < sizeof(priorities)/sizeof(priorities[0]); ++i) {
- intrusive_ptr<Message> m = contentMessage(boost::lexical_cast<string>(i+1));
- m->getFrames().getHeaders()->get<DeliveryProperties>(true)
- ->setPriority(priorities[i]);
- q->deliver(m);
+ qpid::types::Variant::Map properties;
+ properties["priority"] = priorities[i];
+ q->deliver(MessageUtils::createMessage(properties, boost::lexical_cast<string>(i+1)));
}
// Truncation removes messages in fifo order, not priority order.
q->setPosition(3);
- TestConsumer::shared_ptr c(new TestConsumer("test", false)); // Browse in FIFO order
+ TestConsumer::shared_ptr c(new TestConsumer("test", false)); // Browse in priority order
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(1u, c->last.position);
+ BOOST_CHECK_EQUAL(3u, c->lastMessage.getSequence());
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(2u, c->last.position);
+ BOOST_CHECK_EQUAL(2u, c->lastMessage.getSequence());
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(3u, c->last.position);
+ BOOST_CHECK_EQUAL(1u, c->lastMessage.getSequence());
BOOST_CHECK(!q->dispatch(c));
- intrusive_ptr<Message> m = contentMessage("4a");
- m->getFrames().getHeaders()->get<DeliveryProperties>(true)
- ->setPriority(4);
- q->deliver(m);
+ qpid::types::Variant::Map properties;
+ properties["priority"] = 4;
+ q->deliver(MessageUtils::createMessage(properties, "4a"));
+
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(4u, c->last.position);
- BOOST_CHECK_EQUAL("4a", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(4u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("4a", c->lastMessage.getContent());
// But consumers see priority order
c.reset(new TestConsumer("test", true));
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(4u, c->last.position);
- BOOST_CHECK_EQUAL("4a", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(4u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("4a", c->lastMessage.getContent());
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(3u, c->last.position);
- BOOST_CHECK_EQUAL("3", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(3u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("3", c->lastMessage.getContent());
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(2u, c->last.position);
- BOOST_CHECK_EQUAL("2", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(2u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("2", c->lastMessage.getContent());
BOOST_CHECK(q->dispatch(c));
- BOOST_CHECK_EQUAL(1u, c->last.position);
- BOOST_CHECK_EQUAL("1", getContent(c->last.payload));
+ BOOST_CHECK_EQUAL(1u, c->lastMessage.getSequence());
+ BOOST_CHECK_EQUAL("1", c->lastMessage.getContent());
}
QPID_AUTO_TEST_SUITE_END()
diff --git a/cpp/src/tests/ReplicationTest.cpp b/cpp/src/tests/ReplicationTest.cpp
deleted file mode 100644
index 055f06579f..0000000000
--- a/cpp/src/tests/ReplicationTest.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "unit_test.h"
-#include "test_tools.h"
-#include "config.h"
-#include "BrokerFixture.h"
-
-#include "qpid/Plugin.h"
-#include "qpid/broker/Broker.h"
-#include "qpid/client/QueueOptions.h"
-#include "qpid/framing/reply_exceptions.h"
-#include "qpid/framing/SequenceNumber.h"
-#include "qpid/replication/constants.h"
-#include "qpid/sys/Shlib.h"
-
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <boost/assign.hpp>
-#include <boost/bind.hpp>
-
-using namespace qpid::client;
-using namespace qpid::framing;
-using namespace qpid::replication::constants;
-using boost::assign::list_of;
-
-namespace qpid {
-namespace tests {
-
-QPID_AUTO_TEST_SUITE(ReplicationTestSuite)
-
-// FIXME aconway 2009-11-26: clean this up.
-// The CMake-based build passes in the module suffix; if it's not there, this
-// is a Linux/UNIX libtool-based build.
-#if defined (QPID_MODULE_PREFIX) && defined (QPID_MODULE_SUFFIX)
-static const char *default_shlib =
- QPID_MODULE_PREFIX "replicating_listener" QPID_MODULE_POSTFIX QPID_MODULE_SUFFIX;
-#else
-static const char *default_shlib = ".libs/replicating_listener.so";
-#endif
-qpid::sys::Shlib plugin(getLibPath("REPLICATING_LISTENER_LIB", default_shlib));
-
-qpid::broker::Broker::Options getBrokerOpts(const std::vector<std::string>& args)
-{
- std::vector<const char*> argv(args.size());
- transform(args.begin(), args.end(), argv.begin(), boost::bind(&std::string::c_str, _1));
-
- qpid::broker::Broker::Options opts;
- qpid::Plugin::addOptions(opts);
- opts.parse(argv.size(), &argv[0], "", true);
- return opts;
-}
-
-QPID_AUTO_TEST_CASE(testReplicationExchange)
-{
- qpid::broker::Broker::Options brokerOpts(getBrokerOpts(list_of<std::string>("qpidd")
- ("--replication-exchange-name=qpid.replication")));
- SessionFixture f(brokerOpts);
-
-
- std::string dataQ("queue-1");
- std::string eventQ("event-queue-1");
- std::string dataQ2("queue-2");
- std::string eventQ2("event-queue-2");
- FieldTable eventQopts;
- eventQopts.setString("qpid.insert_sequence_numbers", REPLICATION_EVENT_SEQNO);
-
- f.session.queueDeclare(arg::queue=eventQ, arg::exclusive=true, arg::autoDelete=true, arg::arguments=eventQopts);
- f.session.exchangeBind(arg::exchange="qpid.replication", arg::queue=eventQ, arg::bindingKey=dataQ);
-
- f.session.queueDeclare(arg::queue=eventQ2, arg::exclusive=true, arg::autoDelete=true, arg::arguments=eventQopts);
- f.session.exchangeBind(arg::exchange="qpid.replication", arg::queue=eventQ2, arg::bindingKey=dataQ2);
-
- QueueOptions args;
- args.enableQueueEvents(false);
- f.session.queueDeclare(arg::queue=dataQ, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
- f.session.queueDeclare(arg::queue=dataQ2, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
- for (int i = 0; i < 10; i++) {
- f.session.messageTransfer(arg::content=Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), dataQ));
- f.session.messageTransfer(arg::content=Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), dataQ2));
- }
- Message msg;
- LocalQueue incoming;
- Subscription sub = f.subs.subscribe(incoming, dataQ);
- for (int i = 0; i < 10; i++) {
- BOOST_CHECK(incoming.get(msg, qpid::sys::TIME_SEC));
- BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
- }
- BOOST_CHECK(!f.subs.get(msg, dataQ));
-
- sub.cancel();
- sub = f.subs.subscribe(incoming, eventQ);
- //check that we received enqueue events for first queue:
- for (int i = 0; i < 10; i++) {
- BOOST_CHECK(incoming.get(msg, qpid::sys::TIME_SEC));
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsString(REPLICATION_TARGET_QUEUE), dataQ);
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt(REPLICATION_EVENT_TYPE), ENQUEUE);
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt64(REPLICATION_EVENT_SEQNO), (i+1));
- BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
- }
- //check that we received dequeue events for first queue:
- for (int i = 0; i < 10; i++) {
- BOOST_CHECK(incoming.get(msg, qpid::sys::TIME_SEC));
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsString(REPLICATION_TARGET_QUEUE), dataQ);
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt(REPLICATION_EVENT_TYPE), DEQUEUE);
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt(DEQUEUED_MESSAGE_POSITION), (i+1));
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt64(REPLICATION_EVENT_SEQNO), (i+11));
- }
-
- sub.cancel();
- sub = f.subs.subscribe(incoming, eventQ2);
- //check that we received enqueue events for second queue:
- for (int i = 0; i < 10; i++) {
- BOOST_CHECK(incoming.get(msg, qpid::sys::TIME_SEC));
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsString(REPLICATION_TARGET_QUEUE), dataQ2);
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt(REPLICATION_EVENT_TYPE), ENQUEUE);
- BOOST_CHECK_EQUAL(msg.getHeaders().getAsInt64(REPLICATION_EVENT_SEQNO), (i+1));
- BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
- }
-}
-
-
-QPID_AUTO_TEST_SUITE_END()
-
-}} // namespace qpid::tests
diff --git a/cpp/src/tests/TxMocks.h b/cpp/src/tests/TxMocks.h
index 72cb50cd21..bf21104f70 100644
--- a/cpp/src/tests/TxMocks.h
+++ b/cpp/src/tests/TxMocks.h
@@ -119,8 +119,6 @@ public:
assertEqualVector(expected, actual);
}
- void accept(TxOpConstVisitor&) const {}
-
~MockTxOp(){}
};
diff --git a/cpp/src/tests/TxPublishTest.cpp b/cpp/src/tests/TxPublishTest.cpp
deleted file mode 100644
index a636646035..0000000000
--- a/cpp/src/tests/TxPublishTest.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "qpid/broker/NullMessageStore.h"
-#include "qpid/broker/RecoveryManager.h"
-#include "qpid/broker/TxPublish.h"
-#include "unit_test.h"
-#include <iostream>
-#include <list>
-#include <vector>
-#include "MessageUtils.h"
-#include "TestMessageStore.h"
-
-using std::list;
-using std::pair;
-using std::vector;
-using boost::intrusive_ptr;
-using namespace qpid::broker;
-using namespace qpid::framing;
-
-namespace qpid {
-namespace tests {
-
-struct TxPublishTest
-{
-
- TestMessageStore store;
- Queue::shared_ptr queue1;
- Queue::shared_ptr queue2;
- intrusive_ptr<Message> msg;
- TxPublish op;
-
- TxPublishTest() :
- queue1(new Queue("queue1", false, &store, 0)),
- queue2(new Queue("queue2", false, &store, 0)),
- msg(MessageUtils::createMessage("exchange", "routing_key", true)),
- op(msg)
- {
- op.deliverTo(queue1);
- op.deliverTo(queue2);
- }
-};
-
-
-QPID_AUTO_TEST_SUITE(TxPublishTestSuite)
-
-QPID_AUTO_TEST_CASE(testPrepare)
-{
- TxPublishTest t;
-
- intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(t.msg);
- //ensure messages are enqueued in store
- t.op.prepare(0);
- BOOST_CHECK_EQUAL((size_t) 2, t.store.enqueued.size());
- BOOST_CHECK_EQUAL(std::string("queue1"), t.store.enqueued[0].first);
- BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[0].second);
- BOOST_CHECK_EQUAL(std::string("queue2"), t.store.enqueued[1].first);
- BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[1].second);
- BOOST_CHECK_EQUAL( true, ( boost::static_pointer_cast<PersistableMessage>(t.msg))->isIngressComplete());
-}
-
-QPID_AUTO_TEST_CASE(testCommit)
-{
- TxPublishTest t;
-
- //ensure messages are delivered to queue
- t.op.prepare(0);
- t.op.commit();
- BOOST_CHECK_EQUAL((uint32_t) 1, t.queue1->getMessageCount());
- intrusive_ptr<Message> msg_dequeue = t.queue1->get().payload;
-
- BOOST_CHECK_EQUAL( true, (boost::static_pointer_cast<PersistableMessage>(msg_dequeue))->isIngressComplete());
- BOOST_CHECK_EQUAL(t.msg, msg_dequeue);
-
- BOOST_CHECK_EQUAL((uint32_t) 1, t.queue2->getMessageCount());
- BOOST_CHECK_EQUAL(t.msg, t.queue2->get().payload);
-}
-
-QPID_AUTO_TEST_SUITE_END()
-
-}} // namespace qpid::tests
diff --git a/cpp/src/tests/acl.py b/cpp/src/tests/acl.py
index 0e096a6f5b..102796cba6 100755
--- a/cpp/src/tests/acl.py
+++ b/cpp/src/tests/acl.py
@@ -119,6 +119,7 @@ class ACLTests(TestBase010):
def LookupPublish(self, userName, exchName, keyName, expectedResult):
result = self.acl_lookupPublish(userName, exchName, keyName)
if (result['result'] != expectedResult):
+ suffix = ', [ERROR: Expected= ' + expectedResult
if (result['result'] is None):
suffix = suffix + ', Exception= ' + result['text'] + ']'
else:
@@ -1703,6 +1704,546 @@ class ACLTests(TestBase010):
result = None
+ #=====================================
+ # User name substitution
+ #=====================================
+
+ def test_user_name_substitution(self):
+ """
+ Test name substitution internals, limits, and edge cases.
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ aclf.write('acl allow all create queue name=tmp-${userdomain}\n')
+ aclf.write('acl allow all create queue name=${userdomain}-tmp\n')
+ aclf.write('acl allow all create queue name=tmp-${userdomain}-tmp\n')
+ aclf.write('acl allow all create queue name=tmp-${userdomain}-tmp-${userdomain}\n')
+ aclf.write('acl allow all create queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all access queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all purge queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all consume queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all delete queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all create exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all access exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all bind exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all unbind exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all delete exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all publish exchange name=temp0-${userdomain}\n')
+
+ aclf.write('acl allow all publish exchange name=X routingkey=${userdomain}.cd.e\n')
+ aclf.write('acl allow all publish exchange name=X routingkey=a.*.${userdomain}\n')
+ aclf.write('acl allow all publish exchange name=X routingkey=b.#.${userdomain}\n')
+ aclf.write('acl allow all publish exchange name=X routingkey=*.${userdomain}.#.y\n')
+
+ aclf.write('acl allow all create queue name=user-${user}\n')
+ aclf.write('acl allow all publish exchange name=U routingkey=${user}.cd.e\n')
+ aclf.write('acl allow all publish exchange name=U routingkey=a.*.${user}\n')
+ aclf.write('acl allow all publish exchange name=U routingkey=b.#.${user}\n')
+ aclf.write('acl allow all publish exchange name=U routingkey=*.${user}.#.y\n')
+
+ aclf.write('acl allow all create queue name=domain-${domain}\n')
+ aclf.write('acl allow all publish exchange name=D routingkey=${domain}.cd.e\n')
+ aclf.write('acl allow all publish exchange name=D routingkey=a.*.${domain}\n')
+ aclf.write('acl allow all publish exchange name=D routingkey=b.#.${domain}\n')
+ aclf.write('acl allow all publish exchange name=D routingkey=*.${domain}.#.y\n')
+
+ # Resolving ${user}_${domain} into ${userdomain} works for everything but routing keys
+ aclf.write('acl allow all create queue name=mixed-OK-${user}_${domain}\n')
+ # For routing keys ${user}_${domain} will be parsed into ${userdomain}.
+ # Routing keys not be found when the rule specifies ${user}_${domain}.
+ aclf.write('acl allow all publish exchange name=NOGO routingkey=${user}_${domain}.cd.e\n')
+ # This works since it is does not conflict with ${userdomain}
+ aclf.write('acl allow all publish exchange name=OK routingkey=${user}___${domain}.cd.e\n')
+
+ aclf.write('acl deny-log all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ self.Lookup("alice@QPID", "create", "queue", "tmp-alice_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-tmp", {}, "allow")
+ self.Lookup("charlie@QPID", "create", "queue", "tmp-charlie_QPID-tmp", {}, "allow")
+ self.Lookup("dave@QPID", "create", "queue", "tmp-dave_QPID-tmp-dave_QPID", {}, "allow")
+ self.Lookup("ed@BIG.COM", "create", "queue", "tmp-ed_BIG_COM", {}, "allow")
+ self.Lookup("c.e.r@BIG.GER.COM", "create", "queue", "tmp-c_e_r_BIG_GER_COM", {}, "allow")
+ self.Lookup("c@", "create", "queue", "tmp-c_", {}, "allow")
+ self.Lookup("someuser", "create", "queue", "tmp-someuser", {}, "allow")
+
+ self.Lookup("alice@QPID", "create", "queue", "tmp-${user}", {}, "deny-log")
+
+ self.Lookup("bob@QPID", "create", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "delete", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.LookupPublish("bob@QPID", "temp0-bob_QPID", "x", "allow")
+
+ self.Lookup("bob@QPID", "create", "queue", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "access", "queue", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "purge", "queue", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "consume", "queue", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "delete", "queue", "temp0-bob_QPID", {}, "allow")
+
+ self.Lookup("alice@QPID", "access", "queue", "temp0-bob_QPID", {}, "deny-log")
+
+ # aclKey: "${userdomain}.cd.e"
+ self.LookupPublish("uPlain1@COMPANY", "X", "uPlain1_COMPANY.cd.e", "allow")
+ # aclKey: "a.*.${userdomain}"
+ self.LookupPublish("uStar1@COMPANY", "X", "a.xx.uStar1_COMPANY", "allow")
+ self.LookupPublish("uStar1@COMPANY", "X", "a.b", "deny-log")
+ # aclKey: "b.#.${userdomain}"
+ self.LookupPublish("uHash1@COMPANY", "X", "b.uHash1_COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "X", "b.x.uHash1_COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "X", "b..x.y.zz.uHash1_COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "X", "b.uHash1_COMPANY.", "deny-log")
+ self.LookupPublish("uHash1@COMPANY", "X", "q.x.uHash1_COMPANY", "deny-log")
+ # aclKey: "*.${userdomain}.#.y"
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.uMixed1_COMPANY.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.uMixed1_COMPANY.p.qq.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.a.uMixed1_COMPANY.y", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY", "X", "aa.uMixed1_COMPANY.b.c", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY.COM", "X", "a.uMixed1_COMPANY_COM.y", "allow")
+
+
+ self.Lookup("bob@QPID", "create", "queue", "user-bob", {}, "allow")
+ # aclKey: "${user}.cd.e"
+ self.LookupPublish("uPlain1@COMPANY", "U", "uPlain1.cd.e", "allow")
+ # aclKey: "a.*.${user}"
+ self.LookupPublish("uStar1@COMPANY", "U", "a.xx.uStar1", "allow")
+ self.LookupPublish("uStar1@COMPANY", "U", "a.b", "deny-log")
+ # aclKey: "b.#.${user}"
+ self.LookupPublish("uHash1@COMPANY", "U", "b.uHash1", "allow")
+ self.LookupPublish("uHash1@COMPANY", "U", "b.x.uHash1", "allow")
+ self.LookupPublish("uHash1@COMPANY", "U", "b..x.y.zz.uHash1", "allow")
+ self.LookupPublish("uHash1@COMPANY", "U", "b.uHash1.", "deny-log")
+ self.LookupPublish("uHash1@COMPANY", "U", "q.x.uHash1", "deny-log")
+ # aclKey: "*.${user}.#.y"
+ self.LookupPublish("uMixed1@COMPANY", "U", "a.uMixed1.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "U", "a.uMixed1.p.qq.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "U", "a.a.uMixed1.y", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY", "U", "aa.uMixed1.b.c", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY.COM", "U", "a.uMixed1.y", "allow")
+
+
+ self.Lookup("bob@QPID", "create", "queue", "domain-QPID", {}, "allow")
+ # aclKey: "${domain}.cd.e"
+ self.LookupPublish("uPlain1@COMPANY", "D", "COMPANY.cd.e", "allow")
+ # aclKey: "a.*.${domain}"
+ self.LookupPublish("uStar1@COMPANY", "D", "a.xx.COMPANY", "allow")
+ self.LookupPublish("uStar1@COMPANY", "D", "a.b", "deny-log")
+ # aclKey: "b.#.${domain}"
+ self.LookupPublish("uHash1@COMPANY", "D", "b.COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "D", "b.x.COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "D", "b..x.y.zz.COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "D", "b.COMPANY.", "deny-log")
+ self.LookupPublish("uHash1@COMPANY", "D", "q.x.COMPANY", "deny-log")
+ # aclKey: "*.${domain}.#.y"
+ self.LookupPublish("uMixed1@COMPANY", "D", "a.COMPANY.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "D", "a.COMPANY.p.qq.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "D", "a.a.COMPANY.y", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY", "D", "aa.COMPANY.b.c", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY.COM", "D", "a.COMPANY_COM.y", "allow")
+
+ self.Lookup("uPlain1@COMPANY", "create", "queue", "mixed-OK-uPlain1_COMPANY", {}, "allow")
+ self.LookupPublish("uPlain1@COMPANY", "NOGO", "uPlain1_COMPANY.cd.e", "deny-log")
+ self.LookupPublish("uPlain1@COMPANY", "OK", "uPlain1___COMPANY.cd.e", "allow")
+
+
+ #=====================================
+ # User name substitution details
+ #=====================================
+ # User name substitution allows for three flavors of keyword in the Acl file.
+ # Given a user name of bob.user@QPID.COM the keywords are normalized and resolve as follows:
+ # ${userdomain} - bob_user_QPID_COM
+ # ${user} - bob_user
+ # ${domain} - QPID_COM
+ #
+ # The following substitution tests are very similar but differ in the flavor of keyword used
+ # in the rules. The tests results using the different keywords differ slightly in how permissive
+ # the rules become.
+ # ${userdomain} limits access to one authenticated user
+ # ${user} limits access to a user name regardless of user's domain
+ # ${domain} limits access to a domain regardless of user name
+ #
+
+ def test_user_name_substitution_userdomain(self):
+ """
+ Test a setup where users can create, bind, and publish to a main exchange and queue.
+ Allow access to a single alternate exchange and queue.
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ # Create primary queue and exchange:
+ # allow predefined alternate
+ # deny any other alternate
+ # allow no alternate
+ aclf.write('acl allow all create queue name=${userdomain}-work alternate=${userdomain}-work2\n')
+ aclf.write('acl deny all create queue name=${userdomain}-work alternate=*\n')
+ aclf.write('acl allow all create queue name=${userdomain}-work\n')
+ aclf.write('acl allow all create exchange name=${userdomain}-work alternate=${userdomain}-work2\n')
+ aclf.write('acl deny all create exchange name=${userdomain}-work alternate=*\n')
+ aclf.write('acl allow all create exchange name=${userdomain}-work\n')
+ # Create backup queue and exchange
+ # Deny any alternate
+ aclf.write('acl deny all create queue name=${userdomain}-work2 alternate=*\n')
+ aclf.write('acl allow all create queue name=${userdomain}-work2\n')
+ aclf.write('acl deny all create exchange name=${userdomain}-work2 alternate=*\n')
+ aclf.write('acl allow all create exchange name=${userdomain}-work2\n')
+ # Bind/unbind primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${userdomain}-work routingkey=${userdomain} queuename=${userdomain}-work\n')
+ aclf.write('acl allow all unbind exchange name=${userdomain}-work routingkey=${userdomain} queuename=${userdomain}-work\n')
+ # Bind/unbind backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${userdomain}-work2 routingkey=${userdomain} queuename=${userdomain}-work2\n')
+ aclf.write('acl allow all unbind exchange name=${userdomain}-work2 routingkey=${userdomain} queuename=${userdomain}-work2\n')
+ # Access primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${userdomain}-work routingkey=${userdomain} queuename=${userdomain}-work\n')
+ # Access backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${userdomain}-work2 routingkey=${userdomain} queuename=${userdomain}-work2\n')
+ # Publish primary exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${userdomain}-work routingkey=${userdomain}\n')
+ # Publish backup exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${userdomain}-work2 routingkey=${userdomain}\n')
+ # deny mode
+ aclf.write('acl deny all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ # create queues
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work2", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "joe_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "joe_QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work3", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work", {"alternate":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work", {"alternate":"joe_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work2", {"alternate":"someexchange"}, "deny")
+ # create exchanges
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work2",{}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "joe_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "joe_QPID-work2",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work3",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work", {"alternate":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work2",{"alternate":"someexchange"}, "deny")
+ # bind/unbind/access
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", { "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "joe_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work"}, "deny")
+
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", { "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "joe_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work2"}, "deny")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", { "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "joe_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work"}, "deny")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", { "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "joe_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work2"}, "deny")
+
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", { "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "joe_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work"}, "deny")
+
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", { "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "joe_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work2"}, "deny")
+ # publish
+ self.LookupPublish("bob@QPID", "bob_QPID-work", "bob_QPID", "allow")
+ self.LookupPublish("bob@QPID", "bob_QPID-work2", "bob_QPID", "allow")
+ self.LookupPublish("bob@QPID", "joe_QPID-work", "bob_QPID", "deny")
+ self.LookupPublish("bob@QPID", "joe_QPID-work2", "bob_QPID", "deny")
+ self.LookupPublish("bob@QPID", "bob_QPID-work", "joe_QPID", "deny")
+ self.LookupPublish("bob@QPID", "bob_QPID-work2", "joe_QPID", "deny")
+
+
+ def test_user_name_substitution_user(self):
+ """
+ Test a setup where users can create, bind, and publish to a main exchange and queue.
+ Allow access to a single backup exchange and queue.
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ # Create primary queue and exchange
+ # allow predefined alternate
+ # deny any other alternate
+ # allow no alternate
+ aclf.write('acl allow all create queue name=${user}-work alternate=${user}-work2\n')
+ aclf.write('acl deny all create queue name=${user}-work alternate=*\n')
+ aclf.write('acl allow all create queue name=${user}-work\n')
+ aclf.write('acl allow all create exchange name=${user}-work alternate=${user}-work2\n')
+ aclf.write('acl deny all create exchange name=${user}-work alternate=*\n')
+ aclf.write('acl allow all create exchange name=${user}-work\n')
+ # Create backup queue and exchange
+ # Deny any alternate
+ aclf.write('acl deny all create queue name=${user}-work2 alternate=*\n')
+ aclf.write('acl allow all create queue name=${user}-work2\n')
+ aclf.write('acl deny all create exchange name=${user}-work2 alternate=*\n')
+ aclf.write('acl allow all create exchange name=${user}-work2\n')
+ # Bind/unbind primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${user}-work routingkey=${user} queuename=${user}-work\n')
+ aclf.write('acl allow all unbind exchange name=${user}-work routingkey=${user} queuename=${user}-work\n')
+ # Bind/unbind backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${user}-work2 routingkey=${user} queuename=${user}-work2\n')
+ aclf.write('acl allow all unbind exchange name=${user}-work2 routingkey=${user} queuename=${user}-work2\n')
+ # Access primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${user}-work routingkey=${user} queuename=${user}-work\n')
+ # Access backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${user}-work2 routingkey=${user} queuename=${user}-work2\n')
+ # Publish primary exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${user}-work routingkey=${user}\n')
+ # Publish backup exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${user}-work2 routingkey=${user}\n')
+ # deny mode
+ aclf.write('acl deny all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ # create queues
+ self.Lookup("bob@QPID", "create", "queue", "bob-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work2", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "joe-work", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "joe-work2", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work3", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work", {"alternate":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work", {"alternate":"joe-work2"}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work2", {"alternate":"someexchange"},"deny")
+ # create exchanges
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work2",{}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "joe-work", {}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "joe-work2",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work3",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work", {"alternate":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work2",{"alternate":"someexchange"},"deny")
+ # bind/unbind/access
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", { "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {"routingkey":"bob", "queuename":"bob-work"}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "joe-work", {"routingkey":"bob", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {"routingkey":"joe", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {"routingkey":"bob", "queuename":"joe-work"}, "deny")
+
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", { "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "joe-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {"routingkey":"joe", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"joe-work2"}, "deny")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", { "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {"routingkey":"bob", "queuename":"bob-work"}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "joe-work", {"routingkey":"bob", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {"routingkey":"joe", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {"routingkey":"bob", "queuename":"joe-work"}, "deny")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", { "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "joe-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {"routingkey":"joe", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"joe-work2"}, "deny")
+
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", { "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {"routingkey":"bob", "queuename":"bob-work"}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "joe-work", {"routingkey":"bob", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {"routingkey":"joe", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {"routingkey":"bob", "queuename":"joe-work"}, "deny")
+
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", { "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "joe-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {"routingkey":"joe", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"joe-work2"}, "deny")
+ # publish
+ self.LookupPublish("bob@QPID", "bob-work", "bob", "allow")
+ self.LookupPublish("bob@QPID", "bob-work2", "bob", "allow")
+ self.LookupPublish("bob@QPID", "joe-work", "bob", "deny")
+ self.LookupPublish("bob@QPID", "joe-work2", "bob", "deny")
+ self.LookupPublish("bob@QPID", "bob-work", "joe", "deny")
+ self.LookupPublish("bob@QPID", "bob-work2", "joe", "deny")
+
+
+ def test_user_name_substitution_domain(self):
+ """
+ Test a setup where users can create, bind, and publish to a main exchange and queue.
+ Allow access to a single backup exchange and queue.
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ # Create primary queue and exchange
+ # allow predefined alternate
+ # deny any other alternate
+ # allow no alternate
+ aclf.write('acl allow all create queue name=${domain}-work alternate=${domain}-work2\n')
+ aclf.write('acl deny all create queue name=${domain}-work alternate=*\n')
+ aclf.write('acl allow all create queue name=${domain}-work\n')
+ aclf.write('acl allow all create exchange name=${domain}-work alternate=${domain}-work2\n')
+ aclf.write('acl deny all create exchange name=${domain}-work alternate=*\n')
+ aclf.write('acl allow all create exchange name=${domain}-work\n')
+ # Create backup queue and exchange
+ # Deny any alternate
+ aclf.write('acl deny all create queue name=${domain}-work2 alternate=*\n')
+ aclf.write('acl allow all create queue name=${domain}-work2\n')
+ aclf.write('acl deny all create exchange name=${domain}-work2 alternate=*\n')
+ aclf.write('acl allow all create exchange name=${domain}-work2\n')
+ # Bind/unbind primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${domain}-work routingkey=${domain} queuename=${domain}-work\n')
+ aclf.write('acl allow all unbind exchange name=${domain}-work routingkey=${domain} queuename=${domain}-work\n')
+ # Bind/unbind backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${domain}-work2 routingkey=${domain} queuename=${domain}-work2\n')
+ aclf.write('acl allow all unbind exchange name=${domain}-work2 routingkey=${domain} queuename=${domain}-work2\n')
+ # Access primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${domain}-work routingkey=${domain} queuename=${domain}-work\n')
+ # Access backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${domain}-work2 routingkey=${domain} queuename=${domain}-work2\n')
+ # Publish primary exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${domain}-work routingkey=${domain}\n')
+ # Publish backup exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${domain}-work2 routingkey=${domain}\n')
+ # deny mode
+ aclf.write('acl deny all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ # create queues
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work2", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work3", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work", {"alternate":"QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work", {"alternate":"bob_QPID-work2"},"deny")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work", {"alternate":"joe_QPID-work2"},"deny")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work2", {"alternate":"someexchange"}, "deny")
+ # create exchanges
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work2",{}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work3",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work", {"alternate":"QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work2",{"alternate":"someexchange"}, "deny")
+ # bind/unbind/access
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work", { "queuename":"QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work", {"routingkey":"QPID", "queuename":"QPID-work"}, "allow")
+
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work2", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work2", { "queuename":"QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work2", {"routingkey":"QPID", "queuename":"QPID-work2"}, "allow")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work", { "queuename":"QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work", {"routingkey":"QPID", "queuename":"QPID-work"}, "allow")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work2", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work2", { "queuename":"QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work2", {"routingkey":"QPID", "queuename":"QPID-work2"}, "allow")
+
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work", { "queuename":"QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work", {"routingkey":"QPID", "queuename":"QPID-work"}, "allow")
+
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work2", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work2", { "queuename":"QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work2", {"routingkey":"QPID", "queuename":"QPID-work2"}, "allow")
+ # publish
+ self.LookupPublish("bob@QPID", "QPID-work", "QPID", "allow")
+ self.LookupPublish("bob@QPID", "QPID-work2", "QPID", "allow")
+ self.LookupPublish("joe@QPID", "QPID-work", "QPID", "allow")
+ self.LookupPublish("joe@QPID", "QPID-work2", "QPID", "allow")
+
+
class BrokerAdmin:
def __init__(self, broker, username=None, password=None):
self.connection = qpid.messaging.Connection(broker)
diff --git a/cpp/src/tests/cluster.cmake b/cpp/src/tests/cluster.cmake
deleted file mode 100644
index 31e2d337d1..0000000000
--- a/cpp/src/tests/cluster.cmake
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-#
-# Cluster tests cmake fragment, to be included in CMakeLists.txt
-#
-
-add_executable (failover_soak failover_soak.cpp ForkedBroker.cpp ${platform_test_additions})
-target_link_libraries (failover_soak qpidclient)
-remember_location(failover_soak)
-
-add_executable (cluster_authentication_soak cluster_authentication_soak.cpp ForkedBroker.cpp ${platform_test_additions})
-target_link_libraries (cluster_authentication_soak qpidclient)
-remember_location(cluster_authentication_soak)
-
-set (cluster_test_SOURCES
- cluster_test
- unit_test
- ClusterFixture
- ForkedBroker
- PartialFailure
- ClusterFailover
- InitialStatusMap
- StoreStatus
- )
-add_executable (cluster_test ${cluster_test_SOURCES} ${platform_test_additions})
-target_link_libraries (cluster_test ${qpid_test_boost_libs} qpidclient qpidbroker cluster_shared)
-remember_location(cluster_test)
-
-add_test (cluster_test ${CMAKE_CURRENT_SOURCE_DIR}/run_cluster_test${test_script_suffix})
-add_test (cluster_tests ${CMAKE_CURRENT_SOURCE_DIR}/run_cluster_tests${test_script_suffix})
-add_test (cluster_read_credit ${CMAKE_CURRENT_SOURCE_DIR}/cluster_read_credit${test_script_suffix})
-add_test (cluster_test_watchdog ${CMAKE_CURRENT_SOURCE_DIR}/test_watchdog${test_script_suffix})
-add_test (federated_cluster_test ${CMAKE_CURRENT_SOURCE_DIR}/federated_cluster_test${test_script_suffix})
-add_test (clustered_replication_test ${CMAKE_CURRENT_SOURCE_DIR}/clustered_replication_test${test_script_suffix})
-
-# FIXME aconway 2009-12-01: translate to cmake
-# # Clean up after cluster_test and start_cluster
-# CLEANFILES += cluster_test.acl cluster.ports
-
-# EXTRA_DIST += \
-# cpg_check.sh.in \
-# run_cluster_test \
-# cluster_read_credit \
-# test_watchdog \
-# start_cluster \
-# stop_cluster \
-# restart_cluster \
-# cluster_python_tests \
-# cluster_python_tests_failing.txt \
-# federated_cluster_test \
-# clustered_replication_test \
-# run_cluster_tests \
-# run_long_cluster_tests \
-# testlib.py \
-# cluster_tests.py \
-# long_cluster_tests.py \
-# cluster_tests.fail
-
-# LONG_TESTS += \
-# run_long_cluster_tests \
-# start_cluster \
-# cluster_python_tests \
-# stop_cluster
-
-# qpidtest_PROGRAMS += cluster_test
-
-# cluster_test_SOURCES = \
-
-# cluster_test_LDADD=$(lib_client) $(lib_broker) ../cluster.la -lboost_unit_test_framework
-
-# qpidtest_SCRIPTS += run_cluster_tests cluster_tests.py run_long_cluster_tests long_cluster_tests.py testlib.py cluster_tests.fail
-
-# endif
diff --git a/cpp/src/tests/cluster.mk b/cpp/src/tests/cluster.mk
deleted file mode 100644
index 852b2dda8c..0000000000
--- a/cpp/src/tests/cluster.mk
+++ /dev/null
@@ -1,102 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-# Include cluster scripts and extra files in distribution even if
-# we're not configured for cluster.
-
-# Useful scripts for doing cluster testing.
-CLUSTER_TEST_SCRIPTS_LIST= \
- allhosts rsynchosts \
- qpid-build-rinstall qpid-src-rinstall \
- qpid-test-cluster
-
-EXTRA_DIST += \
- $(CLUSTER_TEST_SCRIPTS_LIST) \
- cpg_check.sh.in \
- run_cluster_test \
- cluster_read_credit \
- test_watchdog \
- start_cluster \
- stop_cluster \
- restart_cluster \
- cluster_python_tests \
- cluster_python_tests_failing.txt \
- federated_cluster_test \
- clustered_replication_test \
- run_cluster_tests \
- run_long_cluster_tests \
- testlib.py \
- brokertest.py \
- cluster_tests.py \
- cluster_test_logs.py \
- long_cluster_tests.py \
- cluster_tests.fail
-
-
-if HAVE_LIBCPG
-
-#
-# Cluster tests makefile fragment, to be included in Makefile.am
-#
-
-# NOTE: Programs using the openais library must be run with gid=ais
-# You should do "newgrp ais" before running the tests to run these.
-#
-
-TESTS += \
- run_cluster_test \
- cluster_read_credit \
- test_watchdog \
- run_cluster_tests \
- federated_cluster_test \
- clustered_replication_test
-
-# Clean up after cluster_test and start_cluster
-CLEANFILES += cluster_test.acl cluster.ports
-
-LONG_TESTS += \
- run_long_cluster_tests \
- start_cluster \
- cluster_python_tests \
- stop_cluster
-
-qpidexectest_PROGRAMS += cluster_test
-
-cluster_test_SOURCES = \
- cluster_test.cpp \
- unit_test.cpp \
- ClusterFixture.cpp \
- ClusterFixture.h \
- ForkedBroker.h \
- ForkedBroker.cpp \
- PartialFailure.cpp \
- ClusterFailover.cpp \
- InitialStatusMap.cpp
-
-# Moved this file here from cluster_test_SOURCES as it breaks the autotools build, but not the cmake
-# build and so we need to make sure it is present in the tarball
-EXTRA_DIST += StoreStatus.cpp
-
-cluster_test_LDADD=$(lib_client) $(lib_broker) ../cluster.la -lboost_unit_test_framework
-
-qpidexectest_SCRIPTS += run_cluster_tests brokertest.py cluster_tests.py cluster_test_logs.py run_long_cluster_tests long_cluster_tests.py testlib.py cluster_tests.fail
-qpidexectest_SCRIPTS += $(CLUSTER_TEST_SCRIPTS_LIST)
-
-endif
diff --git a/cpp/src/tests/ha_tests.py b/cpp/src/tests/ha_tests.py
index d25281eed5..310ef844bd 100755
--- a/cpp/src/tests/ha_tests.py
+++ b/cpp/src/tests/ha_tests.py
@@ -111,9 +111,11 @@ class HaBroker(Broker):
def wait_status(self, status):
def try_get_status():
# Ignore ConnectionError, the broker may not be up yet.
- try: return self.ha_status() == status;
+ try:
+ self._status = self.ha_status()
+ return self._status == status;
except ConnectionError: return False
- assert retry(try_get_status, timeout=20), "%s status != %r"%(self, status)
+ assert retry(try_get_status, timeout=20), "%s %r != %r"%(self, self._status, status)
# FIXME aconway 2012-05-01: do direct python call to qpid-config code.
def qpid_config(self, args):
@@ -581,15 +583,7 @@ class ReplicationTests(BrokerTest):
s = primary.connect().session().sender("q; {create:always, node:{x-declare:{arguments:{'qpid.policy_type':ring, 'qpid.max_count':5, 'qpid.priorities':10}}}}")
priorities = [8,9,5,1,2,2,3,4,9,7,8,9,9,2]
for p in priorities: s.send(Message(priority=p))
-
- # FIXME aconway 2012-02-22: there is a bug in priority ring
- # queues that allows a low priority message to displace a high
- # one. The following commented-out assert_browse is for the
- # correct result, the uncommented one is for the actualy buggy
- # result. See https://issues.apache.org/jira/browse/QPID-3866
- #
- # expect = sorted(priorities,reverse=True)[0:5]
- expect = [9,9,9,9,2]
+ expect = sorted(priorities,reverse=True)[0:5]
primary.assert_browse("q", expect, transform=lambda m: m.priority)
backup.assert_browse_backup("q", expect, transform=lambda m: m.priority)
@@ -963,7 +957,7 @@ class RecoveryTests(BrokerTest):
"""
cluster = HaCluster(self, 3, args=["--ha-backup-timeout=0.5"]);
cluster[0].wait_status("active") # Primary ready
- for b in cluster[1:4]: b.wait_status("ready") # Backups ready
+ for b in cluster[1:3]: b.wait_status("ready") # Backups ready
for i in [0,1]: cluster.kill(i, False)
cluster[2].promote() # New primary, backups will be 1 and 2
cluster[2].wait_status("recovering")
diff --git a/cpp/src/tests/sasl.mk b/cpp/src/tests/sasl.mk
index 11731dcf40..8c31192635 100644
--- a/cpp/src/tests/sasl.mk
+++ b/cpp/src/tests/sasl.mk
@@ -20,13 +20,6 @@
# Test that are only relevant if SASL is enabled.
if HAVE_SASL
-if HAVE_LIBCPG
-check_PROGRAMS+=cluster_authentication_soak
-cluster_authentication_soak_INCLUDES=$(PUBLIC_INCLUDES)
-cluster_authentication_soak_SOURCES=cluster_authentication_soak.cpp ForkedBroker.h ForkedBroker.cpp
-cluster_authentication_soak_LDADD=$(lib_client) $(lib_broker)
-endif HAVE_LIBCPG
-
# Note: sasl_version is not a test -- it is a tool used by tests.
check_PROGRAMS+=sasl_version
sasl_version_SOURCES=sasl_version.cpp
@@ -39,30 +32,12 @@ TESTS += sasl_fed
sasl_fed_ex_route
sasl_no_dir
-if HAVE_LIBCPG
-
-TESTS += run_cluster_authentication_test \
- sasl_fed_ex_route_cluster \
- sasl_fed_ex_link_cluster \
- sasl_fed_ex_queue_cluster \
- sasl_fed_ex_dynamic_cluster
-
-LONG_TESTS += run_cluster_authentication_soak
-
-endif HAVE_LIBCPG
-
-EXTRA_DIST += run_cluster_authentication_test \
- sasl_fed \
+EXTRA_DIST += sasl_fed \
sasl_fed_ex \
- run_cluster_authentication_soak \
sasl_fed_ex_dynamic \
sasl_fed_ex_link \
sasl_fed_ex_queue \
sasl_fed_ex_route \
- sasl_fed_ex_dynamic_cluster \
- sasl_fed_ex_link_cluster \
- sasl_fed_ex_queue_cluster \
- sasl_fed_ex_route_cluster \
sasl_no_dir
diff --git a/cpp/src/tests/storePerftools/asyncPerf/MessageProducer.cpp b/cpp/src/tests/storePerftools/asyncPerf/MessageProducer.cpp
index b9a5e2a211..f5c47c796d 100644
--- a/cpp/src/tests/storePerftools/asyncPerf/MessageProducer.cpp
+++ b/cpp/src/tests/storePerftools/asyncPerf/MessageProducer.cpp
@@ -25,6 +25,7 @@
#include "TestOptions.h"
+#include "qpid/asyncStore/PersistableMessageContext.h"
#include "qpid/broker/SimpleMessage.h"
#include "qpid/broker/SimpleQueue.h"
#include "qpid/broker/SimpleTxnBuffer.h"
@@ -65,7 +66,10 @@ MessageProducer::runProducers() {
tb = new qpid::broker::SimpleTxnBuffer(m_resultQueue);
}
for (uint32_t numMsgs=0; numMsgs<m_perfTestParams.m_numMsgs && !m_stopFlag; ++numMsgs) {
- boost::intrusive_ptr<qpid::broker::SimpleMessage> msg(new qpid::broker::SimpleMessage(m_msgData, m_perfTestParams.m_msgSize, m_store));
+ boost::intrusive_ptr<qpid::asyncStore::PersistableMessageContext> msgCtxt(new qpid::asyncStore::PersistableMessageContext(m_store));
+ boost::intrusive_ptr<qpid::broker::AsyncCompletion> ingressCompl(new qpid::broker::AsyncCompletion);
+ msgCtxt->setIngressCompletion(ingressCompl);
+ boost::intrusive_ptr<qpid::broker::SimpleMessage> msg(new qpid::broker::SimpleMessage(m_msgData, m_perfTestParams.m_msgSize, msgCtxt));
if (useTxns) {
boost::shared_ptr<qpid::broker::SimpleTxnPublish> op(new qpid::broker::SimpleTxnPublish(msg));
op->deliverTo(m_queue);
diff --git a/cpp/src/tests/test_store.cpp b/cpp/src/tests/test_store.cpp
index 257e77b6b4..83f6a5e4b1 100644
--- a/cpp/src/tests/test_store.cpp
+++ b/cpp/src/tests/test_store.cpp
@@ -34,6 +34,7 @@
#include "qpid/broker/NullMessageStore.h"
#include "qpid/broker/Broker.h"
+#include "qpid/broker/amqp_0_10/MessageTransfer.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/log/Statement.h"
#include "qpid/Plugin.h"
@@ -95,7 +96,7 @@ class TestStore : public NullMessageStore {
const boost::intrusive_ptr<PersistableMessage>& pmsg,
const PersistableQueue& )
{
- Message* msg = dynamic_cast<Message*>(pmsg.get());
+ qpid::broker::amqp_0_10::MessageTransfer* msg = dynamic_cast<qpid::broker::amqp_0_10::MessageTransfer*>(pmsg.get());
assert(msg);
// Dump the message if there is a dump file.
diff --git a/doc/book/src/cpp-broker/.gitignore b/doc/book/src/cpp-broker/.gitignore
index 1f57b975cd..6d31bdba7f 100644
--- a/doc/book/src/cpp-broker/.gitignore
+++ b/doc/book/src/cpp-broker/.gitignore
@@ -1 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
/output
diff --git a/doc/book/src/java-broker/HA-Guide.xml b/doc/book/src/java-broker/HA-Guide.xml
index 429f2f76c2..041309d711 100644
--- a/doc/book/src/java-broker/HA-Guide.xml
+++ b/doc/book/src/java-broker/HA-Guide.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urls [
<!ENTITY oracleBdbProductOverviewUrl "http://www.oracle.com/technetwork/products/berkeleydb/overview/index-093405.html">
-<!ENTITY oracleBdbProductVersion "5.0.48">
+<!ENTITY oracleBdbProductVersion "5.0.58">
<!ENTITY oracleBdbRepGuideUrl "http://oracle.com/cd/E17277_02/html/ReplicationGuide/">
<!ENTITY oracleBdbJavaDocUrl "http://docs.oracle.com/cd/E17277_02/html/java/">
<!ENTITY oracleJdkDocUrl "http://oracle.com/javase/6/docs/api/">
@@ -26,8 +26,9 @@
under the License.
-->
-<section>
+<section id="High-Availability">
<title>High Availability</title>
+
<section role="h3" id="HAGeneralIntroduction">
<title>General Introduction</title>
<para>The term High Availability (HA) usually refers to having a number of instances of a service such as a Message Broker
@@ -40,6 +41,7 @@
some kind of standby state, awaiting to quickly step-in in the event the active node becomes unavailable.
</para>
</section>
+
<section role="h3" id="HAOfferingsOfJavaBroker">
<title>HA offerings of the Java Broker</title>
<para>The Java Broker's HA offering became available at release <emphasis role="bold">0.18</emphasis>. HA is provided by way of the HA
@@ -60,6 +62,7 @@
<para>HA is not currently available for those using the the <emphasis role="bold">Derby Store</emphasis> or <emphasis role="bold">Memory
Message Store</emphasis>.</para>
</section>
+
<section role="h3" id="HATwoNodeCluster">
<title>Two Node Cluster</title>
<section role="h4">
@@ -283,11 +286,13 @@
</section>
</section>
</section>
+
<section role="h3" id="HAMultiNodeCluster">
<title>Multi Node Cluster</title>
<para>Multi node clusters, that is clusters where the number of nodes is three or more, are not yet
ready for use.</para>
</section>
+
<section role="h3" id="HAConfiguration">
<title>Configuring a Virtual Host to be a node</title>
<para>To configure a virtualhost as a cluster node, configure the virtualhost.xml in the following manner:</para>
@@ -385,6 +390,7 @@
</store>]]></programlisting>
</section>
</section>
+
<section role="h3" id="HADurabilityGuarantee">
<title>Durability Guarantees</title>
<para>The term <ulink url="http://en.wikipedia.org/wiki/ACID#Durability">durability</ulink> is used to mean that once a
@@ -480,6 +486,7 @@
</para>
</section>
</section>
+
<section id="HAClientFailover">
<title>Client failover configuration</title>
<para>The details about format of Qpid connection URLs can be found at section
@@ -495,6 +502,8 @@
amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672?connectdelay='2000'&retries='3';tcp://localhost:5671?connectdelay='2000'&retries='3';tcp://localhost:5673?connectdelay='2000'&retries='3''&failover='roundrobin?cyclecount='30''
]]></example>
</section>
+
+
<section role="h3" id="HAJMXAPI">
<title>Qpid JMX API for HA</title>
<para>Qpid exposes the BDB HA store information via its JMX interface and provides APIs to remove a Node from
@@ -569,6 +578,7 @@ amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672?connectdelay='
</tr>
</tbody>
</table>
+
<table border="1">
<title>Mbean <classname>BDBHAMessageStore</classname> operations</title>
<thead>
@@ -592,15 +602,15 @@ amqp://guest:guest@clientid/test?brokerlist='tcp://localhost:5672?connectdelay='
<td>updateAddress</td>
<td>
<itemizedlist>
- <itemizedlist>
+ <listitem>
<para><emphasis>nodeName</emphasis>, name of node, string</para>
- </itemizedlist>
- <itemizedlist>
+ </listitem>
+ <listitem>
<para><emphasis>newHostName</emphasis>, new host name, string</para>
- </itemizedlist>
- <itemizedlist>
+ </listitem>
+ <listitem>
<para><emphasis>newPort</emphasis>, new port number, int</para>
- </itemizedlist>
+ </listitem>
</itemizedlist>
</td>
<td>void</td>
@@ -632,6 +642,7 @@ System.out.println("Node state:" + state);
<screen><![CDATA[Node state:MASTER]]></screen>
</example>
</section>
+
<section id="BDB-HA-Monitoring-cluster">
<title>Monitoring cluster</title>
<para>In order to discover potential issues with HA Cluster early, all nodes in the Cluster should be monitored on regular basis
@@ -704,6 +715,7 @@ Current state of node: Node-5001 from group: TestClusterGroup
</listitem>
</itemizedlist>
</section>
+
<section id="HADiskSpace">
<title>Disk space requirements</title>
<para>Disk space is a critical resource for the HA Qpid broker.</para>
@@ -717,6 +729,7 @@ Current state of node: Node-5001 from group: TestClusterGroup
Please, make sure to allocate enough space on your disk to avoid this from happening.
</para>
</section>
+
<section id="BDB-HA-Network-Requirements">
<title>Network Requirements</title>
<para>The HA Cluster performance depends on the network bandwidth, its use by existing traffic, and quality of service.</para>
@@ -724,6 +737,7 @@ Current state of node: Node-5001 from group: TestClusterGroup
which might include installation of dedicated network hardware on Broker hosts, assigning a higher priority to replication ports,
installing a cluster in a separate network not impacted by any other traffic.</para>
</section>
+
<section id="BDB-HA-Security">
<title>Security</title>
<para>At the moment Berkeley replication API supports only TCP/IP protocol to transfer replication data between Master and Replicas.</para>
@@ -731,6 +745,7 @@ Current state of node: Node-5001 from group: TestClusterGroup
<para>Also, anyone who can access to this network can introduce a new node and therefore receive a copy of the data.</para>
<para>In order to reduce the security risks the entire HA cluster is recommended to run in a separate network protected from general access.</para>
</section>
+
<section id="BDB-HA-Backup">
<title>Backups</title>
<para>In order to protect the entire cluster from some cataclysms which might destroy all cluster nodes,
@@ -752,6 +767,7 @@ Current state of node: Node-5001 from group: TestClusterGroup
the lifecycle of the cluster.</para>
</note>
</section>
+
<section id="HAMigrationFromNonHA">
<title>Migration of a non-HA store to HA</title>
<para>Non HA stores starting from schema version 4 (0.14 Qpid release) can be automatically converted into HA store on broker startup if replication is first enabled with the <ulink url="&oracleBdbJavaDocUrl;com/sleepycat/je/rep/util/DbEnableReplication.html"><classname>DbEnableReplication</classname></ulink> utility from the BDB JE jar.</para>
@@ -782,6 +798,7 @@ java -jar je-&oracleBdbProductVersion;.jar DbEnableReplication -h /path/to/store
<para>Due to existing caveats in Berkeley JE with copying of data from Master into Replica it is recommended to restart the Master node after store schema upgrade is finished before starting the Replica nodes.</para>
</note>
</section>
+
<section id="HADisasterRecovery">
<title>Disaster Recovery</title>
<para>This section describes the steps required to restore HA broker cluster from backup.</para>
@@ -987,4 +1004,5 @@ java -cp je-&oracleBdbProductVersion;.jar com.sleepycat.je.rep.util.DbResetRepGr
With this mode enabled, Qpid broker batches the concurrent transaction commits and syncs transaction data into Master disk in one go.
As result, the HA performance only drops by 25-60% for durability <emphasis>NO_SYNC,NO_SYNC,ALL</emphasis> and by 10-90% for <emphasis>WRITE_NO_SYNC,WRITE_NO_SYNC,ALL</emphasis>.</para>
</section>
+
</section>
diff --git a/doc/book/src/java-broker/images/HA-2N-Key.svg b/doc/book/src/java-broker/images/HA-2N-Key.svg
index 9567f385d5..ed471192e2 100644
--- a/doc/book/src/java-broker/images/HA-2N-Key.svg
+++ b/doc/book/src/java-broker/images/HA-2N-Key.svg
@@ -1,3 +1,23 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="-7 -3 435 195" width="435pt" height="195pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-05-31 06:19Z</dc:date><!-- Produced by OmniGraffle Professional 5.3.6 --></metadata><defs><filter id="Shadow" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" result="blur" stdDeviation="3.488"/><feOffset in="blur" result="offset" dx="0" dy="4"/><feFlood flood-color="black" flood-opacity=".75" result="flood"/><feComposite in="flood" in2="offset" operator="in"/></filter><linearGradient x1="0" x2="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#2824aa"/></linearGradient><linearGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(52.803375 70.5) rotate(90) scale(24)"/><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="522.94922" cap-height="717.28516" ascent="770.01953" descent="-229.98047" font-weight="500"><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face><linearGradient x1="0" x2="1" id="Gradient_2" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#0caa25"/></linearGradient><linearGradient id="Obj_Gradient_2" xl:href="#Gradient_2" gradientTransform="translate(127.99037 28.999998) rotate(90) scale(25.5938)"/><linearGradient x1="0" x2="1" id="Gradient_3" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa172d"/></linearGradient><linearGradient id="Obj_Gradient_3" xl:href="#Gradient_3" gradientTransform="translate(160.86441 28.999998) rotate(90) scale(25.5938)"/><linearGradient x1="0" x2="1" id="Gradient_4" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6923aa"/></linearGradient><linearGradient id="Obj_Gradient_4" xl:href="#Gradient_4" gradientTransform="translate(52.803375 107.5) rotate(90) scale(24)"/><radialGradient cx="0" cy="0" r="1" id="Gradient_5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#b5d0ea"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient_5" xl:href="#Gradient_5" gradientTransform="translate(56.678375 41.796898) scale(37.736065)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="Arrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black"><g><path d="M 8 0 L 0 -3 L 0 3 Z" fill="none" stroke="currentColor" stroke-width="1"/></g></marker><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -3 6 6" markerWidth="6" markerHeight="6" color="black"><g><path d="M 3.7333333 0 L 0 -1.4 L 0 1.4 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><linearGradient x1="0" x2="1" id="Gradient_6" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#b5011d"/></linearGradient><linearGradient id="Obj_Gradient_6" xl:href="#Gradient_6" gradientTransform="translate(287.5 113.94637) rotate(90) scale(26.035202)"/><radialGradient cx="0" cy="0" r="1" id="Gradient_7" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#ea061f"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient_7" xl:href="#Gradient_7" gradientTransform="translate(280 41) scale(26.907248)"/><font-face font-family="Arial Unicode MS" font-size="36" panose-1="2 11 6 4 2 2 2 2 2 4" units-per-em="1000" underline-position="-100.097656" underline-thickness="49.804688" slope="0" x-height="529.78516" cap-height="728.02734" ascent="1068.84766" descent="-270.9961" font-weight="500"><font-face-src><font-face-name name="ArialUnicodeMS"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 7</title><g><title>Layer 1</title><g><use xl:href="#id240_Graphic" filter="url(#Shadow)"/><use xl:href="#id239_Graphic" filter="url(#Shadow)"/><use xl:href="#id238_Graphic" filter="url(#Shadow)"/><use xl:href="#id237_Graphic" filter="url(#Shadow)"/><use xl:href="#id236_Graphic" filter="url(#Shadow)"/><use xl:href="#id235_Graphic" filter="url(#Shadow)"/><use xl:href="#id229_Graphic" filter="url(#Shadow)"/><use xl:href="#id227_Graphic" filter="url(#Shadow)"/></g><g id="id240_Graphic"><rect x="13.999878" y="13" width="394.00012" height="155" fill="white"/><rect x="13.999878" y="13" width="394.00012" height="155" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/></g><g id="id239_Graphic"><rect x="28.177876" y="70.5" width="49.251003" height="24" fill="url(#Obj_Gradient)"/><rect x="28.177876" y="70.5" width="49.251003" height="24" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(33.177876 75.5)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x="1.9536247" y="11" textLength="35.34375">Broker</tspan></text></g><g id="id238_Graphic"><path d="M 115.652176 41.796898 L 121.821274 28.999998 L 134.15947 28.999998 L 140.32857 41.796898 L 134.15947 54.593796 L 121.821274 54.593796 Z" fill="url(#Obj_Gradient_2)"/><path d="M 115.652176 41.796898 L 121.821274 28.999998 L 134.15947 28.999998 L 140.32857 41.796898 L 134.15947 54.593796 L 121.821274 54.593796 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/></g><g id="id237_Graphic"><path d="M 148.526215 41.796898 L 154.69531 28.999998 L 167.03351 28.999998 L 173.20261 41.796898 L 167.03351 54.593796 L 154.69531 54.593796 Z" fill="url(#Obj_Gradient_3)"/><path d="M 148.526215 41.796898 L 154.69531 28.999998 L 167.03351 28.999998 L 173.20261 41.796898 L 167.03351 54.593796 L 154.69531 54.593796 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/></g><g id="id236_Graphic"><path d="M 32.853378 107.5 L 72.753372 107.5 C 77.472977 107.5 81.303375 112.876 81.303375 119.5 C 81.303375 126.124 77.472977 131.5 72.753372 131.5 L 32.853378 131.5 C 28.133776 131.5 24.303375 126.124 24.303375 119.5 C 24.303375 112.876 28.133776 107.5 32.853378 107.5" fill="url(#Obj_Gradient_4)"/><path d="M 32.853378 107.5 L 72.753372 107.5 C 77.472977 107.5 81.303375 112.876 81.303375 119.5 C 81.303375 126.124 77.472977 131.5 72.753372 131.5 L 32.853378 131.5 C 28.133776 131.5 24.303375 126.124 24.303375 119.5 C 24.303375 112.876 28.133776 107.5 32.853378 107.5" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(35.003376 112.5)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x="2.4601574" y="11" textLength="30.679688">Client</tspan></text></g><g id="id235_Graphic"><path d="M 30.434645 43.17154 C 18.959625 41.796898 23.535576 30.224663 41.840797 32.199223 C 43.539116 28.35017 64.825623 28.974915 64.686462 32.199223 C 78.033752 28.075294 95.09079 36.298325 83.649857 40.422256 C 97.37842 42.421642 83.476616 53.194073 72.209625 51.394573 C 71.307922 54.39391 51.165936 55.443512 49.398033 51.394573 C 37.992596 55.718647 14.210434 49.070145 30.434645 43.17154 Z" fill="url(#Obj_Gradient_5)"/><path d="M 30.434645 43.17154 C 18.959625 41.796898 23.535576 30.224663 41.840797 32.199223 C 43.539116 28.35017 64.825623 28.974915 64.686462 32.199223 C 78.033752 28.075294 95.09079 36.298325 83.649857 40.422256 C 97.37842 42.421642 83.476616 53.194073 72.209625 51.394573 C 71.307922 54.39391 51.165936 55.443512 49.398033 51.394573 C 37.992596 55.718647 14.210434 49.070145 30.434645 43.17154 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(36.828377 34.796898)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x=".84511757" y="11" textLength="38.009766">Cluster</tspan></text></g><text transform="translate(194.40121 29)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="11" textLength="8.0039062">V</tspan><tspan font-family="Helvetica" font-size="12" font-weight="500" x="7.7929688" y="11" textLength="26.009766">irtual</tspan><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="25" textLength="22.68164">host</tspan></text><line x1="115.65217" y1="84" x2="162.7522" y2="84" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><line x1="114.77717" y1="114.406006" x2="155.878815" y2="114.99225" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><text transform="translate(181.40121 70.5)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="11" textLength="59.367188">Replication</tspan><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="25" textLength="36.673828">stream</tspan></text><text transform="translate(181.90121 93.906006)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="25" textLength="30.679688">Client</tspan><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="39" textLength="58.04297">connection</tspan></text><g id="id229_Graphic"><path d="M 257.6145 123.341385 L 303.64609 123.13183 C 303.64609 123.13183 305.97821 110.84691 310.80124 114.69145 C 315.62408 118.53591 319 121.44636 319 121.44636 L 315.92612 122.44486 L 307.22827 122.069695 L 307.22821 132.69258 L 315.47678 133.06787 C 315.47678 133.06787 315.92618 136.46542 315.92618 136.78604 C 315.92618 137.10628 311.77792 139.65259 309.63474 139.972885 C 307.49097 140.29318 304.06018 131.63016 304.06018 131.63039 C 304.06018 131.63039 257.61444 130.06921 257.48056 130.06921 C 257.34662 130.06921 256.13666 132.15001 256.00693 126.86558 C 255.87709 121.581276 257.6145 123.341385 257.6145 123.341385 Z" fill="url(#Obj_Gradient_6)"/><path d="M 257.6145 123.341385 L 303.64609 123.13183 C 303.64609 123.13183 305.97821 110.84691 310.80124 114.69145 C 315.62408 118.53591 319 121.44636 319 121.44636 L 315.92612 122.44486 L 307.22827 122.069695 L 307.22821 132.69258 L 315.47678 133.06787 C 315.47678 133.06787 315.92618 136.46542 315.92618 136.78604 C 315.92618 137.10628 311.77792 139.65259 309.63474 139.972885 C 307.49097 140.29318 304.06018 131.63016 304.06018 131.63039 C 304.06018 131.63039 257.61444 130.06921 257.48056 130.06921 C 257.34662 130.06921 256.13666 132.15001 256.00693 126.86558 C 255.87709 121.581276 257.6145 123.341385 257.6145 123.341385 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/></g><text transform="translate(334.09879 119.963974)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="11" textLength="35.34961">Repair</tspan></text><g id="id227_Graphic"><path d="M 260 32.310394 L 275.19995 42.241386 L 263.13727 54.738464 L 267.99988 59 L 281.17648 45.481422 L 295.20001 54.655197 L 300 49.68975 L 284.79993 39.137974 L 297.59991 27.965553 L 290.39993 23 L 279.19989 35.413807 L 266.4 25.482777 Z" fill="url(#Obj_Gradient_7)"/><path d="M 260 32.310394 L 275.19995 42.241386 L 263.13727 54.738464 L 267.99988 59 L 281.17648 45.481422 L 295.20001 54.655197 L 300 49.68975 L 284.79993 39.137974 L 297.59991 27.965553 L 290.39993 23 L 279.19989 35.413807 L 266.4 25.482777 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/></g><text transform="translate(329.02448 34)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="11" textLength="26.677734">Fault</tspan></text><text transform="translate(264 59.5)" fill="#262626"><tspan font-family="Arial Unicode MS" font-size="36" font-weight="500" fill="#262626" x="0" y="38" textLength="36">â™›</tspan></text><text transform="translate(320.52448 72)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="11" textLength="54.035156">Designate</tspan><tspan font-family="Helvetica" font-size="12" font-weight="500" x="0" y="25" textLength="41.332031">Primary</tspan></text></g></g></svg>
diff --git a/doc/book/src/java-broker/images/HA-2N-MasterFail.svg b/doc/book/src/java-broker/images/HA-2N-MasterFail.svg
index 35b2c643ff..c3fc0c66f3 100644
--- a/doc/book/src/java-broker/images/HA-2N-MasterFail.svg
+++ b/doc/book/src/java-broker/images/HA-2N-MasterFail.svg
@@ -1,3 +1,23 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="-20 -16 600 871" width="50pc" height="871pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-05-31 06:19Z</dc:date><!-- Produced by OmniGraffle Professional 5.3.6 --></metadata><defs><radialGradient cx="0" cy="0" r="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#b5d0ea"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(200.35501 136.5) scale(145.18695)"/><linearGradient x1="0" x2="1" id="Gradient_2" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#2824aa"/></linearGradient><linearGradient id="Obj_Gradient_2" xl:href="#Gradient_2" gradientTransform="translate(212.855 146) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_3" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#0caa25"/></linearGradient><linearGradient id="Obj_Gradient_3" xl:href="#Gradient_3" gradientTransform="translate(212.85451 162.5) rotate(90) scale(36)"/><linearGradient x1="0" x2="1" id="Gradient_4" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6923aa"/></linearGradient><linearGradient id="Obj_Gradient_4" xl:href="#Gradient_4" gradientTransform="translate(73.18171 111) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient_2" gradientTransform="translate(195.355 59.999996) rotate(90) scale(69.000007)"/><linearGradient x1="0" x2="1" id="Gradient_5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa172d"/></linearGradient><linearGradient id="Obj_Gradient_6" xl:href="#Gradient_5" gradientTransform="translate(195.35451 78) rotate(90) scale(36)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -3 6 6" markerWidth="6" markerHeight="6" color="black"><g><path d="M 3.7333333 0 L 0 -1.4 L 0 1.4 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="Arrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black"><g><path d="M 8 0 L 0 -3 L 0 3 Z" fill="none" stroke="currentColor" stroke-width="1"/></g></marker><radialGradient id="Obj_Gradient_7" xl:href="#Gradient" gradientTransform="translate(470.5 133.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_8" xl:href="#Gradient_2" gradientTransform="translate(488 141.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_6" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaa3a7"/></linearGradient><linearGradient id="Obj_Gradient_9" xl:href="#Gradient_6" gradientTransform="translate(487.9995 158) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_10" xl:href="#Gradient_4" gradientTransform="translate(350.21 85) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_11" xl:href="#Gradient_2" gradientTransform="translate(470.5 55.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_7" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaaaa3"/></linearGradient><linearGradient id="Obj_Gradient_12" xl:href="#Gradient_7" gradientTransform="translate(470.4995 73.5) rotate(90) scale(36)"/><radialGradient cx="0" cy="0" r="1" id="Gradient_8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#ea061f"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient_13" xl:href="#Gradient_8" gradientTransform="translate(488 176) scale(38.183766)"/><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face><radialGradient id="Obj_Gradient_14" xl:href="#Gradient" gradientTransform="translate(474.08 415.255) scale(145.18695)"/><linearGradient id="Obj_Gradient_15" xl:href="#Gradient_2" gradientTransform="translate(491.58 423.255) rotate(90) scale(69)"/><linearGradient id="Obj_Gradient_16" xl:href="#Gradient_6" gradientTransform="translate(491.5795 439.755) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_17" xl:href="#Gradient_4" gradientTransform="translate(353.79 366.755) rotate(90) scale(24.00003)"/><linearGradient id="Obj_Gradient_18" xl:href="#Gradient_2" gradientTransform="translate(474.08 337.255) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_9" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#21aa1a"/></linearGradient><linearGradient id="Obj_Gradient_19" xl:href="#Gradient_9" gradientTransform="translate(474.0795 355.255) rotate(90) scale(36)"/><radialGradient id="Obj_Gradient_20" xl:href="#Gradient" gradientTransform="translate(192.79001 696.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_21" xl:href="#Gradient_2" gradientTransform="translate(210.28999 704.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_10" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa1f43"/></linearGradient><linearGradient id="Obj_Gradient_22" xl:href="#Gradient_10" gradientTransform="translate(210.2895 721) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_23" xl:href="#Gradient_4" gradientTransform="translate(72.5 648) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_24" xl:href="#Gradient_2" gradientTransform="translate(192.78999 618.5) rotate(90) scale(69)"/><linearGradient id="Obj_Gradient_25" xl:href="#Gradient_9" gradientTransform="translate(192.7895 636.5) rotate(90) scale(36)"/><radialGradient id="Obj_Gradient_26" xl:href="#Gradient" gradientTransform="translate(166.45009 415.255) scale(145.18695)"/><linearGradient id="Obj_Gradient_27" xl:href="#Gradient_2" gradientTransform="translate(183.95009 423.255) rotate(90) scale(69)"/><linearGradient id="Obj_Gradient_28" xl:href="#Gradient_6" gradientTransform="translate(183.9496 439.755) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_29" xl:href="#Gradient_4" gradientTransform="translate(72.5 372.755) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_30" xl:href="#Gradient_2" gradientTransform="translate(180.08009 343.255) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_11" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#a9a5a6"/></linearGradient><linearGradient id="Obj_Gradient_31" xl:href="#Gradient_11" gradientTransform="translate(180.0796 361.255) rotate(90) scale(36)"/><radialGradient id="Obj_Gradient_32" xl:href="#Gradient_8" gradientTransform="translate(183.95009 457.755) scale(38.183766)"/><font-face font-family="Arial Unicode MS" font-size="36" panose-1="2 11 6 4 2 2 2 2 2 4" units-per-em="1000" underline-position="-100.097656" underline-thickness="49.804688" slope="0" x-height="529.78516" cap-height="728.02734" ascent="1068.84766" descent="-270.9961" font-weight="500"><font-face-src><font-face-name name="ArialUnicodeMS"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 2</title><g><title>Layer 1</title><rect x="0" y="0" width="278" height="273" fill="white"/><rect x="0" y="0" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 146.38904 149.98122 C 122.79251 136.5 132.20221 23.010353 169.84393 42.375 C 173.33626 4.6271057 217.1085 10.754013 216.82236 42.375 C 244.26889 1.931366 279.34393 82.575165 255.81749 123.01879 C 284.04803 142.62691 255.46124 248.27281 232.29251 230.625 C 230.43831 260.03967 189.01958 270.33319 185.38417 230.625 C 161.930725 273.03143 113.02657 207.82918 146.38904 149.98122 Z" fill="url(#Obj_Gradient)"/><path d="M 146.38904 149.98122 C 122.79251 136.5 132.20221 23.010353 169.84393 42.375 C 173.33626 4.6271057 217.1085 10.754013 216.82236 42.375 C 244.26889 1.931366 279.34393 82.575165 255.81749 123.01879 C 284.04803 142.62691 255.46124 248.27281 232.29251 230.625 C 230.43831 260.03967 189.01958 270.33319 185.38417 230.625 C 161.930725 273.03143 113.02657 207.82918 146.38904 149.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="179.355" y="146" width="67" height="69" fill="url(#Obj_Gradient_2)"/><rect x="179.355" y="146" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 192.524 180.5 L 202.68925 162.5 L 223.01976 162.5 L 233.18501 180.5 L 223.01976 198.5 L 202.68925 198.5 Z" fill="url(#Obj_Gradient_3)"/><path d="M 192.524 180.5 L 202.68925 162.5 L 223.01976 162.5 L 233.18501 180.5 L 223.01976 198.5 L 202.68925 198.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 62.68171 111 L 83.68171 111 C 86.16571 111 88.18171 116.376 88.18171 123 C 88.18171 129.62399 86.16571 135 83.68171 135 L 62.68171 135 C 60.197708 135 58.18171 129.62399 58.18171 123 C 58.18171 116.376 60.197708 111 62.68171 111" fill="url(#Obj_Gradient_4)"/><path d="M 62.68171 111 L 83.68171 111 C 86.16571 111 88.18171 116.376 88.18171 123 C 88.18171 129.62399 86.16571 135 83.68171 135 L 62.68171 135 C 60.197708 135 58.18171 129.62399 58.18171 123 C 58.18171 116.376 60.197708 111 62.68171 111" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="161.855" y="60" width="67" height="69" fill="url(#Obj_Gradient_5)"/><rect x="161.855" y="60" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 175.024 96 L 185.18925 78 L 205.51976 78 L 215.68501 96 L 205.51976 114 L 185.18925 114 Z" fill="url(#Obj_Gradient_6)"/><path d="M 175.024 96 L 185.18925 78 L 205.51976 78 L 215.68501 96 L 205.51976 114 L 185.18925 114 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 74.355003 137 C 80.38701 150.765915 72.80871 171.11536 92.452835 178.3019 C 109.12348 184.40063 145.40762 181.02281 176.33522 180.23158" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 222.38084 162.05576 C 227.03842 153.03807 238.59448 143.85422 236.355 135 C 234.66139 128.303986 225.07715 121.79347 216.5538 115.25858" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="281.29001" y="0" width="278.00003" height="273" fill="white"/><rect x="281.29001" y="0" width="278.00003" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 416.53403 146.98122 C 392.9375 133.5 402.3472 20.010353 439.98892 39.375 C 443.48123 1.6271057 487.2535 7.754013 486.96735 39.375 C 514.41388 -1.06863403 549.4889 79.575165 525.96246 120.01879 C 554.19305 139.62691 525.60626 245.27281 502.4375 227.625 C 500.5833 257.03967 459.16455 267.33319 455.52917 227.625 C 432.07571 270.03143 383.17157 204.82918 416.53403 146.98122 Z" fill="url(#Obj_Gradient_7)"/><path d="M 416.53403 146.98122 C 392.9375 133.5 402.3472 20.010353 439.98892 39.375 C 443.48123 1.6271057 487.2535 7.754013 486.96735 39.375 C 514.41388 -1.06863403 549.4889 79.575165 525.96246 120.01879 C 554.19305 139.62691 525.60626 245.27281 502.4375 227.625 C 500.5833 257.03967 459.16455 267.33319 455.52917 227.625 C 432.07571 270.03143 383.17157 204.82918 416.53403 146.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="454.5" y="141.5" width="67" height="69" fill="url(#Obj_Gradient_8)"/><rect x="454.5" y="141.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 467.669 176 L 477.83426 158 L 498.16476 158 L 508.33002 176 L 498.16476 194 L 477.83426 194 Z" fill="url(#Obj_Gradient_9)"/><path d="M 467.669 176 L 477.83426 158 L 498.16476 158 L 508.33002 176 L 498.16476 194 L 477.83426 194 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 339.71 85 L 360.71 85 C 363.194 85 365.21 90.376 365.21 97 C 365.21 103.624 363.194 109 360.71 109 L 339.71 109 C 337.22598 109 335.21 103.624 335.21 97 C 335.21 90.376 337.22598 85 339.71 85" fill="url(#Obj_Gradient_10)"/><path d="M 339.71 85 L 360.71 85 C 363.194 85 365.21 90.376 365.21 97 C 365.21 103.624 363.194 109 360.71 109 L 339.71 109 C 337.22598 109 335.21 103.624 335.21 97 C 335.21 90.376 337.22598 85 339.71 85" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="437" y="55.5" width="67" height="69" fill="url(#Obj_Gradient_11)"/><rect x="437" y="55.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 450.169 91.5 L 460.33426 73.5 L 480.66476 73.5 L 490.83002 91.5 L 480.66476 109.5 L 460.33426 109.5 Z" fill="url(#Obj_Gradient_12)"/><path d="M 450.169 91.5 L 460.33426 73.5 L 480.66476 73.5 L 490.83002 91.5 L 480.66476 109.5 L 460.33426 109.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 461 162.96559 L 481.51996 177.86208 L 465.23532 196.6077 L 471.79984 203 L 489.58826 182.72214 L 508.52 196.48279 L 515 189.03462 L 494.4799 173.20695 L 511.7599 156.44833 L 502.0399 149 L 486.91986 167.62071 L 469.64001 152.72417 Z" fill="url(#Obj_Gradient_13)"/><path d="M 461 162.96559 L 481.51996 177.86208 L 465.23532 196.6077 L 471.79984 203 L 489.58826 182.72214 L 508.52 196.48279 L 515 189.03462 L 494.4799 173.20695 L 511.7599 156.44833 L 502.0399 149 L 486.91986 167.62071 L 469.64001 152.72417 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(5.8400302 4)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">1</tspan></text><rect x="281.29001" y="278.755" width="278.00003" height="273" fill="white"/><rect x="281.29001" y="278.755" width="278.00003" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 420.11401 428.7362 C 396.51749 415.255 405.92719 301.76535 443.5689 321.13 C 447.06122 283.38211 490.8335 289.50903 490.54733 321.13 C 517.9939 280.68637 553.0689 361.33017 529.54248 401.7738 C 557.773 421.38193 529.18622 527.02783 506.0175 509.38 C 504.1633 538.79468 462.74454 549.0882 459.10913 509.38 C 435.6557 551.78644 386.75156 486.58417 420.11401 428.7362 Z" fill="url(#Obj_Gradient_14)"/><path d="M 420.11401 428.7362 C 396.51749 415.255 405.92719 301.76535 443.5689 321.13 C 447.06122 283.38211 490.8335 289.50903 490.54733 321.13 C 517.9939 280.68637 553.0689 361.33017 529.54248 401.7738 C 557.773 421.38193 529.18622 527.02783 506.0175 509.38 C 504.1633 538.79468 462.74454 549.0882 459.10913 509.38 C 435.6557 551.78644 386.75156 486.58417 420.11401 428.7362 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="458.08" y="423.255" width="66.99997" height="69" fill="url(#Obj_Gradient_15)"/><rect x="458.08" y="423.255" width="66.99997" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 471.249 457.755 L 481.41425 439.755 L 501.74475 439.755 L 511.91 457.755 L 501.74475 475.755 L 481.41425 475.755 Z" fill="url(#Obj_Gradient_16)"/><path d="M 471.249 457.755 L 481.41425 439.755 L 501.74475 439.755 L 511.91 457.755 L 501.74475 475.755 L 481.41425 475.755 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 343.29 366.755 L 364.29 366.755 C 366.77402 366.755 368.79 372.13101 368.79 378.755 C 368.79 385.379 366.77402 390.755 364.29 390.755 L 343.29 390.755 C 340.806 390.755 338.79 385.379 338.79 378.755 C 338.79 372.13101 340.806 366.755 343.29 366.755" fill="url(#Obj_Gradient_17)"/><path d="M 343.29 366.755 L 364.29 366.755 C 366.77402 366.755 368.79 372.13101 368.79 378.755 C 368.79 385.379 366.77402 390.755 364.29 390.755 L 343.29 390.755 C 340.806 390.755 338.79 385.379 338.79 378.755 C 338.79 372.13101 340.806 366.755 343.29 366.755" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="440.57999" y="337.255" width="67" height="69" fill="url(#Obj_Gradient_18)"/><rect x="440.57999" y="337.255" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 453.749 373.255 L 463.91425 355.255 L 484.24475 355.255 L 494.41 373.255 L 484.24475 391.255 L 463.91425 391.255 Z" fill="url(#Obj_Gradient_19)"/><path d="M 453.749 373.255 L 463.91425 355.255 L 484.24475 355.255 L 494.41 373.255 L 484.24475 391.255 L 463.91425 391.255 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 365.46664 366.5985 C 373.74026 357.98486 375.04666 340.75385 390.29 340.755 C 402.3567 340.75592 423.16241 351.55505 442.3288 360.32996" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><rect x="0" y="558" width="278" height="273" fill="white"/><rect x="0" y="558" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 138.824036 709.9812 C 115.22751 696.5 124.63721 583.01038 162.27893 602.375 C 165.77126 564.62708 209.5435 570.75403 209.25735 602.375 C 236.70389 561.9314 271.77893 642.57513 248.25249 683.0188 C 276.48303 702.6269 247.89624 808.27283 224.72751 790.625 C 222.8733 820.03967 181.45457 830.3332 177.81917 790.625 C 154.36572 833.03143 105.46157 767.82916 138.824036 709.9812 Z" fill="url(#Obj_Gradient_20)"/><path d="M 138.824036 709.9812 C 115.22751 696.5 124.63721 583.01038 162.27893 602.375 C 165.77126 564.62708 209.5435 570.75403 209.25735 602.375 C 236.70389 561.9314 271.77893 642.57513 248.25249 683.0188 C 276.48303 702.6269 247.89624 808.27283 224.72751 790.625 C 222.8733 820.03967 181.45457 830.3332 177.81917 790.625 C 154.36572 833.03143 105.46157 767.82916 138.824036 709.9812 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="176.78999" y="704.5" width="67" height="69" fill="url(#Obj_Gradient_21)"/><rect x="176.78999" y="704.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 189.959 739 L 200.12425 721 L 220.45476 721 L 230.62001 739 L 220.45476 757 L 200.12425 757 Z" fill="url(#Obj_Gradient_22)"/><path d="M 189.959 739 L 200.12425 721 L 220.45476 721 L 230.62001 739 L 220.45476 757 L 200.12425 757 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 62 648 L 83 648 C 85.484 648 87.5 653.37598 87.5 660 C 87.5 666.62402 85.484 672 83 672 L 62 672 C 59.516 672 57.5 666.62402 57.5 660 C 57.5 653.37598 59.516 648 62 648" fill="url(#Obj_Gradient_23)"/><path d="M 62 648 L 83 648 C 85.484 648 87.5 653.37598 87.5 660 C 87.5 666.62402 85.484 672 83 672 L 62 672 C 59.516 672 57.5 666.62402 57.5 660 C 57.5 653.37598 59.516 648 62 648" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="159.28999" y="618.5" width="67" height="69" fill="url(#Obj_Gradient_24)"/><rect x="159.28999" y="618.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 172.459 654.5 L 182.62425 636.5 L 202.95476 636.5 L 213.12001 654.5 L 202.95476 672.5 L 182.62425 672.5 Z" fill="url(#Obj_Gradient_25)"/><path d="M 172.459 654.5 L 182.62425 636.5 L 202.95476 636.5 L 213.12001 654.5 L 202.95476 672.5 L 182.62425 672.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 84.176636 647.8435 C 92.450264 639.22986 93.75663 621.99884 109 622 C 121.06667 622.0009 141.87247 632.80005 161.03886 641.575" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 181.93205 672.16388 C 174.38545 684.44135 157.17926 699.40002 159.28999 709 C 160.93364 716.4756 174.29166 720.7052 185.68005 725.4799" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(286 8)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">2</tspan></text><text transform="translate(286 289.62299)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">4</tspan></text><text transform="translate(10.3773594 571.472)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">5</tspan></text><rect x="0" y="278.755" width="278" height="273" fill="white"/><rect x="0" y="278.755" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 112.48411 428.7362 C 88.88759 415.255 98.297287 301.76535 135.93901 321.13 C 139.431335 283.38211 183.20358 289.50903 182.91743 321.13 C 210.36397 280.68637 245.439 361.33017 221.91257 401.7738 C 250.14313 421.38193 221.55634 527.02783 198.38759 509.38 C 196.53339 538.79468 155.11465 549.0882 151.47925 509.38 C 128.02582 551.78644 79.12165 486.58417 112.48411 428.7362 Z" fill="url(#Obj_Gradient_26)"/><path d="M 112.48411 428.7362 C 88.88759 415.255 98.297287 301.76535 135.93901 321.13 C 139.431335 283.38211 183.20358 289.50903 182.91743 321.13 C 210.36397 280.68637 245.439 361.33017 221.91257 401.7738 C 250.14313 421.38193 221.55634 527.02783 198.38759 509.38 C 196.53339 538.79468 155.11465 549.0882 151.47925 509.38 C 128.02582 551.78644 79.12165 486.58417 112.48411 428.7362 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="150.45009" y="423.255" width="67" height="69" fill="url(#Obj_Gradient_27)"/><rect x="150.45009" y="423.255" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 163.61909 457.755 L 173.78435 439.755 L 194.11485 439.755 L 204.2801 457.755 L 194.11485 475.755 L 173.78435 475.755 Z" fill="url(#Obj_Gradient_28)"/><path d="M 163.61909 457.755 L 173.78435 439.755 L 194.11485 439.755 L 204.2801 457.755 L 194.11485 475.755 L 173.78435 475.755 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 62 372.755 L 83 372.755 C 85.484 372.755 87.5 378.13101 87.5 384.755 C 87.5 391.379 85.484 396.755 83 396.755 L 62 396.755 C 59.516 396.755 57.5 391.379 57.5 384.755 C 57.5 378.13101 59.516 372.755 62 372.755" fill="url(#Obj_Gradient_29)"/><path d="M 62 372.755 L 83 372.755 C 85.484 372.755 87.5 378.13101 87.5 384.755 C 87.5 391.379 85.484 396.755 83 396.755 L 62 396.755 C 59.516 396.755 57.5 391.379 57.5 384.755 C 57.5 378.13101 59.516 372.755 62 372.755" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="146.58009" y="343.255" width="67" height="69" fill="url(#Obj_Gradient_30)"/><rect x="146.58009" y="343.255" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 159.7491 379.255 L 169.91435 361.255 L 190.24486 361.255 L 200.41011 379.255 L 190.24486 397.255 L 169.91435 397.255 Z" fill="url(#Obj_Gradient_31)"/><path d="M 159.7491 379.255 L 169.91435 361.255 L 190.24486 361.255 L 200.41011 379.255 L 190.24486 397.255 L 169.91435 397.255 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 156.95009 444.72058 L 177.47003 459.6171 L 161.18541 478.3627 L 167.74992 484.755 L 185.53835 464.47714 L 204.47009 478.2378 L 210.95009 470.78964 L 190.42998 454.96198 L 207.70998 438.20334 L 197.98997 430.755 L 182.86996 449.3757 L 165.59009 434.47916 Z" fill="url(#Obj_Gradient_32)"/><path d="M 156.95009 444.72058 L 177.47003 459.6171 L 161.18541 478.3627 L 167.74992 484.755 L 185.53835 464.47714 L 204.47009 478.2378 L 210.95009 470.78964 L 190.42998 454.96198 L 207.70998 438.20334 L 197.98997 430.755 L 182.86996 449.3757 L 165.59009 434.47916 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(210.37738 346.23645)" fill="#262626"><tspan font-family="Arial Unicode MS" font-size="36" font-weight="500" fill="#262626" x="0" y="38" textLength="36">â™›</tspan></text><text transform="translate(5.8400302 287.736)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">3</tspan></text></g></g></svg>
diff --git a/doc/book/src/java-broker/images/HA-2N-NetworkPartition.svg b/doc/book/src/java-broker/images/HA-2N-NetworkPartition.svg
index 375d88a7db..392489c5c8 100644
--- a/doc/book/src/java-broker/images/HA-2N-NetworkPartition.svg
+++ b/doc/book/src/java-broker/images/HA-2N-NetworkPartition.svg
@@ -1,3 +1,23 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="-20 -12 600 596" width="50pc" height="596pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-05-31 06:19Z</dc:date><!-- Produced by OmniGraffle Professional 5.3.6 --></metadata><defs><radialGradient cx="0" cy="0" r="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#b5d0ea"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(474.08 425.5) scale(145.18695)"/><linearGradient x1="0" x2="1" id="Gradient_2" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#2824aa"/></linearGradient><linearGradient id="Obj_Gradient_2" xl:href="#Gradient_2" gradientTransform="translate(466.66 343.723) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_3" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa1f43"/></linearGradient><linearGradient id="Obj_Gradient_3" xl:href="#Gradient_3" gradientTransform="translate(466.65952 360.223) rotate(90) scale(36)"/><linearGradient x1="0" x2="1" id="Gradient_4" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6923aa"/></linearGradient><linearGradient id="Obj_Gradient_4" xl:href="#Gradient_4" gradientTransform="translate(353.79 377) rotate(90) scale(24.00003)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient_2" gradientTransform="translate(474.08 438) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#21aa1a"/></linearGradient><linearGradient id="Obj_Gradient_6" xl:href="#Gradient_5" gradientTransform="translate(474.0795 456) rotate(90) scale(36)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -3 6 6" markerWidth="6" markerHeight="6" color="black"><g><path d="M 3.7333333 0 L 0 -1.4 L 0 1.4 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="Arrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black"><g><path d="M 8 0 L 0 -3 L 0 3 Z" fill="none" stroke="currentColor" stroke-width="1"/></g></marker><radialGradient id="Obj_Gradient_7" xl:href="#Gradient" gradientTransform="translate(470.5 137.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_8" xl:href="#Gradient_2" gradientTransform="translate(488 145.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_6" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6ead6a"/></linearGradient><linearGradient id="Obj_Gradient_9" xl:href="#Gradient_6" gradientTransform="translate(487.9995 162) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_10" xl:href="#Gradient_4" gradientTransform="translate(350.21 89) rotate(90) scale(24)"/><radialGradient cx="0" cy="0" r="1" id="Gradient_7" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#ea061f"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient_11" xl:href="#Gradient_7" gradientTransform="translate(487.17532 136.54291) scale(20.071926)"/><linearGradient id="Obj_Gradient_12" xl:href="#Gradient_2" gradientTransform="translate(466.66 55.445) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#b6b4b5"/></linearGradient><linearGradient id="Obj_Gradient_13" xl:href="#Gradient_8" gradientTransform="translate(466.65952 71.945) rotate(90) scale(36)"/><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face><radialGradient id="Obj_Gradient_14" xl:href="#Gradient" gradientTransform="translate(200.35501 140.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_15" xl:href="#Gradient_2" gradientTransform="translate(212.855 150) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_9" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#0caa25"/></linearGradient><linearGradient id="Obj_Gradient_16" xl:href="#Gradient_9" gradientTransform="translate(212.85451 166.5) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_17" xl:href="#Gradient_4" gradientTransform="translate(80.355003 115) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_18" xl:href="#Gradient_2" gradientTransform="translate(195.355 63.999996) rotate(90) scale(69.000007)"/><linearGradient x1="0" x2="1" id="Gradient_10" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa172d"/></linearGradient><linearGradient id="Obj_Gradient_19" xl:href="#Gradient_10" gradientTransform="translate(195.35451 82) rotate(90) scale(36)"/><radialGradient id="Obj_Gradient_20" xl:href="#Gradient" gradientTransform="translate(180.29001 423.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_21" xl:href="#Gradient_2" gradientTransform="translate(172.37 346) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_11" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaa3a7"/></linearGradient><linearGradient id="Obj_Gradient_22" xl:href="#Gradient_11" gradientTransform="translate(172.36951 360.5) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_23" xl:href="#Gradient_4" gradientTransform="translate(72.5 379) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_24" xl:href="#Gradient_2" gradientTransform="translate(180.953 435.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_12" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#66ab61"/></linearGradient><linearGradient id="Obj_Gradient_25" xl:href="#Gradient_12" gradientTransform="translate(180.95251 452) rotate(90) scale(36)"/><linearGradient x1="0" x2="1" id="Gradient_13" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#b5011d"/></linearGradient><linearGradient id="Obj_Gradient_26" xl:href="#Gradient_13" gradientTransform="translate(169.38802 421.22614) rotate(45) scale(21.988586)"/></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 5</title><g><title>Layer 1</title><rect x="281.29001" y="287" width="278.00003" height="273" fill="white"/><rect x="281.29001" y="287" width="278.00003" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 420.11401 438.9812 C 396.51749 425.5 405.92719 312.01035 443.5689 331.375 C 447.06122 293.6271 490.8335 299.75403 490.54733 331.375 C 517.9939 290.93137 553.0689 371.57516 529.54248 412.0188 C 557.773 431.62692 529.18622 537.27283 506.0175 519.625 C 504.1633 549.03967 462.74454 559.3332 459.10913 519.625 C 435.6557 562.03143 386.75156 496.82916 420.11401 438.9812 Z" fill="url(#Obj_Gradient)"/><path d="M 420.11401 438.9812 C 396.51749 425.5 405.92719 312.01035 443.5689 331.375 C 447.06122 293.6271 490.8335 299.75403 490.54733 331.375 C 517.9939 290.93137 553.0689 371.57516 529.54248 412.0188 C 557.773 431.62692 529.18622 537.27283 506.0175 519.625 C 504.1633 549.03967 462.74454 559.3332 459.10913 519.625 C 435.6557 562.03143 386.75156 496.82916 420.11401 438.9812 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="433.16" y="343.723" width="67" height="69" fill="url(#Obj_Gradient_2)"/><rect x="433.16" y="343.723" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 446.329 378.223 L 456.49426 360.223 L 476.82477 360.223 L 486.99002 378.223 L 476.82477 396.223 L 456.49426 396.223 Z" fill="url(#Obj_Gradient_3)"/><path d="M 446.329 378.223 L 456.49426 360.223 L 476.82477 360.223 L 486.99002 378.223 L 476.82477 396.223 L 456.49426 396.223 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 343.29 377 L 364.29 377 C 366.77402 377 368.79 382.376 368.79 389 C 368.79 395.624 366.77402 401 364.29 401 L 343.29 401 C 340.806 401 338.79 395.624 338.79 389 C 338.79 382.376 340.806 377 343.29 377" fill="url(#Obj_Gradient_4)"/><path d="M 343.29 377 L 364.29 377 C 366.77402 377 368.79 382.376 368.79 389 C 368.79 395.624 366.77402 401 364.29 401 L 343.29 401 C 340.806 401 338.79 395.624 338.79 389 C 338.79 382.376 340.806 377 343.29 377" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="440.57999" y="438" width="67" height="69" fill="url(#Obj_Gradient_5)"/><rect x="440.57999" y="438" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 453.749 474 L 463.91425 456 L 484.24475 456 L 494.41 474 L 484.24475 492 L 463.91425 492 Z" fill="url(#Obj_Gradient_6)"/><path d="M 453.749 474 L 463.91425 456 L 484.24475 456 L 494.41 474 L 484.24475 492 L 463.91425 492 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 358.11069 401.47244 C 364.4065 419.64648 360.82266 444.49713 377 456 C 390.09668 465.31238 416.1513 465.88107 439.42624 468.3237" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 480.27563 455.52597 C 482.5702 448.68466 488.31772 444.80447 487.16 435 C 486.26978 427.46088 481.2962 416.41544 476.94943 405.90878" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="281.29001" y="4" width="278.00003" height="273" fill="white"/><rect x="281.29001" y="4" width="278.00003" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 416.53403 150.98122 C 392.9375 137.5 402.3472 24.010353 439.98892 43.375 C 443.48123 5.6271057 487.2535 11.754013 486.96735 43.375 C 514.41388 2.931366 549.4889 83.575165 525.96246 124.01879 C 554.19305 143.62691 525.60626 249.27281 502.4375 231.625 C 500.5833 261.03967 459.16455 271.33319 455.52917 231.625 C 432.07571 274.03143 383.17157 208.82918 416.53403 150.98122 Z" fill="url(#Obj_Gradient_7)"/><path d="M 416.53403 150.98122 C 392.9375 137.5 402.3472 24.010353 439.98892 43.375 C 443.48123 5.6271057 487.2535 11.754013 486.96735 43.375 C 514.41388 2.931366 549.4889 83.575165 525.96246 124.01879 C 554.19305 143.62691 525.60626 249.27281 502.4375 231.625 C 500.5833 261.03967 459.16455 271.33319 455.52917 231.625 C 432.07571 274.03143 383.17157 208.82918 416.53403 150.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="454.5" y="145.5" width="67" height="69" fill="url(#Obj_Gradient_8)"/><rect x="454.5" y="145.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 467.669 180 L 477.83426 162 L 498.16476 162 L 508.33002 180 L 498.16476 198 L 477.83426 198 Z" fill="url(#Obj_Gradient_9)"/><path d="M 467.669 180 L 477.83426 162 L 498.16476 162 L 508.33002 180 L 498.16476 198 L 477.83426 198 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 339.71 89 L 360.71 89 C 363.194 89 365.21 94.376 365.21 101 C 365.21 107.624 363.194 113 360.71 113 L 339.71 113 C 337.22598 113 335.21 107.624 335.21 101 C 335.21 94.376 337.22598 89 339.71 89" fill="url(#Obj_Gradient_10)"/><path d="M 339.71 89 L 360.71 89 C 363.194 89 365.21 94.376 365.21 101 C 365.21 107.624 363.194 113 360.71 113 L 339.71 113 C 337.22598 113 335.21 107.624 335.21 101 C 335.21 94.376 337.22598 89 339.71 89" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 474.53464 129.01602 L 484.14154 137.61832 L 476.51752 148.44287 L 479.59082 152.134415 L 487.91891 140.42473 L 496.7823 148.37096 L 499.816 144.06992 L 490.20901 134.93007 L 498.2991 125.25254 L 493.74844 120.95141 L 486.66962 131.70415 L 478.57965 123.101974 Z" fill="url(#Obj_Gradient_11)"/><path d="M 474.53464 129.01602 L 484.14154 137.61832 L 476.51752 148.44287 L 479.59082 152.134415 L 487.91891 140.42473 L 496.7823 148.37096 L 499.816 144.06992 L 490.20901 134.93007 L 498.2991 125.25254 L 493.74844 120.95141 L 486.66962 131.70415 L 478.57965 123.101974 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="433.16" y="55.445" width="67" height="69" fill="url(#Obj_Gradient_12)"/><rect x="433.16" y="55.445" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 446.329 89.945 L 456.49426 71.945 L 476.82477 71.945 L 486.99002 89.945 L 476.82477 107.945 L 456.49426 107.945 Z" fill="url(#Obj_Gradient_13)"/><path d="M 446.329 89.945 L 456.49426 71.945 L 476.82477 71.945 L 486.99002 89.945 L 476.82477 107.945 L 456.49426 107.945 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 487.69427 161.50006 C 487.55954 153.3342 489.4468 145.84863 487.29 137 C 485.7971 130.87509 482.3659 124.09454 479.00916 117.33957" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(5.8400302 4)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">1</tspan></text><text transform="translate(286 6)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">2</tspan></text><rect x="0" y="4" width="278" height="273" fill="white"/><rect x="0" y="4" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 146.38904 153.98122 C 122.79251 140.5 132.20221 27.010353 169.84393 46.375 C 173.33626 8.6271057 217.1085 14.754013 216.82236 46.375 C 244.26889 5.931366 279.34393 86.575165 255.81749 127.01879 C 284.04803 146.62691 255.46124 252.27281 232.29251 234.625 C 230.43831 264.03967 189.01958 274.33319 185.38417 234.625 C 161.930725 277.03143 113.02657 211.82918 146.38904 153.98122 Z" fill="url(#Obj_Gradient_14)"/><path d="M 146.38904 153.98122 C 122.79251 140.5 132.20221 27.010353 169.84393 46.375 C 173.33626 8.6271057 217.1085 14.754013 216.82236 46.375 C 244.26889 5.931366 279.34393 86.575165 255.81749 127.01879 C 284.04803 146.62691 255.46124 252.27281 232.29251 234.625 C 230.43831 264.03967 189.01958 274.33319 185.38417 234.625 C 161.930725 277.03143 113.02657 211.82918 146.38904 153.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="179.355" y="150" width="67" height="69" fill="url(#Obj_Gradient_15)"/><rect x="179.355" y="150" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 192.524 184.5 L 202.68925 166.5 L 223.01976 166.5 L 233.18501 184.5 L 223.01976 202.5 L 202.68925 202.5 Z" fill="url(#Obj_Gradient_16)"/><path d="M 192.524 184.5 L 202.68925 166.5 L 223.01976 166.5 L 233.18501 184.5 L 223.01976 202.5 L 202.68925 202.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 69.855003 115 L 90.855003 115 C 93.339005 115 95.355003 120.376 95.355003 127 C 95.355003 133.62399 93.339005 139 90.855003 139 L 69.855003 139 C 67.371002 139 65.355003 133.62399 65.355003 127 C 65.355003 120.376 67.371002 115 69.855003 115" fill="url(#Obj_Gradient_17)"/><path d="M 69.855003 115 L 90.855003 115 C 93.339005 115 95.355003 120.376 95.355003 127 C 95.355003 133.62399 93.339005 139 90.855003 139 L 69.855003 139 C 67.371002 139 65.355003 133.62399 65.355003 127 C 65.355003 120.376 67.371002 115 69.855003 115" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="161.855" y="64" width="67" height="69" fill="url(#Obj_Gradient_18)"/><rect x="161.855" y="64" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 175.024 100 L 185.18925 82 L 205.51976 82 L 215.68501 100 L 205.51976 118 L 185.18925 118 Z" fill="url(#Obj_Gradient_19)"/><path d="M 175.024 100 L 185.18925 82 L 205.51976 82 L 215.68501 100 L 205.51976 118 L 185.18925 118 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 88 139 C 101.11702 162.9976 109.51097 202.49907 127.355 211 C 141.45248 217.71606 161.45502 205.08597 180.36313 196.03654" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 222.38084 166.05576 C 227.03842 157.03807 238.59448 147.85422 236.355 139 C 234.66139 132.304 225.07715 125.79347 216.5538 119.25858" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(286 293)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">4</tspan></text><text transform="translate(5.8400302 6)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">1</tspan></text><text transform="translate(5.840027 287)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">3</tspan></text><rect x="0" y="287" width="278" height="273" fill="white"/><rect x="0" y="287" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 126.32403 436.9812 C 102.72751 423.5 112.13721 310.01035 149.77893 329.375 C 153.27126 291.6271 197.0435 297.75403 196.75735 329.375 C 224.20389 288.93137 259.27893 369.57516 235.75249 410.0188 C 263.98303 429.62692 235.39624 535.27283 212.22751 517.625 C 210.37331 547.03967 168.95457 557.3332 165.31917 517.625 C 141.86572 560.03143 92.96157 494.82916 126.32403 436.9812 Z" fill="url(#Obj_Gradient_20)"/><path d="M 126.32403 436.9812 C 102.72751 423.5 112.13721 310.01035 149.77893 329.375 C 153.27126 291.6271 197.0435 297.75403 196.75735 329.375 C 224.20389 288.93137 259.27893 369.57516 235.75249 410.0188 C 263.98303 429.62692 235.39624 535.27283 212.22751 517.625 C 210.37331 547.03967 168.95457 557.3332 165.31917 517.625 C 141.86572 560.03143 92.96157 494.82916 126.32403 436.9812 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="138.869995" y="346" width="67" height="69" fill="url(#Obj_Gradient_21)"/><rect x="138.869995" y="346" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 152.039 378.5 L 162.20425 360.5 L 182.53476 360.5 L 192.70001 378.5 L 182.53476 396.5 L 162.20425 396.5 Z" fill="url(#Obj_Gradient_22)"/><path d="M 152.039 378.5 L 162.20425 360.5 L 182.53476 360.5 L 192.70001 378.5 L 182.53476 396.5 L 162.20425 396.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 62 379 L 83 379 C 85.484 379 87.5 384.376 87.5 391 C 87.5 397.624 85.484 403 83 403 L 62 403 C 59.516 403 57.5 397.624 57.5 391 C 57.5 384.376 59.516 379 62 379" fill="url(#Obj_Gradient_23)"/><path d="M 62 379 L 83 379 C 85.484 379 87.5 384.376 87.5 391 C 87.5 397.624 85.484 403 83 403 L 62 403 C 59.516 403 57.5 397.624 57.5 391 C 57.5 384.376 59.516 379 62 379" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="147.453" y="435.5" width="67" height="69" fill="url(#Obj_Gradient_24)"/><rect x="147.453" y="435.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 160.62201 470 L 170.78726 452 L 191.11777 452 L 201.28302 470 L 191.11777 488 L 170.78726 488 Z" fill="url(#Obj_Gradient_25)"/><path d="M 160.62201 470 L 170.78726 452 L 191.11777 452 L 201.28302 470 L 191.11777 488 L 170.78726 488 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 181.17079 451.50006 C 181.27284 442.8504 182.34718 434.63248 181.47696 425.54852 C 180.89874 419.51263 179.46176 413.09204 178.022 406.67056" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 162.48625 439.34933 L 182.67911 418.90622 C 182.67911 418.90622 176.37192 410.54022 180.79669 410.70734 C 185.22139 410.87448 187.68919 413.07565 187.68919 413.07565 L 183.62592 416.69077 L 189.96997 423.03482 L 193.83488 419.61807 C 193.83488 419.61807 196.0623 421.44876 196.25372 421.64017 C 196.44499 421.83145 196.1347 425.18307 195.37999 426.3204 C 194.62503 427.45789 187.93712 423.79865 187.93724 423.79877 C 187.93724 423.79877 166.50412 443.3672 166.44502 443.4263 C 166.38591 443.4854 165.92685 444.32736 163.88141 442.16357 C 161.83583 439.99976 162.48625 439.34933 162.48625 439.34933 Z" fill="url(#Obj_Gradient_26)"/><path d="M 162.48625 439.34933 L 182.67911 418.90622 C 182.67911 418.90622 176.37192 410.54022 180.79669 410.70734 C 185.22139 410.87448 187.68919 413.07565 187.68919 413.07565 L 183.62592 416.69077 L 189.96997 423.03482 L 193.83488 419.61807 C 193.83488 419.61807 196.0623 421.44876 196.25372 421.64017 C 196.44499 421.83145 196.1347 425.18307 195.37999 426.3204 C 194.62503 427.45789 187.93712 423.79865 187.93724 423.79877 C 187.93724 423.79877 166.50412 443.3672 166.44502 443.4263 C 166.38591 443.4854 165.92685 444.32736 163.88141 442.16357 C 161.83583 439.99976 162.48625 439.34933 162.48625 439.34933 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 75.526443 403.48596 C 80.05397 422.16476 74.80702 448.81583 89.11038 459.52802 C 100.46647 468.0329 124.151474 466.49478 145.480865 466.87387" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><text transform="translate(10 297)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">3</tspan></text></g></g></svg>
diff --git a/doc/book/src/java-broker/images/HA-2N-Normal.svg b/doc/book/src/java-broker/images/HA-2N-Normal.svg
index c4fac9d37a..68ade6acd0 100644
--- a/doc/book/src/java-broker/images/HA-2N-Normal.svg
+++ b/doc/book/src/java-broker/images/HA-2N-Normal.svg
@@ -1,3 +1,23 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="-11 -10 318 313" width="318pt" height="313pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-05-31 06:19Z</dc:date><!-- Produced by OmniGraffle Professional 5.3.6 --></metadata><defs><radialGradient cx="0" cy="0" r="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#b5d0ea"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(209.35501 142.5) scale(145.18695)"/><linearGradient x1="0" x2="1" id="Gradient_2" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#2824aa"/></linearGradient><linearGradient id="Obj_Gradient_2" xl:href="#Gradient_2" gradientTransform="translate(221.85501 152) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_3" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#0caa25"/></linearGradient><linearGradient id="Obj_Gradient_3" xl:href="#Gradient_3" gradientTransform="translate(221.85452 168.5) rotate(90) scale(36)"/><linearGradient x1="0" x2="1" id="Gradient_4" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6923aa"/></linearGradient><linearGradient id="Obj_Gradient_4" xl:href="#Gradient_4" gradientTransform="translate(71.35501 115) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient_2" gradientTransform="translate(204.35501 66) rotate(90) scale(69.000007)"/><linearGradient x1="0" x2="1" id="Gradient_5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa172d"/></linearGradient><linearGradient id="Obj_Gradient_6" xl:href="#Gradient_5" gradientTransform="translate(204.35452 84) rotate(90) scale(36)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -3 6 6" markerWidth="6" markerHeight="6" color="black"><g><path d="M 3.7333333 0 L 0 -1.4 L 0 1.4 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="Arrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black"><g><path d="M 8 0 L 0 -3 L 0 3 Z" fill="none" stroke="currentColor" stroke-width="1"/></g></marker></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><g><title>Layer 1</title><rect x="9" y="6" width="278" height="273" fill="white"/><rect x="9" y="6" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 155.38904 155.98122 C 131.79251 142.5 141.20221 29.010353 178.84393 48.375 C 182.33626 10.627106 226.1085 16.754013 225.82236 48.375 C 253.26889 7.931366 288.34393 88.575165 264.8175 129.01878 C 293.04803 148.62691 264.46124 254.27281 241.29251 236.625 C 239.43831 266.03967 198.01958 276.33319 194.38417 236.625 C 170.93073 279.03143 122.02657 213.82918 155.38904 155.98122 Z" fill="url(#Obj_Gradient)"/><path d="M 155.38904 155.98122 C 131.79251 142.5 141.20221 29.010353 178.84393 48.375 C 182.33626 10.627106 226.1085 16.754013 225.82236 48.375 C 253.26889 7.931366 288.34393 88.575165 264.8175 129.01878 C 293.04803 148.62691 264.46124 254.27281 241.29251 236.625 C 239.43831 266.03967 198.01958 276.33319 194.38417 236.625 C 170.93073 279.03143 122.02657 213.82918 155.38904 155.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="188.35501" y="152" width="67" height="69" fill="url(#Obj_Gradient_2)"/><rect x="188.35501" y="152" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 201.52402 186.5 L 211.68927 168.5 L 232.01978 168.5 L 242.18503 186.5 L 232.01978 204.5 L 211.68927 204.5 Z" fill="url(#Obj_Gradient_3)"/><path d="M 201.52402 186.5 L 211.68927 168.5 L 232.01978 168.5 L 242.18503 186.5 L 232.01978 204.5 L 211.68927 204.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 60.85501 115 L 81.85501 115 C 84.33901 115 86.35501 120.376 86.35501 127 C 86.35501 133.62399 84.33901 139 81.85501 139 L 60.85501 139 C 58.37101 139 56.35501 133.62399 56.35501 127 C 56.35501 120.376 58.37101 115 60.85501 115" fill="url(#Obj_Gradient_4)"/><path d="M 60.85501 115 L 81.85501 115 C 84.33901 115 86.35501 120.376 86.35501 127 C 86.35501 133.62399 84.33901 139 81.85501 139 L 60.85501 139 C 58.37101 139 56.35501 133.62399 56.35501 127 C 56.35501 120.376 58.37101 115 60.85501 115" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="170.85501" y="66" width="67" height="69" fill="url(#Obj_Gradient_5)"/><rect x="170.85501" y="66" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 184.02402 102 L 194.18927 84 L 214.51978 84 L 224.68503 102 L 214.51978 120 L 194.18927 120 Z" fill="url(#Obj_Gradient_6)"/><path d="M 184.02402 102 L 194.18927 84 L 214.51978 84 L 224.68503 102 L 214.51978 120 L 194.18927 120 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 83.35501 143 C 101.01991 166.33099 116.23704 204.83237 136.35501 213 C 152.19005 219.42882 171.06885 207.06767 189.39609 198.1017" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 231.38086 168.05576 C 236.03844 159.03807 247.59447 149.85422 245.35498 141 C 243.66136 134.304 234.07715 127.79349 225.55383 121.2586" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/></g></g></svg>
diff --git a/doc/book/src/java-broker/images/HA-2N-ReplicaFail.svg b/doc/book/src/java-broker/images/HA-2N-ReplicaFail.svg
index aa872a30e3..8caf055b98 100644
--- a/doc/book/src/java-broker/images/HA-2N-ReplicaFail.svg
+++ b/doc/book/src/java-broker/images/HA-2N-ReplicaFail.svg
@@ -1,3 +1,23 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="-20 -16 600 590" width="50pc" height="590pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-05-31 06:19Z</dc:date><!-- Produced by OmniGraffle Professional 5.3.6 --></metadata><defs><radialGradient cx="0" cy="0" r="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#b5d0ea"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(470.5 133.5) scale(145.18695)"/><linearGradient x1="0" x2="1" id="Gradient_2" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#2824aa"/></linearGradient><linearGradient id="Obj_Gradient_2" xl:href="#Gradient_2" gradientTransform="translate(488 141.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_3" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6cad67"/></linearGradient><linearGradient id="Obj_Gradient_3" xl:href="#Gradient_3" gradientTransform="translate(487.9995 158) rotate(90) scale(36)"/><linearGradient x1="0" x2="1" id="Gradient_4" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6923aa"/></linearGradient><linearGradient id="Obj_Gradient_4" xl:href="#Gradient_4" gradientTransform="translate(350.21 85) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient_2" gradientTransform="translate(470.5 55.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaaaa3"/></linearGradient><linearGradient id="Obj_Gradient_6" xl:href="#Gradient_5" gradientTransform="translate(470.4995 73.5) rotate(90) scale(36)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -3 6 6" markerWidth="6" markerHeight="6" color="black"><g><path d="M 3.7333333 0 L 0 -1.4 L 0 1.4 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><radialGradient cx="0" cy="0" r="1" id="Gradient_6" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#ea061f"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient_7" xl:href="#Gradient_6" gradientTransform="translate(472.145 91.5) scale(38.183766)"/><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face><radialGradient id="Obj_Gradient_8" xl:href="#Gradient" gradientTransform="translate(474.08 415.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_9" xl:href="#Gradient_2" gradientTransform="translate(466.66 333.723) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_7" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa1f43"/></linearGradient><linearGradient id="Obj_Gradient_10" xl:href="#Gradient_7" gradientTransform="translate(466.65952 350.223) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_11" xl:href="#Gradient_4" gradientTransform="translate(353.79 367) rotate(90) scale(24.00003)"/><linearGradient id="Obj_Gradient_12" xl:href="#Gradient_2" gradientTransform="translate(474.08 428) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#21aa1a"/></linearGradient><linearGradient id="Obj_Gradient_13" xl:href="#Gradient_8" gradientTransform="translate(474.0795 446) rotate(90) scale(36)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="Arrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black"><g><path d="M 8 0 L 0 -3 L 0 3 Z" fill="none" stroke="currentColor" stroke-width="1"/></g></marker><radialGradient id="Obj_Gradient_14" xl:href="#Gradient" gradientTransform="translate(180.29001 409.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_15" xl:href="#Gradient_2" gradientTransform="translate(172.37 332) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_9" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaa3a7"/></linearGradient><linearGradient id="Obj_Gradient_16" xl:href="#Gradient_9" gradientTransform="translate(172.36951 346.5) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_17" xl:href="#Gradient_4" gradientTransform="translate(72.5 365) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_18" xl:href="#Gradient_2" gradientTransform="translate(180.953 421.5) rotate(90) scale(69)"/><linearGradient id="Obj_Gradient_19" xl:href="#Gradient_8" gradientTransform="translate(180.9525 438) rotate(90) scale(36)"/><linearGradient x1="0" x2="1" id="Gradient_10" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#b5011d"/></linearGradient><linearGradient id="Obj_Gradient_20" xl:href="#Gradient_10" gradientTransform="translate(134.69392 361.18848) rotate(45) scale(23.213103)"/><radialGradient id="Obj_Gradient_21" xl:href="#Gradient" gradientTransform="translate(200.35501 136.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_22" xl:href="#Gradient_2" gradientTransform="translate(212.855 146) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_11" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#0caa25"/></linearGradient><linearGradient id="Obj_Gradient_23" xl:href="#Gradient_11" gradientTransform="translate(212.85451 162.5) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_24" xl:href="#Gradient_4" gradientTransform="translate(80.355003 111) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_25" xl:href="#Gradient_2" gradientTransform="translate(195.355 59.999996) rotate(90) scale(69.000007)"/><linearGradient x1="0" x2="1" id="Gradient_12" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa172d"/></linearGradient><linearGradient id="Obj_Gradient_26" xl:href="#Gradient_12" gradientTransform="translate(195.35451 78) rotate(90) scale(36)"/></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 4</title><g><title>Layer 1</title><rect x="281.29001" y="0" width="278.00003" height="273" fill="white"/><rect x="281.29001" y="0" width="278.00003" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 416.53403 146.98122 C 392.9375 133.5 402.3472 20.010353 439.98892 39.375 C 443.48123 1.6271057 487.2535 7.754013 486.96735 39.375 C 514.41388 -1.06863403 549.4889 79.575165 525.96246 120.01879 C 554.19305 139.62691 525.60626 245.27281 502.4375 227.625 C 500.5833 257.03967 459.16455 267.33319 455.52917 227.625 C 432.07571 270.03143 383.17157 204.82918 416.53403 146.98122 Z" fill="url(#Obj_Gradient)"/><path d="M 416.53403 146.98122 C 392.9375 133.5 402.3472 20.010353 439.98892 39.375 C 443.48123 1.6271057 487.2535 7.754013 486.96735 39.375 C 514.41388 -1.06863403 549.4889 79.575165 525.96246 120.01879 C 554.19305 139.62691 525.60626 245.27281 502.4375 227.625 C 500.5833 257.03967 459.16455 267.33319 455.52917 227.625 C 432.07571 270.03143 383.17157 204.82918 416.53403 146.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="454.5" y="141.5" width="67" height="69" fill="url(#Obj_Gradient_2)"/><rect x="454.5" y="141.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 467.669 176 L 477.83426 158 L 498.16476 158 L 508.33002 176 L 498.16476 194 L 477.83426 194 Z" fill="url(#Obj_Gradient_3)"/><path d="M 467.669 176 L 477.83426 158 L 498.16476 158 L 508.33002 176 L 498.16476 194 L 477.83426 194 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 339.71 85 L 360.71 85 C 363.194 85 365.21 90.376 365.21 97 C 365.21 103.624 363.194 109 360.71 109 L 339.71 109 C 337.22598 109 335.21 103.624 335.21 97 C 335.21 90.376 337.22598 85 339.71 85" fill="url(#Obj_Gradient_4)"/><path d="M 339.71 85 L 360.71 85 C 363.194 85 365.21 90.376 365.21 97 C 365.21 103.624 363.194 109 360.71 109 L 339.71 109 C 337.22598 109 335.21 103.624 335.21 97 C 335.21 90.376 337.22598 85 339.71 85" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="437" y="55.5" width="67" height="69" fill="url(#Obj_Gradient_5)"/><rect x="437" y="55.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 450.169 91.5 L 460.33426 73.5 L 480.66476 73.5 L 490.83002 91.5 L 480.66476 109.5 L 460.33426 109.5 Z" fill="url(#Obj_Gradient_6)"/><path d="M 450.169 91.5 L 460.33426 73.5 L 480.66476 73.5 L 490.83002 91.5 L 480.66476 109.5 L 460.33426 109.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 355.0216 109.46646 C 360.75049 124.30949 353.19086 143.50909 372.21 154 C 388.3057 162.87834 423.4454 165.52399 453.4511 169.84836" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 445.145 78.46559 L 465.66495 93.362083 L 449.3803 112.107697 L 455.94482 118.5 L 473.73325 98.22214 L 492.66498 111.982796 L 499.145 104.53463 L 478.62488 88.706955 L 495.90488 71.948326 L 486.18488 64.5 L 471.06485 83.12071 L 453.78497 68.224167 Z" fill="url(#Obj_Gradient_7)"/><path d="M 445.145 78.46559 L 465.66495 93.362083 L 449.3803 112.107697 L 455.94482 118.5 L 473.73325 98.22214 L 492.66498 111.982796 L 499.145 104.53463 L 478.62488 88.706955 L 495.90488 71.948326 L 486.18488 64.5 L 471.06485 83.12071 L 453.78497 68.224167 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(286 6)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">2</tspan></text><rect x="281.29001" y="277" width="278.00003" height="273" fill="white"/><rect x="281.29001" y="277" width="278.00003" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 420.11401 428.9812 C 396.51749 415.5 405.92719 302.01035 443.5689 321.375 C 447.06122 283.6271 490.8335 289.75403 490.54733 321.375 C 517.9939 280.93137 553.0689 361.57516 529.54248 402.0188 C 557.773 421.62692 529.18622 527.27283 506.0175 509.625 C 504.1633 539.03967 462.74454 549.3332 459.10913 509.625 C 435.6557 552.03143 386.75156 486.82916 420.11401 428.9812 Z" fill="url(#Obj_Gradient_8)"/><path d="M 420.11401 428.9812 C 396.51749 415.5 405.92719 302.01035 443.5689 321.375 C 447.06122 283.6271 490.8335 289.75403 490.54733 321.375 C 517.9939 280.93137 553.0689 361.57516 529.54248 402.0188 C 557.773 421.62692 529.18622 527.27283 506.0175 509.625 C 504.1633 539.03967 462.74454 549.3332 459.10913 509.625 C 435.6557 552.03143 386.75156 486.82916 420.11401 428.9812 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="433.16" y="333.723" width="67" height="69" fill="url(#Obj_Gradient_9)"/><rect x="433.16" y="333.723" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 446.329 368.223 L 456.49426 350.223 L 476.82477 350.223 L 486.99002 368.223 L 476.82477 386.223 L 456.49426 386.223 Z" fill="url(#Obj_Gradient_10)"/><path d="M 446.329 368.223 L 456.49426 350.223 L 476.82477 350.223 L 486.99002 368.223 L 476.82477 386.223 L 456.49426 386.223 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 343.29 367 L 364.29 367 C 366.77402 367 368.79 372.376 368.79 379 C 368.79 385.624 366.77402 391 364.29 391 L 343.29 391 C 340.806 391 338.79 385.624 338.79 379 C 338.79 372.376 340.806 367 343.29 367" fill="url(#Obj_Gradient_11)"/><path d="M 343.29 367 L 364.29 367 C 366.77402 367 368.79 372.376 368.79 379 C 368.79 385.624 366.77402 391 364.29 391 L 343.29 391 C 340.806 391 338.79 385.624 338.79 379 C 338.79 372.376 340.806 367 343.29 367" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="440.57999" y="428" width="67" height="69" fill="url(#Obj_Gradient_12)"/><rect x="440.57999" y="428" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 453.749 464 L 463.91425 446 L 484.24475 446 L 494.41 464 L 484.24475 482 L 463.91425 482 Z" fill="url(#Obj_Gradient_13)"/><path d="M 453.749 464 L 463.91425 446 L 484.24475 446 L 494.41 464 L 484.24475 482 L 463.91425 482 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 358.11069 391.47244 C 364.4065 409.64648 360.82266 434.49713 377 446 C 390.09668 455.31238 416.1513 455.88107 439.42624 458.3237" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 480.27567 445.52594 C 482.57022 438.68463 488.31775 434.80447 487.16 425 C 486.26974 417.46088 481.2962 406.41544 476.94943 395.90878" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="0" y="277" width="278" height="273" fill="white"/><rect x="0" y="277" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 126.32403 422.9812 C 102.72751 409.5 112.13721 296.01035 149.77893 315.375 C 153.27126 277.6271 197.0435 283.75403 196.75735 315.375 C 224.20389 274.93137 259.27893 355.57516 235.75249 396.0188 C 263.98303 415.62692 235.39624 521.27283 212.22751 503.625 C 210.37331 533.03967 168.95457 543.3332 165.31917 503.625 C 141.86572 546.03143 92.96157 480.82916 126.32403 422.9812 Z" fill="url(#Obj_Gradient_14)"/><path d="M 126.32403 422.9812 C 102.72751 409.5 112.13721 296.01035 149.77893 315.375 C 153.27126 277.6271 197.0435 283.75403 196.75735 315.375 C 224.20389 274.93137 259.27893 355.57516 235.75249 396.0188 C 263.98303 415.62692 235.39624 521.27283 212.22751 503.625 C 210.37331 533.03967 168.95457 543.3332 165.31917 503.625 C 141.86572 546.03143 92.96157 480.82916 126.32403 422.9812 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="138.869995" y="332" width="67" height="69" fill="url(#Obj_Gradient_15)"/><rect x="138.869995" y="332" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 152.039 364.5 L 162.20425 346.5 L 182.53476 346.5 L 192.70001 364.5 L 182.53476 382.5 L 162.20425 382.5 Z" fill="url(#Obj_Gradient_16)"/><path d="M 152.039 364.5 L 162.20425 346.5 L 182.53476 346.5 L 192.70001 364.5 L 182.53476 382.5 L 162.20425 382.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 62 365 L 83 365 C 85.484 365 87.5 370.376 87.5 377 C 87.5 383.624 85.484 389 83 389 L 62 389 C 59.516 389 57.5 383.624 57.5 377 C 57.5 370.376 59.516 365 62 365" fill="url(#Obj_Gradient_17)"/><path d="M 62 365 L 83 365 C 85.484 365 87.5 370.376 87.5 377 C 87.5 383.624 85.484 389 83 389 L 62 389 C 59.516 389 57.5 383.624 57.5 377 C 57.5 370.376 59.516 365 62 365" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="147.453" y="421.5" width="67" height="69" fill="url(#Obj_Gradient_18)"/><rect x="147.453" y="421.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 160.62199 456 L 170.78725 438 L 191.11775 438 L 201.283 456 L 191.11775 474 L 170.78725 474 Z" fill="url(#Obj_Gradient_19)"/><path d="M 160.62199 456 L 170.78725 438 L 191.11775 438 L 201.283 456 L 191.11775 474 L 170.78725 474 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 75.38166 389.48718 C 79.4207 406.98972 73.112816 431.39597 87.5 442 C 99.01256 450.4853 123.781944 450.13696 145.894165 451.55768" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 118.20667 389.5221 L 154.46504 352.99951 C 154.46504 352.99951 148.56358 343.41068 154.80022 342.02164 C 161.03673 340.63266 163.73999 342.85837 163.73999 342.85837 L 156.62726 349.49799 L 163.3246 356.19534 L 170.08206 349.91098 C 170.08206 349.91098 172.57938 351.69775 172.78146 351.89984 C 172.98338 352.10178 171.3094 356.98645 169.817 358.88278 C 168.32417 360.77942 160.15027 358.03 160.15039 358.03012 C 160.15039 358.03012 122.44828 393.7637 122.342445 393.86954 C 122.23656 393.9754 121.27359 395.3426 119.157745 393.0148 C 117.04174 390.68701 118.20667 389.5221 118.20667 389.5221 Z" fill="url(#Obj_Gradient_20)"/><path d="M 118.20667 389.5221 L 154.46504 352.99951 C 154.46504 352.99951 148.56358 343.41068 154.80022 342.02164 C 161.03673 340.63266 163.73999 342.85837 163.73999 342.85837 L 156.62726 349.49799 L 163.3246 356.19534 L 170.08206 349.91098 C 170.08206 349.91098 172.57938 351.69775 172.78146 351.89984 C 172.98338 352.10178 171.3094 356.98645 169.817 358.88278 C 168.32417 360.77942 160.15027 358.03 160.15039 358.03012 C 160.15039 358.03012 122.44828 393.7637 122.342445 393.86954 C 122.23656 393.9754 121.27359 395.3426 119.157745 393.0148 C 117.04174 390.68701 118.20667 389.5221 118.20667 389.5221 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="0" y="0" width="278" height="273" fill="white"/><rect x="0" y="0" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 146.38904 149.98122 C 122.79251 136.5 132.20221 23.010353 169.84393 42.375 C 173.33626 4.6271057 217.1085 10.754013 216.82236 42.375 C 244.26889 1.931366 279.34393 82.575165 255.81749 123.01879 C 284.04803 142.62691 255.46124 248.27281 232.29251 230.625 C 230.43831 260.03967 189.01958 270.33319 185.38417 230.625 C 161.930725 273.03143 113.02657 207.82918 146.38904 149.98122 Z" fill="url(#Obj_Gradient_21)"/><path d="M 146.38904 149.98122 C 122.79251 136.5 132.20221 23.010353 169.84393 42.375 C 173.33626 4.6271057 217.1085 10.754013 216.82236 42.375 C 244.26889 1.931366 279.34393 82.575165 255.81749 123.01879 C 284.04803 142.62691 255.46124 248.27281 232.29251 230.625 C 230.43831 260.03967 189.01958 270.33319 185.38417 230.625 C 161.930725 273.03143 113.02657 207.82918 146.38904 149.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="179.355" y="146" width="67" height="69" fill="url(#Obj_Gradient_22)"/><rect x="179.355" y="146" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 192.524 180.5 L 202.68925 162.5 L 223.01976 162.5 L 233.18501 180.5 L 223.01976 198.5 L 202.68925 198.5 Z" fill="url(#Obj_Gradient_23)"/><path d="M 192.524 180.5 L 202.68925 162.5 L 223.01976 162.5 L 233.18501 180.5 L 223.01976 198.5 L 202.68925 198.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 69.855003 111 L 90.855003 111 C 93.339005 111 95.355003 116.376 95.355003 123 C 95.355003 129.62399 93.339005 135 90.855003 135 L 69.855003 135 C 67.371002 135 65.355003 129.62399 65.355003 123 C 65.355003 116.376 67.371002 111 69.855003 111" fill="url(#Obj_Gradient_24)"/><path d="M 69.855003 111 L 90.855003 111 C 93.339005 111 95.355003 116.376 95.355003 123 C 95.355003 129.62399 93.339005 135 90.855003 135 L 69.855003 135 C 67.371002 135 65.355003 129.62399 65.355003 123 C 65.355003 116.376 67.371002 111 69.855003 111" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="161.855" y="60" width="67" height="69" fill="url(#Obj_Gradient_25)"/><rect x="161.855" y="60" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 175.024 96 L 185.18925 78 L 205.51976 78 L 215.68501 96 L 205.51976 114 L 185.18925 114 Z" fill="url(#Obj_Gradient_26)"/><path d="M 175.024 96 L 185.18925 78 L 205.51976 78 L 215.68501 96 L 205.51976 114 L 185.18925 114 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 74.355003 137 C 92.019905 160.33099 107.23704 198.83237 127.355 207 C 143.19005 213.42882 162.06882 201.06767 180.39609 192.10172" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 222.38084 162.05576 C 227.03842 153.03807 238.59448 143.85422 236.355 135 C 234.66139 128.303986 225.07715 121.79347 216.5538 115.25858" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(5.8400302 4)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">1</tspan></text><text transform="translate(8 286)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">3</tspan></text><text transform="translate(286 286)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">4</tspan></text></g></g></svg>
diff --git a/doc/book/src/java-broker/images/HA-2N-SplitBrain.svg b/doc/book/src/java-broker/images/HA-2N-SplitBrain.svg
index c82cc5065a..7fed44ea36 100644
--- a/doc/book/src/java-broker/images/HA-2N-SplitBrain.svg
+++ b/doc/book/src/java-broker/images/HA-2N-SplitBrain.svg
@@ -1,3 +1,23 @@
<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="-20 -16 598 591" width="598pt" height="591pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-05-31 06:19Z</dc:date><!-- Produced by OmniGraffle Professional 5.3.6 --></metadata><defs><radialGradient cx="0" cy="0" r="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#b5d0ea"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(200.35501 136.5) scale(145.18695)"/><linearGradient x1="0" x2="1" id="Gradient_2" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#2824aa"/></linearGradient><linearGradient id="Obj_Gradient_2" xl:href="#Gradient_2" gradientTransform="translate(212.855 146) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_3" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#0caa25"/></linearGradient><linearGradient id="Obj_Gradient_3" xl:href="#Gradient_3" gradientTransform="translate(212.85451 162.5) rotate(90) scale(36)"/><linearGradient x1="0" x2="1" id="Gradient_4" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6923aa"/></linearGradient><linearGradient id="Obj_Gradient_4" xl:href="#Gradient_4" gradientTransform="translate(80.355003 111) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient_2" gradientTransform="translate(195.355 59.999996) rotate(90) scale(69.000007)"/><linearGradient x1="0" x2="1" id="Gradient_5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aa172d"/></linearGradient><linearGradient id="Obj_Gradient_6" xl:href="#Gradient_5" gradientTransform="translate(195.35451 78) rotate(90) scale(36)"/><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -3 6 6" markerWidth="6" markerHeight="6" color="black"><g><path d="M 3.7333333 0 L 0 -1.4 L 0 1.4 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="Arrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black"><g><path d="M 8 0 L 0 -3 L 0 3 Z" fill="none" stroke="currentColor" stroke-width="1"/></g></marker><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="532.22656" cap-height="719.72656" ascent="770.01953" descent="-229.98047" font-weight="bold"><font-face-src><font-face-name name="Helvetica-Bold"/></font-face-src></font-face><radialGradient id="Obj_Gradient_7" xl:href="#Gradient" gradientTransform="translate(468.855 133.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_8" xl:href="#Gradient_2" gradientTransform="translate(486.355 141.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_6" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#6ead6a"/></linearGradient><linearGradient id="Obj_Gradient_9" xl:href="#Gradient_6" gradientTransform="translate(486.3545 158) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_10" xl:href="#Gradient_4" gradientTransform="translate(348.565 85) rotate(90) scale(24)"/><radialGradient cx="0" cy="0" r="1" id="Gradient_7" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset=".5" stop-color="#ea061f"/><stop offset="1" stop-color="#aaa"/></radialGradient><radialGradient id="Obj_Gradient_11" xl:href="#Gradient_7" gradientTransform="translate(483.56808 132.68761) scale(20.071926)"/><linearGradient id="Obj_Gradient_12" xl:href="#Gradient_2" gradientTransform="translate(465.01501 51.445) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#b6b4b5"/></linearGradient><linearGradient id="Obj_Gradient_13" xl:href="#Gradient_8" gradientTransform="translate(465.0145 67.945) rotate(90) scale(36)"/><font-face font-family="Arial Unicode MS" font-size="36" panose-1="2 11 6 4 2 2 2 2 2 4" units-per-em="1000" underline-position="-100.097656" underline-thickness="49.804688" slope="0" x-height="529.78516" cap-height="728.02734" ascent="1068.84766" descent="-270.9961" font-weight="500"><font-face-src><font-face-name name="ArialUnicodeMS"/></font-face-src></font-face><radialGradient id="Obj_Gradient_14" xl:href="#Gradient" gradientTransform="translate(180.29001 414.5) scale(145.18695)"/><linearGradient id="Obj_Gradient_15" xl:href="#Gradient_2" gradientTransform="translate(172.37 337) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_9" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#66ab61"/></linearGradient><linearGradient id="Obj_Gradient_16" xl:href="#Gradient_9" gradientTransform="translate(172.36951 351.5) rotate(90) scale(36)"/><linearGradient id="Obj_Gradient_17" xl:href="#Gradient_4" gradientTransform="translate(53.18649 396) rotate(90) scale(24)"/><linearGradient id="Obj_Gradient_18" xl:href="#Gradient_2" gradientTransform="translate(180.953 426.5) rotate(90) scale(69)"/><linearGradient x1="0" x2="1" id="Gradient_10" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#21aa1a"/></linearGradient><linearGradient id="Obj_Gradient_19" xl:href="#Gradient_10" gradientTransform="translate(180.9525 443) rotate(90) scale(36)"/><radialGradient id="Obj_Gradient_20" xl:href="#Gradient_7" gradientTransform="translate(185.10121 416.23209) scale(20.071926)"/><font-face font-family="Arial Unicode MS" font-size="72" panose-1="2 11 6 4 2 2 2 2 2 4" units-per-em="1000" underline-position="-100.097656" underline-thickness="49.804688" slope="0" x-height="529.78516" cap-height="728.02734" ascent="1068.84766" descent="-270.9961" font-weight="500"><font-face-src><font-face-name name="ArialUnicodeMS"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 6</title><g><title>Layer 1</title><rect x="0" y="0" width="278" height="273" fill="white"/><rect x="0" y="0" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 146.38904 149.98122 C 122.79251 136.5 132.20221 23.010353 169.84393 42.375 C 173.33626 4.6271057 217.1085 10.754013 216.82236 42.375 C 244.26889 1.931366 279.34393 82.575165 255.81749 123.01879 C 284.04803 142.62691 255.46124 248.27281 232.29251 230.625 C 230.43831 260.03967 189.01958 270.33319 185.38417 230.625 C 161.930725 273.03143 113.02657 207.82918 146.38904 149.98122 Z" fill="url(#Obj_Gradient)"/><path d="M 146.38904 149.98122 C 122.79251 136.5 132.20221 23.010353 169.84393 42.375 C 173.33626 4.6271057 217.1085 10.754013 216.82236 42.375 C 244.26889 1.931366 279.34393 82.575165 255.81749 123.01879 C 284.04803 142.62691 255.46124 248.27281 232.29251 230.625 C 230.43831 260.03967 189.01958 270.33319 185.38417 230.625 C 161.930725 273.03143 113.02657 207.82918 146.38904 149.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="179.355" y="146" width="67" height="69" fill="url(#Obj_Gradient_2)"/><rect x="179.355" y="146" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 192.524 180.5 L 202.68925 162.5 L 223.01976 162.5 L 233.18501 180.5 L 223.01976 198.5 L 202.68925 198.5 Z" fill="url(#Obj_Gradient_3)"/><path d="M 192.524 180.5 L 202.68925 162.5 L 223.01976 162.5 L 233.18501 180.5 L 223.01976 198.5 L 202.68925 198.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 69.855003 111 L 90.855003 111 C 93.339005 111 95.355003 116.376 95.355003 123 C 95.355003 129.62399 93.339005 135 90.855003 135 L 69.855003 135 C 67.371002 135 65.355003 129.62399 65.355003 123 C 65.355003 116.376 67.371002 111 69.855003 111" fill="url(#Obj_Gradient_4)"/><path d="M 69.855003 111 L 90.855003 111 C 93.339005 111 95.355003 116.376 95.355003 123 C 95.355003 129.62399 93.339005 135 90.855003 135 L 69.855003 135 C 67.371002 135 65.355003 129.62399 65.355003 123 C 65.355003 116.376 67.371002 111 69.855003 111" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="161.855" y="60" width="67" height="69" fill="url(#Obj_Gradient_5)"/><rect x="161.855" y="60" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 175.024 96 L 185.18925 78 L 205.51976 78 L 215.68501 96 L 205.51976 114 L 185.18925 114 Z" fill="url(#Obj_Gradient_6)"/><path d="M 175.024 96 L 185.18925 78 L 205.51976 78 L 215.68501 96 L 205.51976 114 L 185.18925 114 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 83 135 C 87.728355 147.33211 78.882416 164.66258 97.186493 172 C 112.61268 178.18378 147.33044 177.27293 176.94928 178.23598" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 222.38084 162.05576 C 227.03842 153.03807 238.59448 143.85422 236.355 135 C 234.66139 128.303986 225.07715 121.79347 216.5538 115.25858" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(285 6)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">2</tspan></text><rect x="279.64499" y="0" width="278.00003" height="273" fill="white"/><rect x="279.64499" y="0" width="278.00003" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 414.88904 146.98122 C 391.2925 133.5 400.7022 20.010353 438.34393 39.375 C 441.83624 1.6271057 485.60852 7.754013 485.32236 39.375 C 512.76892 -1.06863403 547.84393 79.575165 524.3175 120.01879 C 552.54803 139.62691 523.96124 245.27281 500.7925 227.625 C 498.93832 257.03967 457.51956 267.33319 453.88416 227.625 C 430.43073 270.03143 381.52658 204.82918 414.88904 146.98122 Z" fill="url(#Obj_Gradient_7)"/><path d="M 414.88904 146.98122 C 391.2925 133.5 400.7022 20.010353 438.34393 39.375 C 441.83624 1.6271057 485.60852 7.754013 485.32236 39.375 C 512.76892 -1.06863403 547.84393 79.575165 524.3175 120.01879 C 552.54803 139.62691 523.96124 245.27281 500.7925 227.625 C 498.93832 257.03967 457.51956 267.33319 453.88416 227.625 C 430.43073 270.03143 381.52658 204.82918 414.88904 146.98122 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="452.855" y="141.5" width="66.99997" height="69" fill="url(#Obj_Gradient_8)"/><rect x="452.855" y="141.5" width="66.99997" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 466.024 176 L 476.18924 158 L 496.51974 158 L 506.685 176 L 496.51974 194 L 476.18924 194 Z" fill="url(#Obj_Gradient_9)"/><path d="M 466.024 176 L 476.18924 158 L 496.51974 158 L 506.685 176 L 496.51974 194 L 476.18924 194 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 338.065 85 L 359.065 85 C 361.54901 85 363.565 90.376 363.565 97 C 363.565 103.624 361.54901 109 359.065 109 L 338.065 109 C 335.581 109 333.565 103.624 333.565 97 C 333.565 90.376 335.581 85 338.065 85" fill="url(#Obj_Gradient_10)"/><path d="M 338.065 85 L 359.065 85 C 361.54901 85 363.565 90.376 363.565 97 C 363.565 103.624 361.54901 109 359.065 109 L 338.065 109 C 335.581 109 333.565 103.624 333.565 97 C 333.565 90.376 335.581 85 338.065 85" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 353.37662 109.46646 C 359.1055 124.30949 351.54587 143.50909 370.565 154 C 386.66068 162.87834 421.80042 165.52399 451.8061 169.84834" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 470.9274 125.16071 L 480.5343 133.763016 L 472.91028 144.58757 L 475.98358 148.27911 L 484.31168 136.56943 L 493.17505 144.515656 L 496.20877 140.214615 L 486.60178 131.07477 L 494.69186 121.39724 L 490.1412 117.09611 L 483.06238 127.84885 L 474.9724 119.246674 Z" fill="url(#Obj_Gradient_11)"/><path d="M 470.9274 125.16071 L 480.5343 133.763016 L 472.91028 144.58757 L 475.98358 148.27911 L 484.31168 136.56943 L 493.17505 144.515656 L 496.20877 140.214615 L 486.60178 131.07477 L 494.69186 121.39724 L 490.1412 117.09611 L 483.06238 127.84885 L 474.9724 119.246674 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="431.51501" y="51.445" width="67" height="69" fill="url(#Obj_Gradient_12)"/><rect x="431.51501" y="51.445" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 444.684 85.945 L 454.84924 67.945 L 475.17975 67.945 L 485.345 85.945 L 475.17975 103.945 L 454.84924 103.945 Z" fill="url(#Obj_Gradient_13)"/><path d="M 444.684 85.945 L 454.84924 67.945 L 475.17975 67.945 L 485.345 85.945 L 475.17975 103.945 L 454.84924 103.945 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 485.18884 157.50099 C 484.6743 149.33481 485.7887 141.847626 483.645 133 C 482.1737 126.92762 479.1671 120.211914 476.20593 113.515625" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(496 56.5)" fill="#262626"><tspan font-family="Arial Unicode MS" font-size="36" font-weight="500" fill="#262626" x="0" y="38" textLength="36">♛</tspan></text><text transform="translate(6 6)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">1</tspan></text><rect x="0" y="278" width="278" height="273" fill="white"/><rect x="0" y="278" width="278" height="273" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 126.32403 427.9812 C 102.72751 414.5 112.13721 301.01035 149.77893 320.375 C 153.27126 282.6271 197.0435 288.75403 196.75735 320.375 C 224.20389 279.93137 259.27893 360.57516 235.75249 401.0188 C 263.98303 420.62692 235.39624 526.27283 212.22751 508.625 C 210.37331 538.03967 168.95457 548.3332 165.31917 508.625 C 141.86572 551.03143 92.96157 485.82916 126.32403 427.9812 Z" fill="url(#Obj_Gradient_14)"/><path d="M 126.32403 427.9812 C 102.72751 414.5 112.13721 301.01035 149.77893 320.375 C 153.27126 282.6271 197.0435 288.75403 196.75735 320.375 C 224.20389 279.93137 259.27893 360.57516 235.75249 401.0188 C 263.98303 420.62692 235.39624 526.27283 212.22751 508.625 C 210.37331 538.03967 168.95457 548.3332 165.31917 508.625 C 141.86572 551.03143 92.96157 485.82916 126.32403 427.9812 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="138.869995" y="337" width="67" height="69" fill="url(#Obj_Gradient_15)"/><rect x="138.869995" y="337" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 152.039 369.5 L 162.20425 351.5 L 182.53476 351.5 L 192.70001 369.5 L 182.53476 387.5 L 162.20425 387.5 Z" fill="url(#Obj_Gradient_16)"/><path d="M 152.039 369.5 L 162.20425 351.5 L 182.53476 351.5 L 192.70001 369.5 L 182.53476 387.5 L 162.20425 387.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 42.68649 396 L 63.68649 396 C 66.170486 396 68.186493 401.376 68.186493 408 C 68.186493 414.624 66.170486 420 63.68649 420 L 42.68649 420 C 40.202488 420 38.18649 414.624 38.18649 408 C 38.18649 401.376 40.202488 396 42.68649 396" fill="url(#Obj_Gradient_17)"/><path d="M 42.68649 396 L 63.68649 396 C 66.170486 396 68.186493 401.376 68.186493 408 C 68.186493 414.624 66.170486 420 63.68649 420 L 42.68649 420 C 40.202488 420 38.18649 414.624 38.18649 408 C 38.18649 401.376 40.202488 396 42.68649 396" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><rect x="147.453" y="426.5" width="67" height="69" fill="url(#Obj_Gradient_18)"/><rect x="147.453" y="426.5" width="67" height="69" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 160.62199 461 L 170.78725 443 L 191.11775 443 L 201.283 461 L 191.11775 479 L 170.78725 479 Z" fill="url(#Obj_Gradient_19)"/><path d="M 160.62199 461 L 170.78725 443 L 191.11775 443 L 201.283 461 L 191.11775 479 L 170.78725 479 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 64.073936 420.37445 C 71.881844 429.24875 71.228394 440.71005 87.5 447 C 100.49186 452.02213 124.27972 453.7499 145.93179 456.12848" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><path d="M 61.40507 395.58307 C 67.269463 386.72293 63.968967 373.3653 79 369 C 90.933815 365.53418 114.428574 367.73508 135.71434 368.85406" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"/><text transform="translate(6 286)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="bold" x=".16308594" y="11" textLength="6.673828">3</tspan></text><path d="M 172.46051 408.7052 L 182.06741 417.3075 L 174.4434 428.13205 L 177.51671 431.82358 L 185.8448 420.1139 L 194.70818 428.06015 L 197.74191 423.7591 L 188.1349 414.61926 L 196.22501 404.9417 L 191.67433 400.6406 L 184.59552 411.39334 L 176.50554 402.79114 Z" fill="url(#Obj_Gradient_20)"/><path d="M 172.46051 408.7052 L 182.06741 417.3075 L 174.4434 428.13205 L 177.51671 431.82358 L 185.8448 420.1139 L 194.70818 428.06015 L 197.74191 423.7591 L 188.1349 414.61926 L 196.22501 404.9417 L 191.67433 400.6406 L 184.59552 411.39334 L 176.50554 402.79114 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><path d="M 186.722 441.046 C 186.20738 432.87949 187.32178 425.39178 185.17799 416.544 C 183.70665 410.47153 180.69995 403.75586 177.73871 397.05966" marker-end="url(#Arrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(19.372978 273)" fill="black"><tspan font-family="Arial Unicode MS" font-size="72" font-weight="500" x="0" y="77" textLength="54">☠</tspan></text></g></g></svg>
diff --git a/doc/book/src/programming/Programming-In-Apache-Qpid-Book.xml b/doc/book/src/programming/Programming-In-Apache-Qpid-Book.xml
index 1c6bfafc27..fd32f42f2e 100644
--- a/doc/book/src/programming/Programming-In-Apache-Qpid-Book.xml
+++ b/doc/book/src/programming/Programming-In-Apache-Qpid-Book.xml
@@ -3317,7 +3317,7 @@ spout - -content "$(cat rdu.xml | sed -e 's/70/45/')" xml/weather
integer
</entry>
<entry>
- Length of time to wait before attempting to reconnect (in milliseconds). Defaults to 0.
+ Length of time (in milliseconds) to wait before attempting to reconnect. Defaults to 0.
</entry>
</row>
<row>
@@ -3328,7 +3328,7 @@ spout - -content "$(cat rdu.xml | sed -e 's/70/45/')" xml/weather
integer
</entry>
<entry>
- Length of time to wait for the connection to succeed (in milliseconds). Defaults to 30000.
+ Length of time (in milliseconds) to wait for the socket connection to succeed. A value of 0 represents an infinite timeout, i.e. the connection attempt will block until established or an error occurs. Defaults to 30000.
</entry>
</row>
<row>
diff --git a/extras/qmf/src/py/qmf/console.py b/extras/qmf/src/py/qmf/console.py
index 90cc17d32b..af5d1da5ca 100644
--- a/extras/qmf/src/py/qmf/console.py
+++ b/extras/qmf/src/py/qmf/console.py
@@ -2443,6 +2443,8 @@ class Broker(Thread):
uid = self.conn.user_id
if uid.__class__ == tuple and len(uid) == 2:
self.saslUser = uid[1]
+ elif type(uid) is str:
+ self.saslUser = uid;
else:
self.saslUser = None
diff --git a/java/.gitignore b/java/.gitignore
index 36097e3820..417b51f12d 100644
--- a/java/.gitignore
+++ b/java/.gitignore
@@ -1,2 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
*.swp
eclipse-projects/*
diff --git a/java/amqp-1-0-client-jms/README.txt b/java/amqp-1-0-client-jms/README.txt
new file mode 100644
index 0000000000..eac8344aac
--- /dev/null
+++ b/java/amqp-1-0-client-jms/README.txt
@@ -0,0 +1,12 @@
+Documentation
+=============
+
+You can access documentation for the client via our website at:
+http://qpid.apache.org/documentation
+
+and via our wiki at:
+http://cwiki.apache.org/confluence/display/qpid/Qpid+Java+Documentation
+
+The client uses the Java Message Service (JMS) 1.1 API, information on which is
+widely available using your favoured search engine.
+
diff --git a/java/amqp-1-0-client-jms/build.xml b/java/amqp-1-0-client-jms/build.xml
index 82d5aa5c7a..cfc6e0babe 100644
--- a/java/amqp-1-0-client-jms/build.xml
+++ b/java/amqp-1-0-client-jms/build.xml
@@ -22,8 +22,19 @@
<property name="module.genpom" value="true"/>
<property name="module.depends" value="amqp-1-0-common amqp-1-0-client"/>
+ <property name="module.genpom.args" value="-Sgeronimo-jms_1.1_spec=provided"/>
+ <target name="release-bin-copy-readme">
+ <copy todir="${module.release}" overwrite="true" failonerror="true">
+ <fileset file="${basedir}/README.txt" />
+ </copy>
+ </target>
+
+ <target name="release-bin-other" depends="release-bin-copy-readme"/>
+
+ <target name="release-bin" depends="release-bin-tasks"/>
+
<import file="../module.xml"/>
</project>
diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverter.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverter.java
new file mode 100644
index 0000000000..03dd7c66a8
--- /dev/null
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverter.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.Statistics;
+
+public class ConfiguredObjectToMapConverter
+{
+ /** Name of the key used for the statistics map */
+ public static final String STATISTICS_MAP_KEY = "statistics";
+
+ private Model _model = Model.getInstance();
+
+ public Map<String, Object> convertObjectToMap(final ConfiguredObject confObject,
+ Class<? extends ConfiguredObject> clazz,
+ int depth)
+ {
+ Map<String, Object> object = new LinkedHashMap<String, Object>();
+
+ incorporateAttributesIntoMap(confObject, object);
+ incorporateStatisticsIntoMap(confObject, object);
+
+ if(depth > 0)
+ {
+ incorporateChildrenIntoMap(confObject, clazz, depth, object);
+ }
+ return object;
+ }
+
+ /**
+ * Used for unit test only.
+ */
+ void setModel(Model model)
+ {
+ _model = model;
+ }
+
+ private void incorporateAttributesIntoMap(
+ final ConfiguredObject confObject, Map<String, Object> object)
+ {
+ for(String name : confObject.getAttributeNames())
+ {
+ Object value = confObject.getAttribute(name);
+ if(value instanceof ConfiguredObject)
+ {
+ object.put(name, ((ConfiguredObject) value).getName());
+ }
+ else if(value != null)
+ {
+ object.put(name, value);
+ }
+ }
+ }
+
+ private void incorporateStatisticsIntoMap(
+ final ConfiguredObject confObject, Map<String, Object> object)
+ {
+ Statistics statistics = confObject.getStatistics();
+ Map<String, Object> statMap = new HashMap<String, Object>();
+
+ if (statistics != null)
+ {
+ for(String name : statistics.getStatisticNames())
+ {
+ Object value = statistics.getStatistic(name);
+ if(value != null)
+ {
+ statMap.put(name, value);
+ }
+ }
+
+ if(!statMap.isEmpty())
+ {
+ object.put(STATISTICS_MAP_KEY, statMap);
+ }
+ }
+ }
+
+ private void incorporateChildrenIntoMap(
+ final ConfiguredObject confObject,
+ Class<? extends ConfiguredObject> clazz, int depth,
+ Map<String, Object> object)
+ {
+ for(Class<? extends ConfiguredObject> childClass : _model.getChildTypes(clazz))
+ {
+ Collection<? extends ConfiguredObject> children = confObject.getChildren(childClass);
+ if(children != null)
+ {
+ List<Map<String, Object>> childObjects = new ArrayList<Map<String, Object>>();
+
+ for(ConfiguredObject child : children)
+ {
+ childObjects.add(convertObjectToMap(child, childClass, depth-1));
+ }
+
+ if(!childObjects.isEmpty())
+ {
+ object.put(childClass.getSimpleName().toLowerCase()+"s",childObjects);
+ }
+ }
+ }
+ }
+
+
+
+}
diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
index 593377beed..6a79916d07 100644
--- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
@@ -16,9 +16,9 @@
*/
package org.apache.qpid.server.management.plugin.servlet.rest;
+import java.io.BufferedWriter;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.SocketAddress;
+import java.io.Writer;
import java.util.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@@ -49,6 +49,8 @@ public class RestServlet extends AbstractServlet
private volatile boolean initializationRequired = false;
+ private final ConfiguredObjectToMapConverter _objectConverter = new ConfiguredObjectToMapConverter();
+
public RestServlet()
{
super();
@@ -133,7 +135,7 @@ public class RestServlet extends AbstractServlet
for(int i = 0; i < _hierarchy.length; i++)
{
- if(i == 0 || Model.getChildTypes(_hierarchy[i - 1]).contains(_hierarchy[i]))
+ if(i == 0 || Model.getInstance().getChildTypes(_hierarchy[i - 1]).contains(_hierarchy[i]))
{
for(ConfiguredObject parent : parents)
@@ -257,7 +259,7 @@ public class RestServlet extends AbstractServlet
ConfiguredObject child)
{
Collection<ConfiguredObject> ancestors = new HashSet<ConfiguredObject>();
- Collection<Class<? extends ConfiguredObject>> parentTypes = Model.getParentTypes(childType);
+ Collection<Class<? extends ConfiguredObject>> parentTypes = Model.getInstance().getParentTypes(childType);
for(Class<? extends ConfiguredObject> parentClazz : parentTypes)
{
@@ -282,119 +284,33 @@ public class RestServlet extends AbstractServlet
return ancestors;
}
-
- protected Map<String, Object> convertObjectToMap(final ConfiguredObject confObject,
- Class<? extends ConfiguredObject> clazz,
- int depth)
- {
- Map<String, Object> object = new LinkedHashMap<String, Object>();
-
- for(String name : confObject.getAttributeNames())
- {
- Object value = confObject.getAttribute(name);
- if(value instanceof ConfiguredObject)
- {
- object.put(name, ((ConfiguredObject) value).getName());
- }
- else if(value != null)
- {
- object.put(name, value);
- }
- }
-
- Statistics statistics = confObject.getStatistics();
- Map<String, Object> statMap = new HashMap<String, Object>();
- for(String name : statistics.getStatisticNames())
- {
- Object value = statistics.getStatistic(name);
- if(value != null)
- {
- statMap.put(name, value);
- }
- }
-
- if(!statMap.isEmpty())
- {
- object.put("statistics", statMap);
- }
-
- if(depth > 0)
- {
- for(Class<? extends ConfiguredObject> childClass : Model.getChildTypes(clazz))
- {
- Collection<? extends ConfiguredObject> children = confObject.getChildren(childClass);
- if(children != null)
- {
- List<Map<String, Object>> childObjects = new ArrayList<Map<String, Object>>();
-
- for(ConfiguredObject child : children)
- {
- childObjects.add(convertObjectToMap(child, childClass, depth-1));
- }
-
- if(!childObjects.isEmpty())
- {
- object.put(childClass.getSimpleName().toLowerCase()+"s",childObjects);
- }
- }
- }
- }
- return object;
- }
-
@Override
protected void onGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
- response.setHeader("Cache-Control","no-cache");
- response.setHeader("Pragma","no-cache");
- response.setDateHeader ("Expires", 0);
+ setCachingHeadersOnResponse(response);
Collection<ConfiguredObject> allObjects = getObjects(request);
- @SuppressWarnings("unchecked")
- Map params = new HashMap(request.getParameterMap());
-
- int depth = 1;
- try
- {
- depth = Integer.parseInt(String.valueOf(params.remove("depth")));
- }
- catch (NumberFormatException e)
- {
- // Ignore
- }
+ // TODO - sort special params, everything else should act as a filter
+ int depth = getDepthParameterFromRequest(request);
List<Map<String, Object>> output = new ArrayList<Map<String, Object>>();
-
- // TODO - depth and sort special params, everything else should act as a filter
- if(request.getParameter(DEPTH_PARAM)!=null)
- {
- try
- {
- depth = Integer.parseInt(request.getParameter(DEPTH_PARAM));
- }
- catch (NumberFormatException e)
- {
-
- }
- }
-
for(ConfiguredObject configuredObject : allObjects)
{
- output.add(convertObjectToMap(configuredObject, getConfiguredClass(),depth));
+ output.add(_objectConverter.convertObjectToMap(configuredObject, getConfiguredClass(),
+ depth));
}
- final PrintWriter writer = response.getWriter();
+ final Writer writer = new BufferedWriter(response.getWriter());
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
mapper.writeValue(writer, output);
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
-
}
private Class<? extends ConfiguredObject> getConfiguredClass()
@@ -462,7 +378,7 @@ public class RestServlet extends AbstractServlet
{
for(int j = i-1; j >=0; j--)
{
- if(Model.getChildTypes(_hierarchy[j]).contains(_hierarchy[i]))
+ if(Model.getInstance().getChildTypes(_hierarchy[j]).contains(_hierarchy[i]))
{
for(ConfiguredObject parent : objects[j])
{
@@ -482,7 +398,7 @@ public class RestServlet extends AbstractServlet
}
List<ConfiguredObject> parents = new ArrayList<ConfiguredObject>();
Class<? extends ConfiguredObject> objClass = getConfiguredClass();
- Collection<Class<? extends ConfiguredObject>> parentClasses = Model.getParentTypes(objClass);
+ Collection<Class<? extends ConfiguredObject>> parentClasses = Model.getInstance().getParentTypes(objClass);
for(int i = _hierarchy.length-2; i >=0 ; i--)
{
if(parentClasses.contains(_hierarchy[i]))
@@ -565,9 +481,7 @@ public class RestServlet extends AbstractServlet
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
- response.setHeader("Cache-Control","no-cache");
- response.setHeader("Pragma","no-cache");
- response.setDateHeader ("Expires", 0);
+ setCachingHeadersOnResponse(response);
try
{
Collection<ConfiguredObject> allObjects = getObjects(request);
@@ -583,4 +497,31 @@ public class RestServlet extends AbstractServlet
setResponseStatus(response, e);
}
}
+
+ private void setCachingHeadersOnResponse(HttpServletResponse response)
+ {
+ response.setHeader("Cache-Control","no-cache");
+ response.setHeader("Pragma","no-cache");
+ response.setDateHeader ("Expires", 0);
+ }
+
+ private int getDepthParameterFromRequest(HttpServletRequest request)
+ {
+ int depth = 1;
+ final String depthString = request.getParameter(DEPTH_PARAM);
+ if(depthString!=null)
+ {
+ try
+ {
+ depth = Integer.parseInt(depthString);
+ }
+ catch (NumberFormatException e)
+ {
+ LOGGER.warn("Could not parse " + depthString + " as integer");
+ }
+ }
+ return depth;
+ }
+
+
}
diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
index e4ba374f89..60f977ca66 100644
--- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
+++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
@@ -73,7 +73,7 @@ public class StructureServlet extends AbstractServlet
structure.put("id", object.getId());
structure.put("name", object.getName());
- for(Class<? extends ConfiguredObject> childClass : Model.getChildTypes(clazz))
+ for(Class<? extends ConfiguredObject> childClass : Model.getInstance().getChildTypes(clazz))
{
Collection<? extends ConfiguredObject> children = object.getChildren(childClass);
if(children != null)
diff --git a/java/broker-plugins/management-http/src/main/java/resources/showBroker.html b/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
index a39e334c40..f8d80faba8 100644
--- a/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
+++ b/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
@@ -1,3 +1,23 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License. You may obtain a copy of the License at
+ -
+ - http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied. See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -
+ -->
<div class="broker">
<span>Name:</span><span class="broker-name" style="position:absolute; left:6em"></span>
<br/>
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java
index 37bc2733b0..5e6d9a998a 100644
--- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.util.List;
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java
index 527eb16927..1ed0d97185 100644
--- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.net.HttpURLConnection;
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverterTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverterTest.java
new file mode 100644
index 0000000000..8e5c5e1c10
--- /dev/null
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverterTest.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.management.plugin.servlet.rest;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.apache.qpid.server.management.plugin.servlet.rest.ConfiguredObjectToMapConverter.STATISTICS_MAP_KEY;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.Statistics;
+
+public class ConfiguredObjectToMapConverterTest extends TestCase
+{
+ private ConfiguredObjectToMapConverter _converter = new ConfiguredObjectToMapConverter();
+ private ConfiguredObject _configuredObject = mock(ConfiguredObject.class);
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ }
+
+ public void testConfiguredObjectWithSingleStatistics() throws Exception
+ {
+ final String statisticName = "statisticName";
+ final int statisticValue = 10;
+
+ Statistics mockStatistics = createMockStatistics(statisticName, statisticValue);
+ when(_configuredObject.getStatistics()).thenReturn(mockStatistics);
+
+ Map<String, Object> resultMap = _converter.convertObjectToMap(_configuredObject, ConfiguredObject.class, 0);
+ Map<String, Object> statsAsMap = (Map<String, Object>) resultMap.get(STATISTICS_MAP_KEY);
+ assertNotNull("Statistics should be part of map", statsAsMap);
+ assertEquals("Unexpected number of statistics", 1, statsAsMap.size());
+ assertEquals("Unexpected statistic value", statisticValue, statsAsMap.get(statisticName));
+ }
+
+ public void testConfiguredObjectWithSingleNonConfiguredObjectAttribute() throws Exception
+ {
+ final String attributeName = "attribute";
+ final String attributeValue = "value";
+ configureMockToReturnOneAttribute(_configuredObject, attributeName, attributeValue);
+
+ Map<String, Object> resultMap = _converter.convertObjectToMap(_configuredObject, ConfiguredObject.class, 0);
+ assertEquals("Unexpected number of attributes", 1, resultMap.size());
+ assertEquals("Unexpected attribute value", attributeValue, resultMap.get(attributeName));
+ }
+
+ /*
+ * For now, it is the name of the configured object is returned as the attribute value, rather than the
+ * configured object itself
+ */
+ public void testConfiguredObjectWithSingleConfiguredObjectAttribute() throws Exception
+ {
+ final String attributeName = "attribute";
+ final ConfiguredObject attributeValue = mock(ConfiguredObject.class);
+ when(attributeValue.getName()).thenReturn("attributeConfiguredObjectName");
+
+ configureMockToReturnOneAttribute(_configuredObject, attributeName, attributeValue);
+
+ Map<String, Object> resultMap = _converter.convertObjectToMap(_configuredObject, ConfiguredObject.class, 0);
+ assertEquals("Unexpected number of attributes", 1, resultMap.size());
+ assertEquals("Unexpected attribute value", "attributeConfiguredObjectName", resultMap.get(attributeName));
+ }
+
+ public void testConfiguredObjectWithChildAndDepth1()
+ {
+ final String childAttributeName = "childattribute";
+ final String childAttributeValue = "childvalue";
+
+ Model model = createTestModel();
+ _converter.setModel(model);
+
+ TestChild mockChild = mock(TestChild.class);
+ configureMockToReturnOneAttribute(mockChild, childAttributeName, childAttributeValue);
+ when(_configuredObject.getChildren(TestChild.class)).thenReturn(Arrays.asList(mockChild));
+
+ Map<String, Object> resultMap = _converter.convertObjectToMap(_configuredObject, ConfiguredObject.class, 1);
+ assertEquals("Unexpected parent map size", 1, resultMap.size());
+
+ final List<Map<String, Object>> childList = (List<Map<String, Object>>) resultMap.get("testchilds");
+ assertEquals("Unexpected number of children", 1, childList.size());
+ final Map<String, Object> childMap = childList.get(0);
+ assertEquals("Unexpected child map size", 1, childMap.size());
+ assertNotNull(childMap);
+
+ assertEquals("Unexpected child attribute value", childAttributeValue, childMap.get(childAttributeName));
+ }
+
+ private Model createTestModel()
+ {
+ Model model = mock(Model.class);
+ final List<Class<? extends ConfiguredObject>> list = new ArrayList<Class<? extends ConfiguredObject>>();
+ list.add(TestChild.class);
+ when(model.getChildTypes(ConfiguredObject.class)).thenReturn(list);
+ return model;
+ }
+
+ private void configureMockToReturnOneAttribute(ConfiguredObject mockConfiguredObject, String attributeName, Object attributeValue)
+ {
+ when(mockConfiguredObject.getAttributeNames()).thenReturn(Arrays.asList(attributeName));
+ when(mockConfiguredObject.getAttribute(attributeName)).thenReturn(attributeValue);
+ }
+
+ private Statistics createMockStatistics(String statName, int statValue)
+ {
+ Statistics mockStatistics = mock(Statistics.class);
+ when(mockStatistics.getStatisticNames()).thenReturn(Arrays.asList(statName));
+ when(mockStatistics.getStatistic(statName)).thenReturn(statValue);
+ return mockStatistics;
+ }
+
+ private static interface TestChild extends ConfiguredObject
+ {
+ }
+}
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java
index 59936427f9..4904d2adf3 100644
--- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.net.URLDecoder;
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java
index 49f163baae..739ef5c737 100644
--- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.net.URLDecoder;
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java
index 943466eda7..b504c9fa60 100644
--- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.util.List;
diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java
index 378b349a99..e56fa27e21 100644
--- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java
+++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.net.HttpURLConnection;
diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java
index 49f06d5121..a2a0d2d093 100644
--- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java
+++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.jmx;
import org.apache.log4j.Logger;
+import org.apache.qpid.server.logging.LogActor;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.ManagementActor;
import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
@@ -38,6 +39,7 @@ import javax.management.MBeanServer;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
+import javax.management.RuntimeErrorException;
import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXPrincipal;
import javax.management.remote.MBeanServerForwarder;
@@ -48,6 +50,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.AccessControlContext;
import java.security.AccessController;
+import java.util.Arrays;
import java.util.Map;
import java.util.Set;
@@ -157,77 +160,98 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
// Save the subject
SecurityManager.setThreadSubject(subject);
-
- // Get the component, type and impact, which may be null
- String type = getType(method, args);
- String vhost = getVirtualHost(method, args);
- int impact = getImpact(method, args);
-
- // Get the security manager for the virtual host (if set)
- SecurityManager security;
- if (vhost == null)
+ CurrentActor.set(_logActor);
+ try
{
- security = _appRegistry.getSecurityManager();
+ return authoriseAndInvoke(method, args);
}
- else
+ finally
{
- security = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager();
+ CurrentActor.remove();
}
+ }
+ catch (InvocationTargetException e)
+ {
+ Throwable targetException = e.getCause();
+ logTargetException(method, args, targetException);
+ throw targetException;
+ }
+ }
- methodName = getMethodName(method, args);
- if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO)
- {
- // Check for read-only method invocation permission
- if (!security.authoriseMethod(Operation.ACCESS, type, methodName))
- {
- throw new SecurityException("Permission denied: Access " + methodName);
- }
- }
- else
- {
- // Check for setting properties permission
- if (!security.authoriseMethod(Operation.UPDATE, type, methodName))
- {
- throw new SecurityException("Permission denied: Update " + methodName);
- }
- }
+ private void logTargetException(Method method, Object[] args, Throwable targetException)
+ {
+ Throwable error = null;
+ if (targetException instanceof RuntimeErrorException)
+ {
+ error = ((RuntimeErrorException)targetException).getCause();
+ }
+ else if (targetException instanceof Error)
+ {
+ error = targetException;
+ }
+ if (error == null)
+ {
+ _logger.debug("Exception was thrown on invoking of " + method + " with arguments " + Arrays.toString(args), targetException);
+ }
+ else
+ {
+ _logger.error("Unexpected error occured on invoking of " + method + " with arguments " + Arrays.toString(args), targetException);
+ }
+ }
- boolean oldAccessChecksDisabled = false;
- if(_managementRightsInferAllAccess)
- {
- oldAccessChecksDisabled = SecurityManager.setAccessChecksDisabled(true);
- }
+ private Object authoriseAndInvoke(Method method, Object[] args) throws IllegalAccessException, InvocationTargetException
+ {
+ String methodName;
+ // Get the component, type and impact, which may be null
+ String type = getType(method, args);
+ String vhost = getVirtualHost(method, args);
+ int impact = getImpact(method, args);
+
+ // Get the security manager for the virtual host (if set)
+ SecurityManager security;
+ if (vhost == null)
+ {
+ security = _appRegistry.getSecurityManager();
+ }
+ else
+ {
+ security = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager();
+ }
- try
+ methodName = getMethodName(method, args);
+ if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO)
+ {
+ // Check for read-only method invocation permission
+ if (!security.authoriseMethod(Operation.ACCESS, type, methodName))
{
- return doInvokeWrappingWithManagementActor(method, args);
+ throw new SecurityException("Permission denied: Access " + methodName);
}
- finally
+ }
+ else
+ {
+ // Check for setting properties permission
+ if (!security.authoriseMethod(Operation.UPDATE, type, methodName))
{
- if(_managementRightsInferAllAccess)
- {
- SecurityManager.setAccessChecksDisabled(oldAccessChecksDisabled);
- }
+ throw new SecurityException("Permission denied: Update " + methodName);
}
}
- catch (InvocationTargetException e)
+
+ boolean oldAccessChecksDisabled = false;
+ if(_managementRightsInferAllAccess)
{
- throw e.getTargetException();
+ oldAccessChecksDisabled = SecurityManager.setAccessChecksDisabled(true);
}
- }
- private Object doInvokeWrappingWithManagementActor(Method method,
- Object[] args) throws IllegalAccessException,
- InvocationTargetException
- {
try
{
- CurrentActor.set(_logActor);
return method.invoke(_mbs, args);
}
finally
{
- CurrentActor.remove();
+ if(_managementRightsInferAllAccess)
+ {
+ SecurityManager.setAccessChecksDisabled(oldAccessChecksDisabled);
+ }
}
}
@@ -368,14 +392,17 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
user = splitConnectionId[1];
}
+ // use a separate instance of actor as subject is not set on connect/disconnect
+ // we need to pass principal name explicitly into log actor
+ LogActor logActor = new ManagementActor(_appRegistry.getRootMessageLogger(), user);
if (JMXConnectionNotification.OPENED.equals(type))
{
- _logActor.message(ManagementConsoleMessages.OPEN(user));
+ logActor.message(ManagementConsoleMessages.OPEN(user));
}
else if (JMXConnectionNotification.CLOSED.equals(type) ||
JMXConnectionNotification.FAILED.equals(type))
{
- _logActor.message(ManagementConsoleMessages.CLOSE(user));
+ logActor.message(ManagementConsoleMessages.CLOSE(user));
}
}
}
diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogActorTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogActorTest.java
new file mode 100644
index 0000000000..c1df9afc5d
--- /dev/null
+++ b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogActorTest.java
@@ -0,0 +1,170 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.jmx;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.JMException;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.Result;
+import org.apache.qpid.server.security.SecurityPlugin;
+import org.apache.qpid.server.security.access.ObjectProperties;
+import org.apache.qpid.server.security.access.ObjectType;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.util.TestApplicationRegistry;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class ManagementLogActorTest extends QpidTestCase
+{
+ private ApplicationRegistry _registry;
+ private JMXManagedObjectRegistry _objectRegistry;
+ private int _registryPort;
+ private int _connectorPort;
+ private TestPlugin _plugin;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _registryPort = findFreePort();
+ _connectorPort = getNextAvailable(_registryPort + 1);
+ XMLConfiguration config = new XMLConfiguration();
+ config.addProperty(ServerConfiguration.MGMT_JMXPORT_REGISTRYSERVER, _registryPort + "");
+ config.addProperty(ServerConfiguration.MGMT_JMXPORT_CONNECTORSERVER, _connectorPort + "");
+ _registry = new TestApplicationRegistry(new ServerConfiguration(config));
+ ApplicationRegistry.initialise(_registry);
+
+ _plugin = new TestPlugin();
+ _registry.getSecurityManager().addHostPlugin(_plugin);
+
+ _objectRegistry = new JMXManagedObjectRegistry();
+ new TestMBean(_objectRegistry);
+ _objectRegistry.start();
+ }
+
+ public void tearDown() throws Exception
+ {
+ _objectRegistry.close();
+ ApplicationRegistry.remove();
+ super.tearDown();
+ }
+
+ public void testPrincipalInLogMessage() throws Throwable
+ {
+ Map<String, Object> environment = new HashMap<String, Object>();
+ environment.put(JMXConnector.CREDENTIALS, new String[] { "admin", "admin" });
+ String urlString = "service:jmx:rmi:///jndi/rmi://localhost:" + _registryPort + "/jmxrmi";
+ JMXServiceURL url = new JMXServiceURL(urlString);
+ JMXConnector jmxConnector = JMXConnectorFactory.connect(url, environment);
+ MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection();
+ ObjectName mbeanObject = new ObjectName("org.apache.qpid:type=TestMBean,name=test");
+
+ String actorLogMessage = (String) mbsc.getAttribute(mbeanObject, "ActorLogMessage");
+
+ assertTrue("Unexpected log principal in security plugin", _plugin.getLogMessage().startsWith("[mng:admin"));
+ assertTrue("Unexpected log principal in MBean", actorLogMessage.startsWith("[mng:admin"));
+ }
+
+ public static class TestMBean extends DefaultManagedObject implements CurrentActorRetriever
+ {
+
+ public TestMBean(ManagedObjectRegistry registry) throws JMException
+ {
+ super(CurrentActorRetriever.class, "TestMBean", registry);
+ register();
+ }
+
+ @Override
+ public String getObjectInstanceName()
+ {
+ return "test";
+ }
+
+ @Override
+ public ManagedObject getParentObject()
+ {
+ return null;
+ }
+
+ @Override
+ public String getActorLogMessage()
+ {
+ return CurrentActor.get().getLogMessage();
+ }
+
+ }
+
+ public static interface CurrentActorRetriever
+ {
+ String getActorLogMessage();
+ }
+
+ public static class TestPlugin implements SecurityPlugin
+ {
+ private String _logMessage;
+
+ @Override
+ public void configure(ConfigurationPlugin config) throws ConfigurationException
+ {
+ }
+
+ @Override
+ public Result getDefault()
+ {
+ return Result.ALLOWED;
+ }
+
+ @Override
+ public Result access(ObjectType objectType, Object instance)
+ {
+ return Result.ALLOWED;
+ }
+
+ @Override
+ public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties)
+ {
+ // set thread name to work around logic in MangementActor
+ Thread.currentThread().setName("RMI TCP Connection(1)-" + System.currentTimeMillis());
+ _logMessage = CurrentActor.get().getLogMessage();
+ return Result.ALLOWED;
+ }
+
+ public String getLogMessage()
+ {
+ return _logMessage;
+ }
+
+ }
+
+}
diff --git a/java/broker/etc/broker_example.acl b/java/broker/etc/broker_example.acl
index 1f32f8463e..45a48bda09 100644
--- a/java/broker/etc/broker_example.acl
+++ b/java/broker/etc/broker_example.acl
@@ -18,6 +18,7 @@
#
### EXAMPLE ACL V2 FILE
+### NOTE: Rules are considered from top to bottom, and the first matching rule governs the decision.
### DEFINE GROUPS ###
@@ -27,30 +28,30 @@ GROUP messaging-users client server
#Define a group for management web console users
GROUP webadmins webadmin
-### MANAGEMENT ####
+### JMX MANAGEMENT ####
# Allow everyone to perform read operations on the ServerInformation mbean
# This is used for items such as querying the management API and broker release versions.
-ACL ALLOW-LOG ALL ACCESS METHOD component="ServerInformation"
+ACL ALLOW ALL ACCESS METHOD component="ServerInformation"
-# Allow 'admin' all management operations
+# Allow 'admin' all management operations. To reduce log file noise, only non-read-only operations are logged.
+ACL ALLOW admin ACCESS METHOD
ACL ALLOW-LOG admin ALL METHOD
+# Allow 'guest' to view logger levels, and use getter methods on LoggingManagement
+ACL ALLOW guest ACCESS METHOD component="LoggingManagement" name="viewEffectiveRuntimeLoggerLevels"
+ACL ALLOW guest ACCESS METHOD component="LoggingManagement" name="get*"
+
# Deny access to Shutdown, UserManagement, ConfigurationManagement and LoggingManagement for all other users
-# You could grant specific users access to these beans by adding ALLOW-LOG rules above for them
+# You could grant specific users access to these beans by adding rules above to allow them
ACL DENY-LOG ALL ACCESS METHOD component="Shutdown"
ACL DENY-LOG ALL ACCESS METHOD component="UserManagement"
ACL DENY-LOG ALL ACCESS METHOD component="ConfigurationManagement"
ACL DENY-LOG ALL ACCESS METHOD component="LoggingManagement"
-# Allow 'guest' to view logger levels, and use getter methods on LoggingManagement
-# These are examples of redundant rules! The DENY-LOG rule above will be invoked
-# first and will deny the access to all methods of LoggingManagement for guest
-ACL ALLOW-LOG guest ACCESS METHOD component="LoggingManagement" name="viewEffectiveRuntimeLoggerLevels"
-ACL ALLOW-LOG guest ACCESS METHOD component="LoggingManagement" name="get*"
-
-# Allow everyone to perform all read operations on the mbeans not listened in the DENY-LOG rules above
-ACL ALLOW-LOG ALL ACCESS METHOD
+# Allow everyone to perform all read operations (using ALLOW rather than ALLOW-LOG to reduce log file noise)
+# on the mbeans not listed in the DENY rules above
+ACL ALLOW ALL ACCESS METHOD
### MESSAGING ###
diff --git a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java
index 9cd3c66629..a2f3506502 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java
@@ -30,16 +30,7 @@ import java.text.MessageFormat;
import java.util.Set;
/**
- * NOTE: This actor is not thread safe.
- *
- * Sharing of a ManagementActor instance between threads may result in an
- * incorrect actor value being logged.
- *
- * This is due to the fact that calls to message will dynamically query the
- * thread name and use that to set the log format during each message() call.
- *
- * This is currently not an issue as each MBean operation creates a new Actor
- * that is unique for each operation.
+ * Management actor to use in {@link MBeanInvocationHandlerImpl} to log all management operational logging.
*/
public class ManagementActor extends AbstractActor
{
@@ -66,38 +57,45 @@ public class ManagementActor extends AbstractActor
/**
* The logString to be used for logging
*/
- private String _logString;
+ private String _logStringContainingPrincipal;
+
+ /** used when the principal name cannot be discovered from the Subject */
+ private final String _fallbackPrincipalName;
/** @param rootLogger The RootLogger to use for this Actor */
public ManagementActor(RootMessageLogger rootLogger)
{
super(rootLogger);
+ _fallbackPrincipalName = UNKNOWN_PRINCIPAL;
+ }
+
+ public ManagementActor(RootMessageLogger rootLogger, String principalName)
+ {
+ super(rootLogger);
+ _fallbackPrincipalName = principalName;
}
- private void updateLogString()
+ private synchronized String getAndCacheLogString()
{
String currentName = Thread.currentThread().getName();
String actor;
+ String logString = _logStringContainingPrincipal;
+
// Record the last thread name so we don't have to recreate the log string
- if (!currentName.equals(_lastThreadName))
+ if (_logStringContainingPrincipal == null || !currentName.equals(_lastThreadName))
{
_lastThreadName = currentName;
+ String principalName = getPrincipalName();
// Management Thread names have this format.
// RMI TCP Connection(2)-169.24.29.116
// This is true for both LocalAPI and JMX Connections
// However to be defensive lets test.
-
String[] split = currentName.split("\\(");
if (split.length == 2)
{
String ip = currentName.split("-")[1];
- String principalName = getPrincipalName();
- if (principalName == null)
- {
- principalName = UNKNOWN_PRINCIPAL;
- }
actor = MessageFormat.format(MANAGEMENT_FORMAT, principalName, ip);
}
else
@@ -111,9 +109,14 @@ public class ManagementActor extends AbstractActor
actor = currentName;
}
- _logString = "[" + actor + "] ";
+ logString = "[" + actor + "] ";
+ if(principalName != UNKNOWN_PRINCIPAL )
+ {
+ _logStringContainingPrincipal = logString;
+ }
}
+ return logString;
}
/**
@@ -121,9 +124,9 @@ public class ManagementActor extends AbstractActor
*
* @return principal name or null if principal can not be found
*/
- protected String getPrincipalName()
+ private String getPrincipalName()
{
- String identity = null;
+ String identity = _fallbackPrincipalName;
// retrieve Subject from current AccessControlContext
final Subject subject = Subject.getSubject(AccessController.getContext());
@@ -142,8 +145,7 @@ public class ManagementActor extends AbstractActor
public String getLogMessage()
{
- updateLogString();
- return _logString;
+ return getAndCacheLogString();
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/model/Model.java b/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
index fd429321c8..36179fc105 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
@@ -29,33 +29,20 @@ import java.util.Map;
public class Model
{
- private static final Map<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>
- PARENTS = new HashMap<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>();
+ private static final Model MODEL_INSTANCE = new Model();
+ private final Map<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>
+ _parents = new HashMap<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>();
- private static final Map<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>
- CHILDREN = new HashMap<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>();
+ private final Map<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>
+ _children = new HashMap<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>();
- static void addRelationship(Class<? extends ConfiguredObject> parent, Class<? extends ConfiguredObject> child)
+ public static Model getInstance()
{
- Collection<Class<? extends ConfiguredObject>> parents = PARENTS.get(child);
- if(parents == null)
- {
- parents = new ArrayList<Class<? extends ConfiguredObject>>();
- PARENTS.put(child, parents);
- }
- parents.add(parent);
-
- Collection<Class<? extends ConfiguredObject>> children = CHILDREN.get(parent);
- if(children == null)
- {
- children = new ArrayList<Class<? extends ConfiguredObject>>();
- CHILDREN.put(parent, children);
- }
- children.add(child);
+ return MODEL_INSTANCE;
}
- static
+ private Model()
{
addRelationship(Broker.class, VirtualHost.class);
addRelationship(Broker.class, Port.class);
@@ -78,20 +65,39 @@ public class Model
addRelationship(Session.class, Consumer.class);
addRelationship(Session.class, Publisher.class);
-
}
- public static Collection<Class<? extends ConfiguredObject>> getParentTypes(Class<? extends ConfiguredObject> child)
+ public Collection<Class<? extends ConfiguredObject>> getParentTypes(Class<? extends ConfiguredObject> child)
{
- Collection<Class<? extends ConfiguredObject>> parentTypes = PARENTS.get(child);
- return parentTypes == null ? Collections.EMPTY_LIST
+ Collection<Class<? extends ConfiguredObject>> parentTypes = _parents.get(child);
+ return parentTypes == null ? Collections.<Class<? extends ConfiguredObject>>emptyList()
: Collections.unmodifiableCollection(parentTypes);
}
- public static Collection<Class<? extends ConfiguredObject>> getChildTypes(Class<? extends ConfiguredObject> parent)
+ public Collection<Class<? extends ConfiguredObject>> getChildTypes(Class<? extends ConfiguredObject> parent)
{
- Collection<Class<? extends ConfiguredObject>> childTypes = CHILDREN.get(parent);
- return childTypes == null ? Collections.EMPTY_LIST
+ Collection<Class<? extends ConfiguredObject>> childTypes = _children.get(parent);
+ return childTypes == null ? Collections.<Class<? extends ConfiguredObject>>emptyList()
: Collections.unmodifiableCollection(childTypes);
}
+
+ private void addRelationship(Class<? extends ConfiguredObject> parent, Class<? extends ConfiguredObject> child)
+ {
+ Collection<Class<? extends ConfiguredObject>> parents = _parents.get(child);
+ if(parents == null)
+ {
+ parents = new ArrayList<Class<? extends ConfiguredObject>>();
+ _parents.put(child, parents);
+ }
+ parents.add(parent);
+
+ Collection<Class<? extends ConfiguredObject>> children = _children.get(parent);
+ if(children == null)
+ {
+ children = new ArrayList<Class<? extends ConfiguredObject>>();
+ _children.put(parent, children);
+ }
+ children.add(child);
+ }
+
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java
index b431047d66..cb866245f0 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java
@@ -26,15 +26,6 @@ import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.List;
-/**
- * Test : AMQPManagementActorTest
- * Validate the AMQPManagementActor class.
- *
- * The test creates a new AMQPActor and then logs a message using it.
- *
- * The test then verifies that the logged message was the only one created and
- * that the message contains the required message.
- */
public class ManagementActorTest extends BaseActorTestCase
{
@@ -131,4 +122,67 @@ public class ManagementActorTest extends BaseActorTestCase
assertTrue("Message contains the [mng: prefix", logMessage.contains("[mng:guest(" + IP + ")"));
}
+ public void testGetLogMessageWithSubject()
+ {
+ assertLogMessageInRMIThreadWithPrincipal("RMI TCP Connection(" + CONNECTION_ID + ")-" + IP, "my_principal");
+ }
+
+ public void testGetLogMessageWithoutSubjectButWithActorPrincipal()
+ {
+ String principalName = "my_principal";
+ _amqpActor = new ManagementActor(_rootLogger, principalName);
+ String message = _amqpActor.getLogMessage();
+ assertEquals("Unexpected log message", "[mng:" + principalName + "(" + IP + ")] ", message);
+ }
+
+ /** It's necessary to test successive calls because ManagementActor caches its log message based on thread and principal name */
+ public void testGetLogMessageCaching()
+ {
+ String originalThreadName = "RMI TCP Connection(1)-" + IP;
+ assertLogMessageInRMIThreadWithoutPrincipal(originalThreadName);
+ assertLogMessageInRMIThreadWithPrincipal(originalThreadName, "my_principal");
+ assertLogMessageInRMIThreadWithPrincipal("RMI TCP Connection(2)-" + IP, "my_principal");
+ }
+
+ public void testGetLogMessageAfterRemovingSubject()
+ {
+ assertLogMessageInRMIThreadWithPrincipal("RMI TCP Connection(1)-" + IP, "my_principal");
+
+ Thread.currentThread().setName("RMI TCP Connection(2)-" + IP );
+ String message = _amqpActor.getLogMessage();
+ assertEquals("Unexpected log message", "[mng:N/A(" + IP + ")] ", message);
+
+ assertLogMessageWithoutPrincipal("TEST");
+ }
+
+ private void assertLogMessageInRMIThreadWithoutPrincipal(String threadName)
+ {
+ Thread.currentThread().setName(threadName );
+ String message = _amqpActor.getLogMessage();
+ assertEquals("Unexpected log message", "[mng:N/A(" + IP + ")] ", message);
+ }
+
+ private void assertLogMessageWithoutPrincipal(String threadName)
+ {
+ Thread.currentThread().setName(threadName );
+ String message = _amqpActor.getLogMessage();
+ assertEquals("Unexpected log message", "[" + threadName +"] ", message);
+ }
+
+ private void assertLogMessageInRMIThreadWithPrincipal(String threadName, String principalName)
+ {
+ Thread.currentThread().setName(threadName);
+ Subject subject = new Subject(true, Collections.singleton(new JMXPrincipal(principalName)), Collections.EMPTY_SET,
+ Collections.EMPTY_SET);
+
+ final String message = Subject.doAs(subject, new PrivilegedAction<String>()
+ {
+ public String run()
+ {
+ return _amqpActor.getLogMessage();
+ }
+ });
+
+ assertEquals("Unexpected log message", "[mng:" + principalName + "(" + IP + ")] ", message);
+ }
}
diff --git a/java/build.deps b/java/build.deps
index 52ae277ce4..4742ec1a8c 100644
--- a/java/build.deps
+++ b/java/build.deps
@@ -106,7 +106,7 @@ jca.libs=${geronimo-j2ee} ${geronimo-jta} ${geronimo-jms} ${test.libs} ${geronim
jca.test.libs=${test.libs}
# optional bdbstore module deps
-bdb-je=lib/bdbstore/je-5.0.55.jar
+bdb-je=lib/bdbstore/je-5.0.58.jar
bdbstore.libs=${bdb-je}
bdbstore.test.libs=${test.libs}
diff --git a/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java b/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
index 987404cb80..89273599b9 100644
--- a/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
+++ b/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java
@@ -245,13 +245,13 @@ public class AMQBrokerDetails implements BrokerDetails
_options.put(key, value);
}
- public long getTimeout()
+ private int lookupConnectTimeout()
{
if (_options.containsKey(OPTIONS_CONNECT_TIMEOUT))
{
try
{
- return Long.parseLong(_options.get(OPTIONS_CONNECT_TIMEOUT));
+ return Integer.parseInt(_options.get(OPTIONS_CONNECT_TIMEOUT));
}
catch (NumberFormatException nfe)
{
@@ -290,11 +290,6 @@ public class AMQBrokerDetails implements BrokerDetails
}
}
- public void setTimeout(long timeout)
- {
- setProperty(OPTIONS_CONNECT_TIMEOUT, Long.toString(timeout));
- }
-
public String toString()
{
StringBuffer sb = new StringBuffer();
@@ -460,6 +455,8 @@ public class AMQBrokerDetails implements BrokerDetails
getBooleanProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY,true));
}
+ conSettings.setConnectTimeout(lookupConnectTimeout());
+
return conSettings;
}
}
diff --git a/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java b/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
index 71d7ffd2a3..4a7fca1efa 100644
--- a/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
+++ b/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java
@@ -59,7 +59,7 @@ public interface BrokerDetails
public static final String URL_FORMAT_EXAMPLE =
"<transport>://<hostname>[:<port Default=\"" + DEFAULT_PORT + "\">][?<option>='<value>'[,<option>='<value>']]";
- public static final long DEFAULT_CONNECT_TIMEOUT = 30000L;
+ public static final int DEFAULT_CONNECT_TIMEOUT = 30000;
public static final boolean USE_SSL_DEFAULT = false;
// pulled these properties from the new BrokerDetails class in the qpid package
@@ -101,10 +101,6 @@ public interface BrokerDetails
*/
public void setProperties(Map<String,String> props);
- long getTimeout();
-
- void setTimeout(long timeout);
-
boolean getBooleanProperty(String propName);
String toString();
diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
index 506185cbaf..412c458247 100644
--- a/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
+++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/BrokerDetails/BrokerDetailsTest.java
@@ -24,6 +24,7 @@ import junit.framework.TestCase;
import org.apache.qpid.client.AMQBrokerDetails;
import org.apache.qpid.jms.BrokerDetails;
+import org.apache.qpid.transport.ConnectionSettings;
import org.apache.qpid.url.URLSyntaxException;
public class BrokerDetailsTest extends TestCase
@@ -49,6 +50,29 @@ public class BrokerDetailsTest extends TestCase
assertFalse("value should be false", Boolean.valueOf(broker.getProperty(BrokerDetails.OPTIONS_TCP_NO_DELAY)));
}
+ public void testDefaultConnectTimeout() throws URLSyntaxException
+ {
+ String brokerURL = "tcp://localhost:5672";
+ AMQBrokerDetails broker = new AMQBrokerDetails(brokerURL);
+
+ ConnectionSettings settings = broker.buildConnectionSettings();
+
+ assertEquals("unexpected default connect timeout value", BrokerDetails.DEFAULT_CONNECT_TIMEOUT, settings.getConnectTimeout());
+ }
+
+ public void testOverridingConnectTimeout() throws URLSyntaxException
+ {
+ int timeout = 2 * BrokerDetails.DEFAULT_CONNECT_TIMEOUT;
+ assertTrue(timeout != BrokerDetails.DEFAULT_CONNECT_TIMEOUT);
+
+ String brokerURL = "tcp://localhost:5672?" + BrokerDetails.OPTIONS_CONNECT_TIMEOUT + "='" + timeout + "'";
+ AMQBrokerDetails broker = new AMQBrokerDetails(brokerURL);
+
+ ConnectionSettings settings = broker.buildConnectionSettings();
+
+ assertEquals("unexpected connect timeout value", timeout, settings.getConnectTimeout());
+ }
+
public void testMultiParameters() throws URLSyntaxException
{
String url = "tcp://localhost:5672?timeout='200',immediatedelivery='true'";
diff --git a/java/client/test/bin/IBM-JNDI-Setup.bat b/java/client/test/bin/IBM-JNDI-Setup.bat
deleted file mode 100644
index eb6a87fa9e..0000000000
--- a/java/client/test/bin/IBM-JNDI-Setup.bat
+++ /dev/null
@@ -1,69 +0,0 @@
-@REM
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM
-
-@echo off
-REM Script to run the Qpid Java Broker
-
-set CMD="IBM-JNDI-Setup.bat"
-set JAVACLASS=
-
-rem Guess QPID_HOME if not defined
-set CURRENT_DIR=%cd%
-if not "%QPID_HOME%" == "" goto gotHome
-set QPID_HOME=%CURRENT_DIR%
-echo %QPID_HOME%
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-cd ..
-set QPID_HOME=%cd%
-cd %CURRENT_DIR%
-:gotHome
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-echo The QPID_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program
-goto end
-:okHome
-
-if not "%JAVA_HOME%" == "" goto gotJavaHome
-echo The JAVA_HOME environment variable is not defined
-echo This environment variable is needed to run this program
-goto exit
-:gotJavaHome
-if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
-goto okJavaHome
-:noJavaHome
-echo The JAVA_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program.
-goto exit
-:okJavaHome
-
-set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
-
-echo on
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindConnectionFactory amqp://guest:guest@clientid/testpath?brokerlist='localhost' amq.ConnectionFactory
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindConnectionFactory amqp://guest:guest@clientid/testpath?brokerlist='vm://:1' amq.VMConnectionFactory
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindQueue amq.Queue direct://amq.direct//IBMPerfQueue1
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic1 topic://amq.topic/IBMPerfTopic1/
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic2 topic://amq.topic/IBMPerfTopic2/
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic3 topic://amq.topic/IBMPerfTopic3/
-
-
-
-:end
-
-pause \ No newline at end of file
diff --git a/java/client/test/bin/IBM-JNDI-Setup.sh b/java/client/test/bin/IBM-JNDI-Setup.sh
deleted file mode 100755
index e3112f812d..0000000000
--- a/java/client/test/bin/IBM-JNDI-Setup.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-qpid-run org.apache.qpid.IBMPerfTest.JNDIBindConnectionFactory amqp://guest:guest@clientid/testpath?brokerlist=\'tcp://localhost\' amq.ConnectionFactory
-qpid-run org.apache.qpid.IBMPerfTest.JNDIBindConnectionFactory amqp://guest:guest@clientid/testpath?brokerlist=\'vm://:1\' amq.VMConnectionFactory
-qpid-run org.apache.qpid.IBMPerfTest.JNDIBindQueue amq.Queue direct://amq.direct//IBMPerfQueue1
-qpid-run org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic1 topic://amq.topic/IBMPerfTopic1/
-qpid-run org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic2 topic://amq.topic/IBMPerfTopic2/
-qpid-run org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic3 topic://amq.topic/IBMPerfTopic3/
-qpid-run org.apache.qpid.IBMPerfTest.JNDIBindTopic amq.Topic4 topic://amq.topic/IBMPerfTopic4/ \ No newline at end of file
diff --git a/java/client/test/bin/IBM-Publisher.bat b/java/client/test/bin/IBM-Publisher.bat
deleted file mode 100644
index 5bb4343c4c..0000000000
--- a/java/client/test/bin/IBM-Publisher.bat
+++ /dev/null
@@ -1,62 +0,0 @@
-@REM
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM
-
-@echo off
-REM Script to run the Qpid Java Broker
-
-set CMD="IBM-Publisher.bat"
-set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Topic -db 1 -dx 4 -tc jms.r11.Publisher -nt 4 %*
-
-rem Guess QPID_HOME if not defined
-set CURRENT_DIR=%cd%
-if not "%QPID_HOME%" == "" goto gotHome
-set QPID_HOME=%CURRENT_DIR%
-echo %QPID_HOME%
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-cd ..
-set QPID_HOME=%cd%
-cd %CURRENT_DIR%
-:gotHome
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-echo The QPID_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program
-goto end
-:okHome
-
-if not "%JAVA_HOME%" == "" goto gotJavaHome
-echo The JAVA_HOME environment variable is not defined
-echo This environment variable is needed to run this program
-goto exit
-:gotJavaHome
-if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
-goto okJavaHome
-:noJavaHome
-echo The JAVA_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program.
-goto exit
-:okJavaHome
-
-set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
-
-echo on
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
-
-:end
-
-pause \ No newline at end of file
diff --git a/java/client/test/bin/IBM-Publisher.sh b/java/client/test/bin/IBM-Publisher.sh
deleted file mode 100755
index adecf040bc..0000000000
--- a/java/client/test/bin/IBM-Publisher.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-export MSGSIZE=100
-qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Topic -db 1 -dx 4 -tc jms.r11.Publisher -nt 4 $* \ No newline at end of file
diff --git a/java/client/test/bin/IBM-PutGet.bat b/java/client/test/bin/IBM-PutGet.bat
deleted file mode 100644
index c4316f1256..0000000000
--- a/java/client/test/bin/IBM-PutGet.bat
+++ /dev/null
@@ -1,62 +0,0 @@
-@REM
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM
-
-@echo off
-REM Script to run the Qpid Java Broker
-
-set CMD="IBM-PutGet.bat"
-set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.PutGet -nt 6 %*
-
-rem Guess QPID_HOME if not defined
-set CURRENT_DIR=%cd%
-if not "%QPID_HOME%" == "" goto gotHome
-set QPID_HOME=%CURRENT_DIR%
-echo %QPID_HOME%
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-cd ..
-set QPID_HOME=%cd%
-cd %CURRENT_DIR%
-:gotHome
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-echo The QPID_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program
-goto end
-:okHome
-
-if not "%JAVA_HOME%" == "" goto gotJavaHome
-echo The JAVA_HOME environment variable is not defined
-echo This environment variable is needed to run this program
-goto exit
-:gotJavaHome
-if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
-goto okJavaHome
-:noJavaHome
-echo The JAVA_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program.
-goto exit
-:okJavaHome
-
-set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
-
-echo on
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
-
-:end
-
-pause \ No newline at end of file
diff --git a/java/client/test/bin/IBM-PutGet.sh b/java/client/test/bin/IBM-PutGet.sh
deleted file mode 100755
index c75667c9f6..0000000000
--- a/java/client/test/bin/IBM-PutGet.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.PutGet -nt 6 $* \ No newline at end of file
diff --git a/java/client/test/bin/IBM-README.txt b/java/client/test/bin/IBM-README.txt
deleted file mode 100644
index b076f3b3ca..0000000000
--- a/java/client/test/bin/IBM-README.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-The IBM JMS Performance Harness scripts have take the following additional parameters
-
--tx : Enable transactions
--pp : Enable persistent messaging
-
--ms 1000 : Set message size (default 1000 bytes)
--cc 1 : Number of messages to per commit (default 1) Only applies to Sender/Subscriber
-
-The IBM JMS Performance Harness will need to be downloaded and the library added to client/test/lib.
-
-The Library can be found here:
-
-http://www.alphaworks.ibm.com/tech/perfharness
-
-Before running the required test the IBM JNDI Setup script should be run.
-
-This will create a filesystem based JNDI Context located at:
-
-System.properties{java.io.tmpdir}/IBMPerfTestsJNDI/ \ No newline at end of file
diff --git a/java/client/test/bin/IBM-Receiver.bat b/java/client/test/bin/IBM-Receiver.bat
deleted file mode 100644
index dff44d472a..0000000000
--- a/java/client/test/bin/IBM-Receiver.bat
+++ /dev/null
@@ -1,62 +0,0 @@
-@REM
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM
-
-@echo off
-REM Script to run the Qpid Java Broker
-
-set CMD="IBM-Receiver.bat"
-set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.Receiver %*
-
-rem Guess QPID_HOME if not defined
-set CURRENT_DIR=%cd%
-if not "%QPID_HOME%" == "" goto gotHome
-set QPID_HOME=%CURRENT_DIR%
-echo %QPID_HOME%
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-cd ..
-set QPID_HOME=%cd%
-cd %CURRENT_DIR%
-:gotHome
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-echo The QPID_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program
-goto end
-:okHome
-
-if not "%JAVA_HOME%" == "" goto gotJavaHome
-echo The JAVA_HOME environment variable is not defined
-echo This environment variable is needed to run this program
-goto exit
-:gotJavaHome
-if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
-goto okJavaHome
-:noJavaHome
-echo The JAVA_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program.
-goto exit
-:okJavaHome
-
-set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
-
-echo on
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
-
-:end
-
-pause \ No newline at end of file
diff --git a/java/client/test/bin/IBM-Receiver.sh b/java/client/test/bin/IBM-Receiver.sh
deleted file mode 100755
index f50f0f744e..0000000000
--- a/java/client/test/bin/IBM-Receiver.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-export MSGSIZE=100
-qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.Receiver $* \ No newline at end of file
diff --git a/java/client/test/bin/IBM-Sender.bat b/java/client/test/bin/IBM-Sender.bat
deleted file mode 100644
index b8826322e5..0000000000
--- a/java/client/test/bin/IBM-Sender.bat
+++ /dev/null
@@ -1,62 +0,0 @@
-@REM
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM
-
-@echo off
-REM Script to run the Qpid Java Broker
-
-set CMD="IBM-Sender.bat"
-set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.Sender -ms $MSGSIZE -mg 1000000 %*
-
-rem Guess QPID_HOME if not defined
-set CURRENT_DIR=%cd%
-if not "%QPID_HOME%" == "" goto gotHome
-set QPID_HOME=%CURRENT_DIR%
-echo %QPID_HOME%
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-cd ..
-set QPID_HOME=%cd%
-cd %CURRENT_DIR%
-:gotHome
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-echo The QPID_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program
-goto end
-:okHome
-
-if not "%JAVA_HOME%" == "" goto gotJavaHome
-echo The JAVA_HOME environment variable is not defined
-echo This environment variable is needed to run this program
-goto exit
-:gotJavaHome
-if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
-goto okJavaHome
-:noJavaHome
-echo The JAVA_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program.
-goto exit
-:okJavaHome
-
-set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
-
-echo on
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
-
-:end
-
-pause \ No newline at end of file
diff --git a/java/client/test/bin/IBM-Sender.sh b/java/client/test/bin/IBM-Sender.sh
deleted file mode 100755
index b99429fd54..0000000000
--- a/java/client/test/bin/IBM-Sender.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-export MSGSIZE=100
-qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Queue -tc jms.r11.Sender -ms $MSGSIZE -mg 1000000 $* \ No newline at end of file
diff --git a/java/client/test/bin/IBM-Subscriber.bat b/java/client/test/bin/IBM-Subscriber.bat
deleted file mode 100644
index 5245639eba..0000000000
--- a/java/client/test/bin/IBM-Subscriber.bat
+++ /dev/null
@@ -1,62 +0,0 @@
-@REM
-@REM Licensed to the Apache Software Foundation (ASF) under one
-@REM or more contributor license agreements. See the NOTICE file
-@REM distributed with this work for additional information
-@REM regarding copyright ownership. The ASF licenses this file
-@REM to you under the Apache License, Version 2.0 (the
-@REM "License"); you may not use this file except in compliance
-@REM with the License. You may obtain a copy of the License at
-@REM
-@REM http://www.apache.org/licenses/LICENSE-2.0
-@REM
-@REM Unless required by applicable law or agreed to in writing,
-@REM software distributed under the License is distributed on an
-@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@REM KIND, either express or implied. See the License for the
-@REM specific language governing permissions and limitations
-@REM under the License.
-@REM
-
-@echo off
-REM Script to run the Qpid Java Broker
-
-set CMD="IBM-Subscriber.bat"
-set JAVACLASS=JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:/C:/temp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Topic -db 1 -dx 4 -tc jms.r11.Subscriber -nt 4 %*
-
-rem Guess QPID_HOME if not defined
-set CURRENT_DIR=%cd%
-if not "%QPID_HOME%" == "" goto gotHome
-set QPID_HOME=%CURRENT_DIR%
-echo %QPID_HOME%
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-cd ..
-set QPID_HOME=%cd%
-cd %CURRENT_DIR%
-:gotHome
-if exist "%QPID_HOME%\bin\%CMD%" goto okHome
-echo The QPID_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program
-goto end
-:okHome
-
-if not "%JAVA_HOME%" == "" goto gotJavaHome
-echo The JAVA_HOME environment variable is not defined
-echo This environment variable is needed to run this program
-goto exit
-:gotJavaHome
-if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
-goto okJavaHome
-:noJavaHome
-echo The JAVA_HOME environment variable is not defined correctly
-echo This environment variable is needed to run this program.
-goto exit
-:okJavaHome
-
-set CLIENT_TEST_CLASSES=%QPID_HOME%\lib\client-test-launch.jar
-
-echo on
-"%JAVA_HOME%\bin\java" -server -Xmx1024m -DQPID_HOME="%QPID_HOME%" -cp "%CLIENT_TEST_CLASSES%" %JAVACLASS%
-
-:end
-
-pause \ No newline at end of file
diff --git a/java/client/test/bin/IBM-Subscriber.sh b/java/client/test/bin/IBM-Subscriber.sh
deleted file mode 100755
index 43550100be..0000000000
--- a/java/client/test/bin/IBM-Subscriber.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-export MSGSIZE=100
-qpid-run JMSPerfHarness -pc JNDI -ii com.sun.jndi.fscontext.RefFSContextFactory -iu file:///tmp/IBMPerfTestsJNDI/ -cf amq.ConnectionFactory -d amq.Topic -db 1 -dx 4 -tc jms.r11.Subscriber -nt 4 $* \ No newline at end of file
diff --git a/java/client/test/bin/headersListener.sh b/java/client/test/bin/headersListener.sh
deleted file mode 100755
index 81930b7043..0000000000
--- a/java/client/test/bin/headersListener.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.headers.Listener $*
diff --git a/java/client/test/bin/headersListenerGroup.sh b/java/client/test/bin/headersListenerGroup.sh
deleted file mode 100755
index e1cc05cfd2..0000000000
--- a/java/client/test/bin/headersListenerGroup.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/sh
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-for i; do
- ./headersListener.sh -host 10.0.0.1 -port 5672 >$i.out 2>$i.err &
- echo $! > $i.pid
-done;
diff --git a/java/client/test/bin/headersPublisher.sh b/java/client/test/bin/headersPublisher.sh
deleted file mode 100755
index fd9fd26416..0000000000
--- a/java/client/test/bin/headersPublisher.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.headers.Publisher $*
diff --git a/java/client/test/bin/run_many.sh b/java/client/test/bin/run_many.sh
deleted file mode 100755
index cca2ffec21..0000000000
--- a/java/client/test/bin/run_many.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-# args:
-# <number of processes to start>
-# <name of run>
-# <command ro run>
-
-for i in `seq 1 $1`; do
- $3 >$2.$i.out 2>>$2.err &
- echo $! > $2.$i.pid
-done;
diff --git a/java/client/test/bin/serviceProvidingClient.sh b/java/client/test/bin/serviceProvidingClient.sh
deleted file mode 100755
index cbcf5a0f4b..0000000000
--- a/java/client/test/bin/serviceProvidingClient.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-PROFILE=$1
-shift
-# XXX -Xms1024m -XX:NewSize=300m
-. qpid-run org.apache.qpid.requestreply1.ServiceProvidingClient $1 guest guest /test serviceQ
diff --git a/java/client/test/bin/serviceRequestingClient.sh b/java/client/test/bin/serviceRequestingClient.sh
deleted file mode 100755
index 213f44c00b..0000000000
--- a/java/client/test/bin/serviceRequestingClient.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-PROFILE=$1
-shift
-thehosts=$1
-shift
-echo $thehosts
-# XXX -Xms1024m -XX:NewSize=300m
-. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.requestreply1.ServiceRequestingClient $thehosts guest guest /test serviceQ "$@"
diff --git a/java/client/test/bin/testService.sh b/java/client/test/bin/testService.sh
deleted file mode 100755
index 20161c3abf..0000000000
--- a/java/client/test/bin/testService.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-. qpid-run org.apache.qpid.requestreply1.TestService 192.168.55.63 5672 foo x x
diff --git a/java/client/test/bin/topicListener.sh b/java/client/test/bin/topicListener.sh
deleted file mode 100755
index ac0cb63c91..0000000000
--- a/java/client/test/bin/topicListener.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-
-# XXX -Xmx512m -Xms512m -XX:NewSize=150m
-. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.topic.Listener $*
diff --git a/java/client/test/bin/topicPublisher.sh b/java/client/test/bin/topicPublisher.sh
deleted file mode 100755
index e35c131fe8..0000000000
--- a/java/client/test/bin/topicPublisher.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-# XXX -Xmx512m -Xms512m -XX:NewSize=150m
-. qpid-run -Damqj.logging.level="INFO" org.apache.qpid.topic.Publisher $*
diff --git a/java/client/test/etc/ApacheDS.properties b/java/client/test/etc/ApacheDS.properties
deleted file mode 100644
index 6c5cb4cec4..0000000000
--- a/java/client/test/etc/ApacheDS.properties
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-# Standard JNDI properties
-java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
-java.naming.provider.url=ldap://localhost:389/ou=system
-java.naming.security.authentication=simple
-java.naming.security.principal=uid=admin,ou=system
-java.naming.security.credentials=secret
diff --git a/java/client/test/example_build.xml b/java/client/test/example_build.xml
deleted file mode 100644
index dda3cb4263..0000000000
--- a/java/client/test/example_build.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0"?>
-<!--
- -
- - Licensed to the Apache Software Foundation (ASF) under one
- - or more contributor license agreements. See the NOTICE file
- - distributed with this work for additional information
- - regarding copyright ownership. The ASF licenses this file
- - to you under the Apache License, Version 2.0 (the
- - "License"); you may not use this file except in compliance
- - with the License. You may obtain a copy of the License at
- -
- - http://www.apache.org/licenses/LICENSE-2.0
- -
- - Unless required by applicable law or agreed to in writing,
- - software distributed under the License is distributed on an
- - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- - KIND, either express or implied. See the License for the
- - specific language governing permissions and limitations
- - under the License.
- -
- -->
-
-<!-- example Blaze Component Java build file -->
-
-<project name="example-client" default="jar" basedir=".">
- <property name="lib" value="${basedir}/lib"/>
- <property name="common.lib" value="${basedir}/../common/lib"/>
- <property name="example.dir" value="${basedir}"/>
- <property name="example.src" value="${example.dir}/src"/>
- <property name="example.lib" value="${example.dir}/lib"/>
- <property name="example.tests" value="${example.dir}/test"/>
- <property name="example.classes" value="${example.dir}/classes"/>
- <property name="dist" value="${basedir}/dist"/>
- <property name="dam.dist" value="${basedir}/damPackage"/>
-
- <!-- Setup details -->
- <target name="init">
- <tstamp>
- <format property="release" pattern="-dMMMyy" locale="en" timezone="GMT"/>
- </tstamp>
- <mkdir dir="${example.classes}"/>
- </target>
-
- <path id="example.classpath">
- <fileset dir="${common}/lib">
- <include name="**/*.jar"/>
- </fileset>
- <pathelement path="${example.classes}"/>
- </path>
-
- <!-- Remove all built files -->
- <target name="clean" depends="init">
- <delete dir="${example.classes}"/>
- </target>
-
- <path id="example_amq.classpath">
- <fileset dir="${basedir}/lib">
- <include name="**/*.jar"/>
- </fileset>
- <fileset dir="${example.lib}">
- <include name="**/*.jar"/>
- </fileset>
- <pathelement path="${example.classes}"/>
-
- </path>
-
- <!-- Compile Java -->
- <target name="compile" depends="init">
- <javac destdir="${example.classes}" debug="on" includeantruntime="false">
- <classpath refid="example_amq.classpath"/>
- <src path="${example.src}"/>
- <exclude name="**/Test*.java"/>
- </javac>
-
- <copy todir="${example.classes}">
- <!-- copy any non java src files into the build tree, e.g. properties files -->
- <fileset dir="${example.src}">
- <exclude name="**/*.java"/>
- <exclude name="**/package.html"/>
- </fileset>
- </copy>
- </target>
-
- <!-- Compile and build jar archive -->
- <target name="dist" depends="compile">
- <mkdir dir="${dist}"/>
- <jar basedir="${example.classes}" jarfile="${dist}/example_amq.jar"/>
- </target>
-
- <!-- Create release zip and tar -->
- <target name="release" depends="dist" description="Create a release package">
-
- <zip destfile="${dist}/example_client.zip">
- <zipfileset prefix="lib" file="${dist}/example_amq.jar" />
- </zip>
-
- <tar destfile="${dist}/example_client.tar.gz" compression="gzip">
- <tarfileset prefix="lib" file="${dist}/example_amq.jar" />
- </tar>
- </target>
-
-
-
-</project>
diff --git a/java/common.xml b/java/common.xml
index 7e7b9c0c07..2b61ef08c2 100644
--- a/java/common.xml
+++ b/java/common.xml
@@ -97,7 +97,8 @@
<property name="ivy.jar.dir" value="${project.root}/lib/ivy" />
<property name="ivy.install.version" value="2.2.0" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy-${ivy.install.version}.jar" />
- <property name="ivy.repo.url" value="http://repo1.maven.org/maven2/org/apache/ivy/ivy"/>
+ <property name="ivy.m2repo.url" value="http://repo1.maven.org/maven2"/>
+ <property name="ivy.repo.url" value="${ivy.m2repo.url}/org/apache/ivy/ivy"/>
<property name="ivy.jar.url" value="${ivy.repo.url}/${ivy.install.version}/ivy-${ivy.install.version}.jar"/>
<available property="ivy.jar.file.exists" file="${ivy.jar.file}"/>
diff --git a/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java b/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
index 97fbd43ea0..5268ce9bc2 100644
--- a/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
@@ -20,10 +20,11 @@ package org.apache.qpid.configuration;
/**
* This class centralized the Qpid client properties.
+ *
+ * @see CommonProperties
*/
public class ClientProperties
{
-
/**
* Currently with Qpid it is not possible to change the client ID.
* If one is not specified upon connection construction, an id is generated automatically.
@@ -118,10 +119,6 @@ public class ClientProperties
*/
public static final String REJECT_BEHAVIOUR_PROP_NAME = "qpid.reject.behaviour";
- private ClientProperties()
- {
- }
-
/**
* System property used to set the key manager factory algorithm.
*
@@ -192,4 +189,10 @@ public class ClientProperties
* waiting because the client was flow controlled by the broker.
*/
public static final long DEFAULT_FLOW_CONTROL_WAIT_NOTIFY_PERIOD = 5000L;
+
+
+ private ClientProperties()
+ {
+ //No instances
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java b/java/common/src/main/java/org/apache/qpid/configuration/CommonProperties.java
index 6787157e8e..2449f457e5 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java
+++ b/java/common/src/main/java/org/apache/qpid/configuration/CommonProperties.java
@@ -18,18 +18,24 @@
* under the License.
*
*/
-package org.apache.qpid.transport;
-
+package org.apache.qpid.configuration;
/**
- * ProtocolViolationException
+ * Centralised record of Qpid common properties.
*
+ * @see ClientProperties
*/
-
-public final class ProtocolViolationException extends ConnectionException
+public class CommonProperties
{
- public ProtocolViolationException(String msg,Throwable cause)
+ /**
+ * The timeout used by the IO layer for timeouts such as send timeout in IoSender, and the close timeout for IoSender and IoReceiver
+ */
+ public static final String IO_NETWORK_TRANSPORT_TIMEOUT_PROP_NAME = "qpid.io_network_transport_timeout";
+ public static final int IO_NETWORK_TRANSPORT_TIMEOUT_DEFAULT = 60000;
+
+
+ private CommonProperties()
{
- super(msg, cause);
+ //no instances
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/java/common/src/main/java/org/apache/qpid/transport/Connection.java
index 388e3442bf..e87851cf7d 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Connection.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Connection.java
@@ -382,7 +382,7 @@ public class Connection extends ConnectionInvoker
{
log.debug("SEND: [%s] %s", this, event);
}
- Sender s = sender;
+ Sender<ProtocolEvent> s = sender;
if (s == null)
{
throw new ConnectionException("connection closed");
@@ -415,15 +415,23 @@ public class Connection extends ConnectionInvoker
public void dispatch(Method method)
{
- Session ssn = getSession(method.getChannel());
+ int channel = method.getChannel();
+ Session ssn = getSession(channel);
if(ssn != null)
{
ssn.received(method);
}
else
{
- throw new ProtocolViolationException(
- "Received frames for an already detached session", null);
+ /*
+ * A peer receiving any other control on a detached transport MUST discard it and
+ * send a session.detached with the "not-attached" reason code.
+ */
+ if(log.isDebugEnabled())
+ {
+ log.debug("Control received on unattached channel : %d", channel);
+ }
+ invokeSessionDetached(channel, SessionDetachCode.NOT_ATTACHED);
}
}
@@ -663,7 +671,7 @@ public class Connection extends ConnectionInvoker
public void setServerProperties(final Map<String, Object> serverProperties)
{
- _serverProperties = serverProperties == null ? Collections.EMPTY_MAP : serverProperties;
+ _serverProperties = serverProperties == null ? Collections.<String, Object>emptyMap() : serverProperties;
}
public Map<String, Object> getServerProperties()
@@ -719,4 +727,12 @@ public class Connection extends ConnectionInvoker
{
return _localAddress;
}
+
+ private void invokeSessionDetached(int channel, SessionDetachCode sessionDetachCode)
+ {
+ SessionDetached sessionDetached = new SessionDetached();
+ sessionDetached.setChannel(channel);
+ sessionDetached.setCode(sessionDetachCode);
+ invoke(sessionDetached);
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java b/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
index c90a11594c..14dfeb18ec 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
@@ -60,9 +60,9 @@ public class ConnectionSettings
private int maxChannelCount = 32767;
private int maxFrameSize = 65535;
private int heartbeatInterval;
+ private int connectTimeout = 30000;
private int readBufferSize = QpidProperty.intProperty(65535, RECEIVE_BUFFER_SIZE_PROP_NAME, LEGACY_RECEIVE_BUFFER_SIZE_PROP_NAME).get();
private int writeBufferSize = QpidProperty.intProperty(65535, SEND_BUFFER_SIZE_PROP_NAME, LEGACY_SEND_BUFFER_SIZE_PROP_NAME).get();;
- private long transportTimeout = 60000;
// SSL props
private boolean useSSL;
@@ -345,6 +345,16 @@ public class ConnectionSettings
this.trustStoreType = trustStoreType;
}
+ public int getConnectTimeout()
+ {
+ return connectTimeout;
+ }
+
+ public void setConnectTimeout(int connectTimeout)
+ {
+ this.connectTimeout = connectTimeout;
+ }
+
public int getReadBufferSize()
{
return readBufferSize;
@@ -364,14 +374,4 @@ public class ConnectionSettings
{
this.writeBufferSize = writeBufferSize;
}
-
- public long getTransportTimeout()
- {
- return transportTimeout;
- }
-
- public void setTransportTimeout(long transportTimeout)
- {
- this.transportTimeout = transportTimeout;
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
index dfb318b80c..9b6f0a0b1b 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
@@ -33,6 +33,8 @@ import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
+
+import org.apache.qpid.configuration.CommonProperties;
import org.apache.qpid.protocol.ProtocolEngine;
import org.apache.qpid.protocol.ProtocolEngineFactory;
import org.apache.qpid.transport.ConnectionSettings;
@@ -47,7 +49,8 @@ import org.slf4j.LoggerFactory;
public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNetworkTransport
{
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(IoNetworkTransport.class);
- private static final int TIMEOUT = 60000;
+ private static final int TIMEOUT = Integer.getInteger(CommonProperties.IO_NETWORK_TRANSPORT_TIMEOUT_PROP_NAME,
+ CommonProperties.IO_NETWORK_TRANSPORT_TIMEOUT_DEFAULT);
private Socket _socket;
private IoNetworkConnection _connection;
@@ -75,7 +78,7 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
InetAddress address = InetAddress.getByName(settings.getHost());
- _socket.connect(new InetSocketAddress(address, settings.getPort()), TIMEOUT);
+ _socket.connect(new InetSocketAddress(address, settings.getPort()), settings.getConnectTimeout());
}
catch (SocketException e)
{
diff --git a/java/ivy.retrieve.xml b/java/ivy.retrieve.xml
index 98d3d3785d..3af847a48a 100644
--- a/java/ivy.retrieve.xml
+++ b/java/ivy.retrieve.xml
@@ -74,7 +74,7 @@
<!-- The following are optional dependencies, for modules providing optional functionlity or
for use in optional build/test steps. Their optional status is usually indicative of licences
which are not compatible with the Apache Licence -->
- <dependency org="com.sleepycat" name="je" rev="5.0.55" transitive="false" conf="bdbje"/>
+ <dependency org="com.sleepycat" name="je" rev="5.0.58" transitive="false" conf="bdbje"/>
<dependency org="jfree" name="jfreechart" rev="1.0.13" transitive="false" conf="jfree"/>
<dependency org="jfree" name="jcommon" rev="1.0.16" transitive="false" conf="jfree"/>
<dependency org="net.sourceforge.csvjdbc" name="csvjdbc" rev="1.0.8" transitive="false" conf="csvjdbc"/>
diff --git a/java/ivysettings.retrieve.xml b/java/ivysettings.retrieve.xml
index 8faf23c2d1..e31af1e5b5 100644
--- a/java/ivysettings.retrieve.xml
+++ b/java/ivysettings.retrieve.xml
@@ -18,7 +18,6 @@
<property name="ivy.default.resolver" value="chain" override="false"/>
<property name="ivy.localfs.root" value="${project.root}/localfs_repo" override="false"/>
<property name="ivy.localfs.pattern" value="[artifact]-[revision](-[classifier]).[ext]" override="false"/>
- <property name="ivy.m2repo.url" value="http://repo1.maven.org/maven2" override="false"/>
<settings defaultResolver="${ivy.default.resolver}"/>
<resolvers>
diff --git a/java/lib/poms/je-5.0.55.xml b/java/lib/poms/je-5.0.58.xml
index 0c40ea541a..d71a935dff 100644
--- a/java/lib/poms/je-5.0.55.xml
+++ b/java/lib/poms/je-5.0.58.xml
@@ -18,5 +18,5 @@
<dep>
<groupId>com.sleepycat</groupId>
<artifactId>je</artifactId>
- <version>5.0.55</version>
+ <version>5.0.58</version>
</dep>
diff --git a/java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transacted.chartdef b/java/perftests/etc/chartdefs/1021-AcknowledgementModes-Persistent.chartdef
index 5dcfa5a85e..30aee40c27 100644
--- a/java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transacted.chartdef
+++ b/java/perftests/etc/chartdefs/1021-AcknowledgementModes-Persistent.chartdef
@@ -19,14 +19,17 @@
chartType=BAR
chartTitle=Performance of acknowledgement modes
-chartSubtitle=Transacted
-xAxisTitle=Persistence
+chartSubtitle=Persistent messages (1024b)
+xAxisTitle=Acknowledge mode (0=session transacted; 1=auto-acknowledge)
yAxisTitle=Throughput (KB/s)
-series.1.statement=SELECT testName, throughputKbPerS FROM AcknowledgementModes WHERE acknowledgeMode = '0' AND participantName = 'All'
+series.1.statement=SELECT acknowledgeMode, throughputKbPerS FROM AcknowledgementModes WHERE testName like 'Persistent%' AND participantName = 'All' ORDER BY acknowledgeMode
series.1.legend=Current
series.1.dir=${csvCurrentDir}
-series.2.statement=SELECT testName, throughputKbPerS FROM AcknowledgementModes WHERE acknowledgeMode = '0' AND participantName = 'All'
+
+
+series.2.statement=SELECT acknowledgeMode, throughputKbPerS FROM AcknowledgementModes WHERE testName like 'Persistent%' AND participantName = 'All' ORDER BY acknowledgeMode
series.2.legend=Baseline
series.2.dir=${csvBaselineDir}
+
diff --git a/java/perftests/etc/chartdefs/1021-AcknowledgementModes-AutoAck.chartdef b/java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transient.chartdef
index 009ac6d80f..7a26391deb 100644
--- a/java/perftests/etc/chartdefs/1021-AcknowledgementModes-AutoAck.chartdef
+++ b/java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transient.chartdef
@@ -19,15 +19,14 @@
chartType=BAR
chartTitle=Performance of acknowledgement modes
-chartSubtitle=Auto-acknowledge
-xAxisTitle=Persistence
+chartSubtitle=Transient messages (1024b)
+xAxisTitle=Acknowledge mode (0=session transacted; 1=auto-acknowledge)
yAxisTitle=Throughput (KB/s)
-series.1.statement=SELECT testName, throughputKbPerS FROM AcknowledgementModes WHERE acknowledgeMode = '1' AND participantName = 'All'
+series.1.statement=SELECT acknowledgeMode, throughputKbPerS FROM AcknowledgementModes WHERE testName like 'Transient%' AND participantName = 'All' ORDER BY acknowledgeMode
series.1.legend=Current
series.1.dir=${csvCurrentDir}
-series.2.statement=SELECT testName, throughputKbPerS FROM AcknowledgementModes WHERE acknowledgeMode = '1' AND participantName = 'All'
+series.2.statement=SELECT acknowledgeMode, throughputKbPerS FROM AcknowledgementModes WHERE testName like 'Transient%' AND participantName = 'All' ORDER BY acknowledgeMode
series.2.legend=Baseline
series.2.dir=${csvBaselineDir}
-
diff --git a/java/perftests/etc/testdefs/Topic-AckModes.js b/java/perftests/etc/testdefs/Topic-AckModes.js
index 5c4dee88e3..63c4b8646e 100644
--- a/java/perftests/etc/testdefs/Topic-AckModes.js
+++ b/java/perftests/etc/testdefs/Topic-AckModes.js
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
var duration = 30000;
var topicName = "topic://amq.topic/?routingkey='testTopic'";
@@ -30,6 +50,7 @@ var jsonObject = {
{
"_name": "Producer",
"_destinationName": topicName,
+ "_deliveryMode": 1,
"_maximumDuration": duration,
"_startDelay": 2000 // gives the consumers time to implicitly create the topic
}
diff --git a/java/perftests/etc/testdefs/Topic-NumberOfConsumers.js b/java/perftests/etc/testdefs/Topic-NumberOfConsumers.js
index 751b8b1528..58ae2f5862 100644
--- a/java/perftests/etc/testdefs/Topic-NumberOfConsumers.js
+++ b/java/perftests/etc/testdefs/Topic-NumberOfConsumers.js
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
var jsonObject = {
_tests:[]
};
@@ -26,6 +46,7 @@ for(i=0; i < numbersOfConsumers.length ; i++)
{
"_name": "Producer1",
"_destinationName": topicName,
+ "_deliveryMode": 1,
"_maximumDuration": duration,
"_startDelay": 2000 // gives the consumers time to implicitly create the topic
}
diff --git a/java/perftests/etc/testdefs/Topic-NumberOfTopics.js b/java/perftests/etc/testdefs/Topic-NumberOfTopics.js
index 89e5ecf56c..d31dd36c76 100644
--- a/java/perftests/etc/testdefs/Topic-NumberOfTopics.js
+++ b/java/perftests/etc/testdefs/Topic-NumberOfTopics.js
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
var jsonObject = {
_tests:[]
};
@@ -29,6 +49,7 @@ for(i=0; i < numbersOfTopics.length ; i++)
{
"_name": "Producer-__INDEX",
"_destinationName": topicName,
+ "_deliveryMode": 1,
"_maximumDuration": duration,
"_startDelay": 2000 // gives the consumers time to implicitly create the topic
}
diff --git a/java/perftests/etc/testdefs/Topic-Persistence.js b/java/perftests/etc/testdefs/Topic-Persistence.js
index fd92560fc3..bbec7ab8ed 100644
--- a/java/perftests/etc/testdefs/Topic-Persistence.js
+++ b/java/perftests/etc/testdefs/Topic-Persistence.js
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
var duration = 30000;
var topicName = "topic://amq.topic/?routingkey='testTopic'";
diff --git a/java/perftests/example/perftests.js b/java/perftests/example/perftests.js
index 51160e7214..be7d5e0be4 100644
--- a/java/perftests/example/perftests.js
+++ b/java/perftests/example/perftests.js
@@ -1,4 +1,23 @@
-
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
var jsonObject = {
_tests:[]
};
diff --git a/java/perftests/src/main/java/test-utils.js b/java/perftests/src/main/java/test-utils.js
index 7bfe233266..cbf27786b7 100644
--- a/java/perftests/src/main/java/test-utils.js
+++ b/java/perftests/src/main/java/test-utils.js
@@ -1,3 +1,23 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
var QPID;
if (!QPID) {
QPID = {};
diff --git a/java/perftests/visualisation-jfc/src/main/java/org/apache/qpid/disttest/charting/writer/ChartWriter.java b/java/perftests/visualisation-jfc/src/main/java/org/apache/qpid/disttest/charting/writer/ChartWriter.java
index 08bdf122ba..5d4a9b6b7e 100644
--- a/java/perftests/visualisation-jfc/src/main/java/org/apache/qpid/disttest/charting/writer/ChartWriter.java
+++ b/java/perftests/visualisation-jfc/src/main/java/org/apache/qpid/disttest/charting/writer/ChartWriter.java
@@ -105,8 +105,17 @@ public class ChartWriter
writer = new BufferedWriter(new FileWriter(summaryFile));
writer.write(htmlHeader);
+
+ writer.write(" <ul>\n");
+ for (File chartFile : _chartFiles)
+ {
+ writer.write(" <li><a href='#"+ chartFile.getName() +"'>" + chartFile.getName() + "</a></li>\n");
+ }
+ writer.write(" </ul>\n");
+
for (File chartFile : _chartFiles)
{
+ writer.write(" <a name='" + chartFile.getName() + "'/>\n");
writer.write(" <img src='" + chartFile.getName() + "'/>\n");
}
writer.write(htmlFooter);
diff --git a/java/perftests/visualisation-jfc/src/test/java/org/apache/qpid/disttest/charting/writer/expected-chart-summary.html b/java/perftests/visualisation-jfc/src/test/java/org/apache/qpid/disttest/charting/writer/expected-chart-summary.html
index d1f039f44a..89c508a77e 100644..100755
--- a/java/perftests/visualisation-jfc/src/test/java/org/apache/qpid/disttest/charting/writer/expected-chart-summary.html
+++ b/java/perftests/visualisation-jfc/src/test/java/org/apache/qpid/disttest/charting/writer/expected-chart-summary.html
@@ -3,7 +3,13 @@
<title>Performance Charts</title>
</head>
<body>
+ <ul>
+ <li><a href='#chart1.png'>chart1.png</a></li>
+ <li><a href='#chart2.png'>chart2.png</a></li>
+ </ul>
+ <a name='chart1.png'/>
<img src='chart1.png'/>
+ <a name='chart2.png'/>
<img src='chart2.png'/>
</body>
</html> \ No newline at end of file
diff --git a/java/systests/etc/log.properties b/java/systests/etc/log.properties
index 745c5187c9..ff36b7cd0c 100644
--- a/java/systests/etc/log.properties
+++ b/java/systests/etc/log.properties
@@ -1,2 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
com.sleepycat.je.util.FileHandler.level=ALL
com.sleepycat.je.util.ConsoleHandler.level=ALL
diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java b/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java
deleted file mode 100644
index 62ea5fdcc9..0000000000
--- a/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.queue;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.AMQChannelClosedException;
-import org.apache.qpid.AMQConnectionClosedException;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.url.URLSyntaxException;
-import org.apache.qpid.util.CommandLineParser;
-
-import javax.jms.JMSException;
-import javax.jms.MessageProducer;
-import javax.jms.Queue;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-import java.io.IOException;
-import java.util.Properties;
-
-public class PersistentTestManual
-{
- private static final Logger _logger = Logger.getLogger(PersistentTestManual.class);
-
-
- private static final String QUEUE = "direct://amq.direct//PersistentTest-Queue2?durable='true',exclusive='true'";
-
- protected AMQConnection _connection;
-
- protected Session _session;
-
- protected Queue _queue;
- private Properties properties;
-
- private String _brokerDetails;
- private String _username;
- private String _password;
- private String _virtualpath;
-
- public PersistentTestManual(Properties overrides)
- {
- properties = new Properties(defaults);
- properties.putAll(overrides);
-
- _brokerDetails = properties.getProperty(BROKER_PROPNAME);
- _username = properties.getProperty(USERNAME_PROPNAME);
- _password = properties.getProperty(PASSWORD_PROPNAME);
- _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME);
-
- createConnection();
- }
-
- protected void createConnection()
- {
- try
- {
- _connection = new AMQConnection(_brokerDetails, _username, _password, "PersistentTest", _virtualpath);
-
- _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- _connection.start();
- }
- catch (Exception e)
- {
- _logger.error("Unable to create test class due to:" + e.getMessage(), e);
- System.exit(0);
- }
- }
-
- public void test() throws AMQException, URLSyntaxException
- {
-
- //Create the Durable Queue
- try
- {
- _session.createConsumer(_session.createQueue(QUEUE)).close();
- }
- catch (JMSException e)
- {
- _logger.error("Unable to create Queue due to:" + e.getMessage(), e);
- System.exit(0);
- }
-
- try
- {
- if (testQueue())
- {
- // close connection
- _connection.close();
- // wait
- System.out.println("Restart Broker Now");
- try
- {
- System.in.read();
- }
- catch (IOException e)
- {
- //
- }
- finally
- {
- System.out.println("Continuing....");
- }
-
- //Test queue is still there.
- AMQConnection connection = new AMQConnection(_brokerDetails, _username, _password, "DifferentClientID", _virtualpath);
-
- AMQSession session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- try
- {
- session.createConsumer(session.createQueue(QUEUE));
- _logger.error("Create consumer succeeded." +
- " This shouldn't be allowed as this means the queue didn't exist when it should");
-
- connection.close();
-
- exit();
- }
- catch (JMSException e)
- {
- try
- {
- connection.close();
- }
- catch (JMSException cce)
- {
- if (cce.getLinkedException() instanceof AMQConnectionClosedException)
- {
- _logger.error("Channel Close Bug still present QPID-432, should see an 'Error closing session'");
- }
- else
- {
- exit(cce);
- }
- }
-
- if (e.getLinkedException() instanceof AMQChannelClosedException)
- {
- _logger.info("AMQChannelClosedException received as expected");
- }
- else
- {
- exit(e);
- }
- }
- }
- }
- catch (JMSException e)
- {
- _logger.error("Unable to test Queue due to:" + e.getMessage(), e);
- System.exit(0);
- }
- }
-
- private void exit(JMSException e)
- {
- _logger.error("JMSException received:" + e.getMessage());
- e.printStackTrace();
- exit();
- }
-
- private void exit()
- {
- try
- {
- _connection.close();
- }
- catch (JMSException e)
- {
- //
- }
- System.exit(0);
- }
-
- private boolean testQueue() throws JMSException
- {
- String TEST_TEXT = "init";
-
- //Create a new session to send producer
- Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
- Queue q = session.createQueue(QUEUE);
- MessageProducer producer = session.createProducer(q);
-
- producer.send(session.createTextMessage(TEST_TEXT));
-
- //create a new consumer on the original session
- TextMessage m = (TextMessage) _session.createConsumer(q).receive();
-
-
- if ((m != null) && m.getText().equals(TEST_TEXT))
- {
- return true;
- }
- else
- {
- _logger.error("Incorrect values returned from Queue Test:" + m);
- System.exit(0);
- return false;
- }
- }
-
- /** Holds the name of the property to get the test broker url from. */
- public static final String BROKER_PROPNAME = "broker";
-
- /** Holds the default broker url for the test. */
- public static final String BROKER_DEFAULT = "tcp://localhost:5672";
-
- /** Holds the name of the property to get the test broker virtual path. */
- public static final String VIRTUAL_HOST_PROPNAME = "virtualHost";
-
- /** Holds the default virtual path for the test. */
- public static final String VIRTUAL_HOST_DEFAULT = "";
-
- /** Holds the name of the property to get the broker access username from. */
- public static final String USERNAME_PROPNAME = "username";
-
- /** Holds the default broker log on username. */
- public static final String USERNAME_DEFAULT = "guest";
-
- /** Holds the name of the property to get the broker access password from. */
- public static final String PASSWORD_PROPNAME = "password";
-
- /** Holds the default broker log on password. */
- public static final String PASSWORD_DEFAULT = "guest";
-
- /** Holds the default configuration properties. */
- public static Properties defaults = new Properties();
-
- static
- {
- defaults.setProperty(BROKER_PROPNAME, BROKER_DEFAULT);
- defaults.setProperty(USERNAME_PROPNAME, USERNAME_DEFAULT);
- defaults.setProperty(PASSWORD_PROPNAME, PASSWORD_DEFAULT);
- defaults.setProperty(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT);
- }
-
- public static void main(String[] args)
- {
- PersistentTestManual test;
-
- Properties options =
- CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][]{}), System.getProperties());
-
- test = new PersistentTestManual(options);
- try
- {
- test.test();
- System.out.println("Test was successfull.");
- }
- catch (Exception e)
- {
- _logger.error("Unable to test due to:" + e.getMessage(), e);
- }
- }
-}
diff --git a/java/test-profiles/python_tests/Java010PythonExcludes b/java/test-profiles/python_tests/Java010PythonExcludes
index d3c058a2e9..f99a6d5bba 100644
--- a/java/test-profiles/python_tests/Java010PythonExcludes
+++ b/java/test-profiles/python_tests/Java010PythonExcludes
@@ -58,6 +58,7 @@ qpid_tests.broker_0_10.dtx.DtxTests.test_simple_prepare_commit
qpid_tests.broker_0_10.dtx.DtxTests.test_simple_prepare_rollback
qpid_tests.broker_0_10.dtx.DtxTests.test_simple_rollback
+qpid_tests.broker_0_10.new_api.GeneralTests.test_qpid_3481_acquired_to_alt_exchange_2_consumers
###### Java Broker defects ######
diff --git a/python/qpid/util.py b/python/qpid/util.py
index 7541595453..39ad1d830e 100644
--- a/python/qpid/util.py
+++ b/python/qpid/util.py
@@ -27,7 +27,7 @@ except ImportError:
def __init__(self, sock, keyfile=None, certfile=None, trustfile=None):
self.sock = sock
- self.ssl = wrap_socket(sock, keyfile=keyfile, certfile=certfile, ca_certs=trustfile)
+ self.ssl = wrap_socket(sock, keyfile=keyfile, certfile=certfile)
def recv(self, n):
return self.ssl.read(n)
diff --git a/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py b/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py
index 8cbb5793d9..2e2d5de13a 100644
--- a/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py
+++ b/tests/src/py/qpid_tests/broker_0_10/alternate_exchange.py
@@ -308,8 +308,6 @@ class AlternateExchangeTests(TestBase010):
#create a queue using the intermediary as its alternate exchange:
session.queue_declare(queue="delivery-queue", alternate_exchange="my-exchange", auto_delete=True)
- #bind that queue to the dlq as well:
- session.exchange_bind(exchange="dlq", queue="delivery-queue")
#send it some messages:
dp=self.session.delivery_properties(routing_key="delivery-queue")
for m in ["One", "Two", "Three"]:
@@ -349,5 +347,5 @@ class AlternateExchangeTests(TestBase010):
def assertEmpty(self, queue):
try:
msg = queue.get(timeout=1)
- self.fail("Queue not empty: " + msg)
+ self.fail("Queue not empty: " + str(msg))
except Empty: None
diff --git a/tests/src/py/qpid_tests/broker_0_10/management.py b/tests/src/py/qpid_tests/broker_0_10/management.py
index a1316ea854..4ec3e0dd03 100644
--- a/tests/src/py/qpid_tests/broker_0_10/management.py
+++ b/tests/src/py/qpid_tests/broker_0_10/management.py
@@ -498,7 +498,7 @@ class ManagementTest (TestBase010):
session.queue_declare(queue="whatever", exclusive=True, auto_delete=True)
def test_immediate_method(self):
- url = "%s://%s:%d" % (self.broker.scheme or "amqp", self.broker.host, self.broker.port)
+ url = "%s://%s:%d" % (self.broker.scheme or "amqp", self.broker.host or "localhost", self.broker.port or 5672)
conn = qpid.messaging.Connection(url)
conn.open()
sess = conn.session()
@@ -659,7 +659,7 @@ class ManagementTest (TestBase010):
self.assertEqual(rc.receive, True)
# setup a connection & session to the broker
- url = "%s://%s:%d" % (self.broker.scheme or "amqp", self.broker.host, self.broker.port)
+ url = "%s://%s:%d" % (self.broker.scheme or "amqp", self.broker.host or "localhost", self.broker.port or 5672)
conn = qpid.messaging.Connection(url)
conn.open()
sess = conn.session()
diff --git a/tests/src/py/qpid_tests/broker_0_10/msg_groups.py b/tests/src/py/qpid_tests/broker_0_10/msg_groups.py
index ace7611a2f..ec015e1be4 100644
--- a/tests/src/py/qpid_tests/broker_0_10/msg_groups.py
+++ b/tests/src/py/qpid_tests/broker_0_10/msg_groups.py
@@ -787,7 +787,7 @@ class MultiConsumerMsgGroupTests(Base):
except Empty:
pass
assert count == 3 # non-A's
- assert a_count == 2 # pending acquired message included in browse results
+ assert a_count == 1 # assumes the acquired message was not the one purged and regular browsers don't get acquired messages
s1.acknowledge() # ack the consumed A-0
self.qmf_session.delBroker(self.qmf_broker)
diff --git a/tests/src/py/qpid_tests/broker_0_10/new_api.py b/tests/src/py/qpid_tests/broker_0_10/new_api.py
index 05c4815e57..18a13e3ddf 100644
--- a/tests/src/py/qpid_tests/broker_0_10/new_api.py
+++ b/tests/src/py/qpid_tests/broker_0_10/new_api.py
@@ -106,10 +106,10 @@ class GeneralTests(Base):
self.assertEqual(rx_alt.available(), 0, "No messages should have been routed to the alt_exchange")
- # Close sess1; This will cause the queue to be deleted
+ # Close sess1; This will cause the queue to be deleted and all its messages (including those acquired) to be reouted to the alternate exchange
sess1.close()
sleep(1)
- self.assertEqual(rx_alt.available(), 2, "2 of the messages should have been routed to the alt_exchange")
+ self.assertEqual(rx_alt.available(), 5, "All the messages should have been routed to the alt_exchange")
# Close sess2; This will cause the acquired messages to be requeued and routed to the alternate
sess2.close()
diff --git a/tests/src/py/qpid_tests/broker_0_10/priority.py b/tests/src/py/qpid_tests/broker_0_10/priority.py
index f99e908d76..bf4f1209b1 100644
--- a/tests/src/py/qpid_tests/broker_0_10/priority.py
+++ b/tests/src/py/qpid_tests/broker_0_10/priority.py
@@ -112,11 +112,11 @@ class PriorityTests (Base):
#check all messages on the queue were received by the browser; don't relay on any specific ordering at present
assert set([m.content for m in msgs]) == set([m.content for m in received])
- def ring_queue_check(self, msgs):
+ def ring_queue_check(self, msgs, count=10):
"""
Ensure that a ring queue removes lowest priority messages first.
"""
- snd = self.ssn.sender(address("priority-ring-queue", arguments="x-qpid-priorities:10, 'qpid.policy_type':ring, 'qpid.max_count':10"),
+ snd = self.ssn.sender(address("priority-ring-queue", arguments="x-qpid-priorities:10, 'qpid.policy_type':ring, 'qpid.max_count':%s" % count),
durable=self.durable())
for m in msgs: snd.send(m)
@@ -126,23 +126,31 @@ class PriorityTests (Base):
while True: received.append(rcv.fetch(0))
except Empty: None
- expected = []
- for m in msgs:
- while len(expected) > 9:
- expected=sorted_(expected, key=lambda x: priority_level(x.priority,10))
- expected.pop(0)
- expected.append(m)
- #print "sent %s; expected %s; got %s" % ([m.content for m in msgs], [m.content for m in expected], [m.content for m in received])
+ expected = sorted_(msgs, key=lambda x: priority_level(x.priority,10))[len(msgs)-count:]
+ expected = sorted_(expected, key=lambda x: priority_level(x.priority,10), reverse=True)
+ #print "sent %s; expected %s; got %s" % ([m.priority for m in msgs], [m.priority for m in expected], [m.priority for m in received])
+ #print "sent %s; expected %s; got %s" % ([m.content for m in msgs], [m.content for m in expected], [m.content for m in received])
assert [m.content for m in expected] == [m.content for m in received]
def test_ring_queue_1(self):
priorities = [4,5,3,6,9,9,2,9,2,9,9,1,9,9,9,3,3,3,9,9,3,9,3,9,9,9,9,9,9,2,3]
- seq = content("msg")
+ seq = content("msg")
self.ring_queue_check([Message(content=seq.next(), priority = p) for p in priorities])
def test_ring_queue_2(self):
- priorities = [9,0,2,3,6,9,9,2,9,2,9,9,1,9,4,7,1,1,3,9,9,3,9,3,9,9,9,1,9,9,2,3,0,9]
- seq = content("msg")
+ priorities = [9,0,2,3,6,3,4,2,9,2,9,9,1,9,4,7,1,1,3,9,7,3,9,3,9,1,5,1,9,7,2,3,0,9]
+ seq = content("msg")
+ self.ring_queue_check([Message(content=seq.next(), priority = p) for p in priorities])
+
+ def test_ring_queue_3(self):
+ #test case given for QPID-3866
+ priorities = [8,9,5,1,2,2,3,4,9,7,8,9,9,2]
+ seq = content("msg")
+ self.ring_queue_check([Message(content=seq.next(), priority = p) for p in priorities], 5)
+
+ def test_ring_queue_4(self):
+ priorities = [9,0,2,3,6,3,4,2,9,2,9,3,1,9,4,7,1,1,3,2,7,3,9,3,6,1,5,1,9,7,2,3,0,2]
+ seq = content("msg")
self.ring_queue_check([Message(content=seq.next(), priority = p) for p in priorities])
def test_requeue(self):
@@ -169,6 +177,7 @@ class PriorityTests (Base):
for expected in sorted_(msgs, key=lambda m: priority_level(m.priority,10), reverse=True):
msg = rcv.fetch(0)
#print "expected priority %s got %s" % (expected.priority, msg.priority)
+ #print "expected content %s got %s" % (expected.content, msg.content)
assert msg.content == expected.content
self.ssn.acknowledge(msg)
@@ -231,7 +240,7 @@ def sorted_(msgs, key=None, reverse=False):
Workaround lack of sorted builtin function in python 2.3 and lack
of keyword arguments to list.sort()
"""
- temp = msgs
+ temp = [m for m in msgs]
temp.sort(key_to_cmp(key, reverse=reverse))
return temp
diff --git a/tests/src/py/qpid_tests/broker_0_10/threshold.py b/tests/src/py/qpid_tests/broker_0_10/threshold.py
index 6628ae8424..0ad2295822 100644
--- a/tests/src/py/qpid_tests/broker_0_10/threshold.py
+++ b/tests/src/py/qpid_tests/broker_0_10/threshold.py
@@ -41,7 +41,7 @@ class ThresholdTests (Base):
snd.send(m)
count = count + 1
size = size + len(m.content)
- event = rcv.fetch()
+ event = rcv.fetch(timeout=1)
schema = event.content[0]["_schema_id"]
assert schema["_class_name"] == "queueThresholdExceeded"
values = event.content[0]["_values"]