summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src')
-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
251 files changed, 5578 insertions, 17092 deletions
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.