summaryrefslogtreecommitdiff
path: root/cpp/src/qpid
diff options
context:
space:
mode:
authorKim van der Riet <kpvdr@apache.org>2012-05-04 15:39:19 +0000
committerKim van der Riet <kpvdr@apache.org>2012-05-04 15:39:19 +0000
commit633c33f224f3196f3f9bd80bd2e418d8143fea06 (patch)
tree1391da89470593209466df68c0b40b89c14963b1 /cpp/src/qpid
parentc73f9286ebff93a6c8dbc29cf05e258c4b55c976 (diff)
downloadqpid-python-633c33f224f3196f3f9bd80bd2e418d8143fea06.tar.gz
QPID-3858: Updated branch - merged from trunk r.1333987
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/asyncstore@1334037 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/src/qpid')
-rw-r--r--cpp/src/qpid/Options.cpp7
-rw-r--r--cpp/src/qpid/Url.cpp17
-rw-r--r--cpp/src/qpid/UrlArray.cpp2
-rw-r--r--cpp/src/qpid/UrlArray.h1
-rw-r--r--cpp/src/qpid/acl/Acl.cpp183
-rw-r--r--cpp/src/qpid/acl/Acl.h75
-rw-r--r--cpp/src/qpid/acl/AclConnectionCounter.cpp214
-rw-r--r--cpp/src/qpid/acl/AclConnectionCounter.h81
-rw-r--r--cpp/src/qpid/acl/AclData.cpp572
-rw-r--r--cpp/src/qpid/acl/AclData.h89
-rw-r--r--cpp/src/qpid/acl/AclPlugin.cpp4
-rw-r--r--cpp/src/qpid/acl/AclReader.cpp222
-rw-r--r--cpp/src/qpid/acl/AclReader.h80
-rw-r--r--cpp/src/qpid/acl/AclValidator.cpp61
-rw-r--r--cpp/src/qpid/acl/AclValidator.h24
-rw-r--r--cpp/src/qpid/acl/management-schema.xml34
-rw-r--r--cpp/src/qpid/agent/ManagementAgentImpl.cpp11
-rw-r--r--cpp/src/qpid/broker/AclModule.h191
-rw-r--r--cpp/src/qpid/broker/Bridge.cpp15
-rw-r--r--cpp/src/qpid/broker/Bridge.h13
-rw-r--r--cpp/src/qpid/broker/Broker.cpp7
-rw-r--r--cpp/src/qpid/broker/Broker.h87
-rw-r--r--cpp/src/qpid/broker/Connection.cpp16
-rw-r--r--cpp/src/qpid/broker/Connection.h5
-rw-r--r--cpp/src/qpid/broker/ConnectionHandler.cpp1
-rw-r--r--cpp/src/qpid/broker/ConnectionHandler.h1
-rw-r--r--cpp/src/qpid/broker/DirectExchange.cpp3
-rw-r--r--cpp/src/qpid/broker/DirectExchange.h4
-rw-r--r--cpp/src/qpid/broker/DtxManager.cpp29
-rw-r--r--cpp/src/qpid/broker/DtxManager.h3
-rw-r--r--cpp/src/qpid/broker/DtxWorkRecord.cpp11
-rw-r--r--cpp/src/qpid/broker/Exchange.cpp28
-rw-r--r--cpp/src/qpid/broker/Exchange.h2
-rw-r--r--cpp/src/qpid/broker/ExchangeRegistry.cpp3
-rw-r--r--cpp/src/qpid/broker/ExchangeRegistry.h6
-rw-r--r--cpp/src/qpid/broker/Fairshare.cpp1
-rw-r--r--cpp/src/qpid/broker/FanOutExchange.cpp2
-rw-r--r--cpp/src/qpid/broker/FanOutExchange.h4
-rw-r--r--cpp/src/qpid/broker/HeadersExchange.cpp3
-rw-r--r--cpp/src/qpid/broker/HeadersExchange.h4
-rw-r--r--cpp/src/qpid/broker/LegacyLVQ.cpp29
-rw-r--r--cpp/src/qpid/broker/LegacyLVQ.h1
-rw-r--r--cpp/src/qpid/broker/Link.cpp263
-rw-r--r--cpp/src/qpid/broker/Link.h58
-rw-r--r--cpp/src/qpid/broker/LinkRegistry.cpp31
-rw-r--r--cpp/src/qpid/broker/LinkRegistry.h110
-rw-r--r--cpp/src/qpid/broker/Message.cpp8
-rw-r--r--cpp/src/qpid/broker/MessageDeque.cpp20
-rw-r--r--cpp/src/qpid/broker/MessageDeque.h7
-rw-r--r--cpp/src/qpid/broker/MessageGroupManager.cpp92
-rw-r--r--cpp/src/qpid/broker/MessageGroupManager.h19
-rw-r--r--cpp/src/qpid/broker/MessageMap.cpp78
-rw-r--r--cpp/src/qpid/broker/MessageMap.h2
-rw-r--r--cpp/src/qpid/broker/PriorityQueue.cpp118
-rw-r--r--cpp/src/qpid/broker/PriorityQueue.h27
-rw-r--r--cpp/src/qpid/broker/Queue.cpp667
-rw-r--r--cpp/src/qpid/broker/Queue.h147
-rw-r--r--cpp/src/qpid/broker/QueueListeners.cpp4
-rw-r--r--cpp/src/qpid/broker/QueueListeners.h7
-rw-r--r--cpp/src/qpid/broker/QueuedMessage.cpp (renamed from cpp/src/qpid/sys/apr/Time.cpp)24
-rw-r--r--cpp/src/qpid/broker/QueuedMessage.h3
-rw-r--r--cpp/src/qpid/broker/SaslAuthenticator.cpp1
-rw-r--r--cpp/src/qpid/broker/SemanticState.cpp4
-rw-r--r--cpp/src/qpid/broker/SemanticState.h65
-rw-r--r--cpp/src/qpid/broker/SessionAdapter.cpp51
-rw-r--r--cpp/src/qpid/broker/SessionAdapter.h4
-rw-r--r--cpp/src/qpid/broker/SessionHandler.cpp5
-rw-r--r--cpp/src/qpid/broker/SessionHandler.h10
-rw-r--r--cpp/src/qpid/broker/TopicExchange.cpp3
-rw-r--r--cpp/src/qpid/broker/TopicExchange.h4
-rw-r--r--cpp/src/qpid/broker/windows/SaslAuthenticator.cpp1
-rw-r--r--cpp/src/qpid/client/Connection.cpp2
-rw-r--r--cpp/src/qpid/client/ConnectionHandler.cpp10
-rw-r--r--cpp/src/qpid/client/ConnectionImpl.cpp4
-rw-r--r--cpp/src/qpid/client/LoadPlugins.cpp6
-rw-r--r--cpp/src/qpid/client/SessionImpl.cpp2
-rw-r--r--cpp/src/qpid/client/SslConnector.cpp4
-rw-r--r--cpp/src/qpid/client/TCPConnector.cpp8
-rw-r--r--cpp/src/qpid/client/amqp0_10/AddressResolution.cpp1
-rw-r--r--cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp3
-rw-r--r--cpp/src/qpid/cluster/Cluster.cpp28
-rw-r--r--cpp/src/qpid/cluster/ClusterMap.cpp4
-rw-r--r--cpp/src/qpid/cluster/ClusterTimer.cpp2
-rw-r--r--cpp/src/qpid/cluster/Connection.cpp49
-rw-r--r--cpp/src/qpid/cluster/Connection.h2
-rw-r--r--cpp/src/qpid/cluster/CredentialsExchange.cpp3
-rw-r--r--cpp/src/qpid/cluster/CredentialsExchange.h2
-rw-r--r--cpp/src/qpid/cluster/FailoverExchange.cpp2
-rw-r--r--cpp/src/qpid/cluster/FailoverExchange.h2
-rw-r--r--cpp/src/qpid/cluster/InitialStatusMap.cpp2
-rw-r--r--cpp/src/qpid/cluster/UpdateClient.cpp11
-rw-r--r--cpp/src/qpid/cluster/UpdateDataExchange.cpp4
-rw-r--r--cpp/src/qpid/cluster/UpdateDataExchange.h3
-rw-r--r--cpp/src/qpid/framing/AMQFrame.h3
-rw-r--r--cpp/src/qpid/framing/BodyHandler.cpp56
-rw-r--r--cpp/src/qpid/framing/FieldTable.cpp219
-rw-r--r--cpp/src/qpid/framing/FrameSet.cpp5
-rw-r--r--cpp/src/qpid/framing/FrameSet.h1
-rw-r--r--cpp/src/qpid/framing/MethodContent.h2
-rw-r--r--cpp/src/qpid/framing/TransferContent.cpp2
-rw-r--r--cpp/src/qpid/framing/TransferContent.h2
-rw-r--r--cpp/src/qpid/framing/amqp_framing.h1
-rw-r--r--cpp/src/qpid/ha/Backup.cpp36
-rw-r--r--cpp/src/qpid/ha/Backup.h4
-rw-r--r--cpp/src/qpid/ha/BrokerReplicator.cpp190
-rw-r--r--cpp/src/qpid/ha/BrokerReplicator.h16
-rw-r--r--cpp/src/qpid/ha/HaBroker.cpp95
-rw-r--r--cpp/src/qpid/ha/HaBroker.h8
-rw-r--r--cpp/src/qpid/ha/HaPlugin.cpp28
-rw-r--r--cpp/src/qpid/ha/QueueReplicator.cpp62
-rw-r--r--cpp/src/qpid/ha/QueueReplicator.h5
-rw-r--r--cpp/src/qpid/ha/ReplicateLevel.cpp72
-rw-r--r--cpp/src/qpid/ha/ReplicateLevel.h (renamed from cpp/src/qpid/framing/BodyHandler.h)48
-rw-r--r--cpp/src/qpid/ha/ReplicatingSubscription.cpp71
-rw-r--r--cpp/src/qpid/ha/ReplicatingSubscription.h4
-rw-r--r--cpp/src/qpid/ha/Settings.h7
-rw-r--r--cpp/src/qpid/ha/management-schema.xml35
-rw-r--r--cpp/src/qpid/log/Statement.cpp44
-rw-r--r--cpp/src/qpid/log/posix/SinkOptions.cpp8
-rw-r--r--cpp/src/qpid/management/ManagementAgent.cpp79
-rw-r--r--cpp/src/qpid/management/ManagementAgent.h4
-rw-r--r--cpp/src/qpid/management/ManagementDirectExchange.cpp8
-rw-r--r--cpp/src/qpid/management/ManagementDirectExchange.h4
-rw-r--r--cpp/src/qpid/management/ManagementTopicExchange.cpp8
-rw-r--r--cpp/src/qpid/management/ManagementTopicExchange.h4
-rw-r--r--cpp/src/qpid/replication/ReplicatingEventListener.cpp4
-rw-r--r--cpp/src/qpid/replication/ReplicationExchange.cpp11
-rw-r--r--cpp/src/qpid/replication/ReplicationExchange.h2
-rw-r--r--cpp/src/qpid/store/MessageStorePlugin.cpp6
-rw-r--r--cpp/src/qpid/store/ms-clfs/MessageLog.cpp8
-rw-r--r--cpp/src/qpid/store/ms-clfs/Transaction.h1
-rw-r--r--cpp/src/qpid/store/ms-clfs/TransactionLog.cpp8
-rw-r--r--cpp/src/qpid/sys/MemStat.h (renamed from cpp/src/qpid/sys/apr/APRPool.h)36
-rw-r--r--cpp/src/qpid/sys/Probes.h65
-rw-r--r--cpp/src/qpid/sys/apr/APRBase.cpp89
-rw-r--r--cpp/src/qpid/sys/apr/APRBase.h74
-rw-r--r--cpp/src/qpid/sys/apr/APRPool.cpp41
-rw-r--r--cpp/src/qpid/sys/apr/Condition.h84
-rw-r--r--cpp/src/qpid/sys/apr/Mutex.h124
-rw-r--r--cpp/src/qpid/sys/apr/Shlib.cpp49
-rw-r--r--cpp/src/qpid/sys/apr/Socket.cpp114
-rw-r--r--cpp/src/qpid/sys/apr/Thread.cpp34
-rw-r--r--cpp/src/qpid/sys/apr/Thread.h106
-rw-r--r--cpp/src/qpid/sys/posix/AsynchIO.cpp38
-rw-r--r--cpp/src/qpid/sys/posix/PollableCondition.cpp5
-rw-r--r--cpp/src/qpid/sys/ssl/SslIo.cpp7
-rw-r--r--cpp/src/qpid/sys/windows/AsynchIO.cpp100
-rw-r--r--cpp/src/qpid/sys/windows/PollableCondition.cpp5
-rw-r--r--cpp/src/qpid/sys/windows/Socket.cpp10
-rw-r--r--cpp/src/qpid/sys/windows/SslAsynchIO.cpp8
-rw-r--r--cpp/src/qpid/xml/XmlExchange.cpp4
-rw-r--r--cpp/src/qpid/xml/XmlExchange.h2
152 files changed, 3842 insertions, 2457 deletions
diff --git a/cpp/src/qpid/Options.cpp b/cpp/src/qpid/Options.cpp
index 4b13e349f5..35787aa8f3 100644
--- a/cpp/src/qpid/Options.cpp
+++ b/cpp/src/qpid/Options.cpp
@@ -186,13 +186,14 @@ void Options::parse(int argc, char const* const* argv, const std::string& config
}
}
-CommonOptions::CommonOptions(const string& name, const string& configfile)
- : Options(name), config(configfile)
+CommonOptions::CommonOptions(const string& name, const string& configfile, const string& clientfile)
+ : Options(name), config(configfile), clientConfig(clientfile)
{
addOptions()
("help,h", optValue(help), "Displays the help message")
("version,v", optValue(version), "Displays version information")
- ("config", optValue(config, "FILE"), "Reads configuration from FILE");
+ ("config", optValue(config, "FILE"), "Reads configuration from FILE")
+ ("client-config", optValue(clientConfig, "FILE"), "Reads client configuration from FILE (for cluster interconnect)");
}
diff --git a/cpp/src/qpid/Url.cpp b/cpp/src/qpid/Url.cpp
index 2061499ec3..840f46e928 100644
--- a/cpp/src/qpid/Url.cpp
+++ b/cpp/src/qpid/Url.cpp
@@ -111,7 +111,8 @@ ssl_addr = "ssl:" host [":" port]
*/
class UrlParser {
public:
- UrlParser(Url& u, const char* s) : url(u), text(s), end(s+strlen(s)), i(s) {}
+ UrlParser(Url& u, const char* s, const std::string& defaultProtocol_=Address::TCP) : url(u), text(s), end(s+strlen(s)), i(s),
+ defaultProtocol(defaultProtocol_) {}
bool parse() {
literal("amqp:"); // Optional
userPass(); // Optional
@@ -135,7 +136,7 @@ class UrlParser {
bool comma() { return literal(","); }
bool protocolAddr() {
- Address addr(Address::TCP, "", Address::AMQP_PORT); // Set up defaults
+ Address addr(defaultProtocol, "", Address::AMQP_PORT); // Set up defaults
protocolTag(addr.protocol); // Optional
bool ok = (host(addr.host) &&
(literal(":") ? port(addr.port) : true));
@@ -244,20 +245,28 @@ class UrlParser {
const char* text;
const char* end;
const char* i;
+ const std::string defaultProtocol;
};
const string UrlParser::LOCALHOST("127.0.0.1");
void Url::parse(const char* url) {
- parseNoThrow(url);
+ parse(url, Address::TCP);
+}
+void Url::parse(const char* url, const std::string& defaultProtocol) {
+ parseNoThrow(url, defaultProtocol);
if (empty())
throw Url::Invalid(QPID_MSG("Invalid URL: " << url));
}
void Url::parseNoThrow(const char* url) {
+ parseNoThrow(url, Address::TCP);
+}
+
+void Url::parseNoThrow(const char* url, const std::string& defaultProtocol) {
clear();
cache.clear();
- if (!UrlParser(*this, url).parse())
+ if (!UrlParser(*this, url, defaultProtocol).parse())
clear();
}
diff --git a/cpp/src/qpid/UrlArray.cpp b/cpp/src/qpid/UrlArray.cpp
index 489309c8ad..9ebacbd945 100644
--- a/cpp/src/qpid/UrlArray.cpp
+++ b/cpp/src/qpid/UrlArray.cpp
@@ -20,6 +20,8 @@
*/
#include "UrlArray.h"
+#include <qpid/framing/FieldValue.h>
+
namespace qpid {
std::vector<Url> urlArrayToVector(const framing::Array& array) {
diff --git a/cpp/src/qpid/UrlArray.h b/cpp/src/qpid/UrlArray.h
index 8b11df5c73..ce9e42f248 100644
--- a/cpp/src/qpid/UrlArray.h
+++ b/cpp/src/qpid/UrlArray.h
@@ -23,7 +23,6 @@
*/
#include "qpid/framing/Array.h"
-#include "qpid/framing/FieldValue.h"
#include "qpid/Url.h"
#include <vector>
diff --git a/cpp/src/qpid/acl/Acl.cpp b/cpp/src/qpid/acl/Acl.cpp
index 12bf13018c..917c2e3398 100644
--- a/cpp/src/qpid/acl/Acl.cpp
+++ b/cpp/src/qpid/acl/Acl.cpp
@@ -17,6 +17,7 @@
*/
#include "qpid/acl/Acl.h"
+#include "qpid/acl/AclConnectionCounter.h"
#include "qpid/acl/AclData.h"
#include "qpid/acl/AclValidator.h"
#include "qpid/sys/Mutex.h"
@@ -26,8 +27,11 @@
#include "qpid/Options.h"
#include "qpid/log/Logger.h"
#include "qpid/types/Variant.h"
+#include "qmf/org/apache/qpid/acl/ArgsAclLookup.h"
+#include "qmf/org/apache/qpid/acl/ArgsAclLookupPublish.h"
#include "qmf/org/apache/qpid/acl/Package.h"
#include "qmf/org/apache/qpid/acl/EventAllow.h"
+#include "qmf/org/apache/qpid/acl/EventConnectionDeny.h"
#include "qmf/org/apache/qpid/acl/EventDeny.h"
#include "qmf/org/apache/qpid/acl/EventFileLoaded.h"
#include "qmf/org/apache/qpid/acl/EventFileLoadFailed.h"
@@ -35,7 +39,6 @@
#include <map>
#include <boost/shared_ptr.hpp>
-#include <boost/utility/in_place_factory.hpp>
using namespace std;
using namespace qpid::acl;
@@ -47,7 +50,8 @@ using qpid::management::Manageable;
using qpid::management::Args;
namespace _qmf = qmf::org::apache::qpid::acl;
-Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(false), mgmtObject(0)
+Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(false), mgmtObject(0),
+ connectionCounter(new ConnectionCounter(*this, aclValues.aclMaxConnectPerUser, aclValues.aclMaxConnectPerIp))
{
agent = broker->getManagementAgent();
@@ -62,14 +66,30 @@ Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(fals
throw Exception("Could not read ACL file " + errorString);
if (mgmtObject!=0) mgmtObject->set_enforcingAcl(0);
}
+ broker->getConnectionObservers().add(connectionCounter);
QPID_LOG(info, "ACL Plugin loaded");
if (mgmtObject!=0) mgmtObject->set_enforcingAcl(1);
}
-bool Acl::authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params)
+
+void Acl::reportConnectLimit(const std::string user, const std::string addr)
+{
+ if (mgmtObject!=0)
+ mgmtObject->inc_connectionDenyCount();
+
+ agent->raiseEvent(_qmf::EventConnectionDeny(user, addr));
+}
+
+
+bool Acl::authorise(
+ const std::string& id,
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& name,
+ std::map<Property, std::string>* params)
{
boost::shared_ptr<AclData> dataLocal;
- {
+ {
Mutex::ScopedLock locker(dataLock);
dataLocal = data; //rcu copy
}
@@ -81,7 +101,12 @@ bool Acl::authorise(const std::string& id, const Action& action, const ObjectTyp
return result(aclreslt, id, action, objType, name);
}
-bool Acl::authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName, const std::string& RoutingKey)
+bool Acl::authorise(
+ const std::string& id,
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& ExchangeName,
+ const std::string& RoutingKey)
{
boost::shared_ptr<AclData> dataLocal;
{
@@ -96,31 +121,50 @@ bool Acl::authorise(const std::string& id, const Action& action, const ObjectTyp
}
-bool Acl::result(const AclResult& aclreslt, const std::string& id, const Action& action, const ObjectType& objType, const std::string& name)
+bool Acl::result(
+ const AclResult& aclreslt,
+ const std::string& id,
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& name)
{
+ bool result(false);
+
switch (aclreslt)
{
case ALLOWLOG:
- QPID_LOG(info, "ACL Allow id:" << id <<" action:" << AclHelper::getActionStr(action) <<
- " ObjectType:" << AclHelper::getObjectTypeStr(objType) << " Name:" << name );
+ QPID_LOG(info, "ACL Allow id:" << id
+ << " action:" << AclHelper::getActionStr(action)
+ << " ObjectType:" << AclHelper::getObjectTypeStr(objType)
+ << " Name:" << name );
agent->raiseEvent(_qmf::EventAllow(id, AclHelper::getActionStr(action),
- AclHelper::getObjectTypeStr(objType),
- name, types::Variant::Map()));
+ AclHelper::getObjectTypeStr(objType),
+ name, types::Variant::Map()));
+ // FALLTHROUGH
case ALLOW:
- return true;
- case DENY:
- if (mgmtObject!=0) mgmtObject->inc_aclDenyCount();
- return false;
+ result = true;
+ break;
+
case DENYLOG:
- if (mgmtObject!=0) mgmtObject->inc_aclDenyCount();
- default:
- QPID_LOG(info, "ACL Deny id:" << id << " action:" << AclHelper::getActionStr(action) << " ObjectType:" << AclHelper::getObjectTypeStr(objType) << " Name:" << name);
+ QPID_LOG(info, "ACL Deny id:" << id
+ << " action:" << AclHelper::getActionStr(action)
+ << " ObjectType:" << AclHelper::getObjectTypeStr(objType)
+ << " Name:" << name);
agent->raiseEvent(_qmf::EventDeny(id, AclHelper::getActionStr(action),
- AclHelper::getObjectTypeStr(objType),
- name, types::Variant::Map()));
- return false;
+ AclHelper::getObjectTypeStr(objType),
+ name, types::Variant::Map()));
+ // FALLTHROUGH
+ case DENY:
+ if (mgmtObject!=0)
+ mgmtObject->inc_aclDenyCount();
+ result = false;
+ break;
+
+ default:
+ assert (false);
}
- return false;
+
+ return result;
}
bool Acl::readAclFile(std::string& errorText)
@@ -129,7 +173,7 @@ bool Acl::readAclFile(std::string& errorText)
return readAclFile(aclValues.aclFile, errorText);
}
-bool Acl::readAclFile(std::string& aclFile, std::string& errorText) {
+bool Acl::readAclFile(std::string& aclFile, std::string& errorText) {
boost::shared_ptr<AclData> d(new AclData);
AclReader ar;
if (ar.read(aclFile, d)){
@@ -142,17 +186,17 @@ bool Acl::readAclFile(std::string& aclFile, std::string& errorText) {
AclValidator validator;
validator.validate(d);
- {
+ {
Mutex::ScopedLock locker(dataLock);
data = d;
}
transferAcl = data->transferAcl; // any transfer ACL
if (data->transferAcl){
- QPID_LOG(debug,"Transfer ACL is Enabled!");
+ QPID_LOG(debug,"ACL: Transfer ACL is Enabled!");
}
- data->aclSource = aclFile;
+ data->aclSource = aclFile;
if (mgmtObject!=0){
mgmtObject->set_transferAcl(transferAcl?1:0);
mgmtObject->set_policyFile(aclFile);
@@ -164,17 +208,92 @@ bool Acl::readAclFile(std::string& aclFile, std::string& errorText) {
return true;
}
-Acl::~Acl(){}
+
+//
+// management lookup function performs general query on acl engine
+//
+Manageable::status_t Acl::lookup(qpid::management::Args& args, std::string& text)
+{
+ _qmf::ArgsAclLookup& ioArgs = (_qmf::ArgsAclLookup&) args;
+ Manageable::status_t result(STATUS_USER);
+
+ try {
+ ObjectType objType = AclHelper::getObjectType(ioArgs.i_object);
+ Action action = AclHelper::getAction( ioArgs.i_action);
+ std::map<Property, std::string> propertyMap;
+ for (::qpid::types::Variant::Map::const_iterator
+ iMapIter = ioArgs.i_propertyMap.begin();
+ iMapIter != ioArgs.i_propertyMap.end();
+ iMapIter++)
+ {
+ Property property = AclHelper::getProperty(iMapIter->first);
+ propertyMap.insert(make_pair(property, iMapIter->second));
+ }
+
+ boost::shared_ptr<AclData> dataLocal;
+ {
+ Mutex::ScopedLock locker(dataLock);
+ dataLocal = data; //rcu copy
+ }
+ AclResult aclResult = dataLocal->lookup(
+ ioArgs.i_userId,
+ action,
+ objType,
+ ioArgs.i_objectName,
+ &propertyMap);
+
+ ioArgs.o_result = AclHelper::getAclResultStr(aclResult);
+ result = STATUS_OK;
+
+ } catch (const std::exception& e) {
+ std::ostringstream oss;
+ oss << "AclLookup invalid name : " << e.what();
+ ioArgs.o_result = oss.str();
+ text = oss.str();
+ }
+
+ return result;
+}
+
+
+//
+// management lookupPublish function performs fastpath
+// PUBLISH EXCHANGE query on acl engine
+//
+Manageable::status_t Acl::lookupPublish(qpid::management::Args& args, std::string& /*text*/)
+{
+ _qmf::ArgsAclLookupPublish& ioArgs = (_qmf::ArgsAclLookupPublish&) args;
+ boost::shared_ptr<AclData> dataLocal;
+ {
+ Mutex::ScopedLock locker(dataLock);
+ dataLocal = data; //rcu copy
+ }
+ AclResult aclResult = dataLocal->lookup(
+ ioArgs.i_userId,
+ ACT_PUBLISH,
+ OBJ_EXCHANGE,
+ ioArgs.i_exchangeName,
+ ioArgs.i_routingKey);
+
+ ioArgs.o_result = AclHelper::getAclResultStr(aclResult);
+
+ return STATUS_OK;
+}
+
+
+Acl::~Acl(){
+ broker->getConnectionObservers().remove(connectionCounter);
+}
ManagementObject* Acl::GetManagementObject(void) const
{
return (ManagementObject*) mgmtObject;
}
-Manageable::status_t Acl::ManagementMethod (uint32_t methodId, Args& /*args*/, string& text)
+Manageable::status_t Acl::ManagementMethod (uint32_t methodId, Args& args, string& text)
{
Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD;
- QPID_LOG (debug, "Queue::ManagementMethod [id=" << methodId << "]");
+ QPID_LOG (debug, "ACL: Queue::ManagementMethod [id=" << methodId << "]");
switch (methodId)
{
@@ -185,6 +304,14 @@ Manageable::status_t Acl::ManagementMethod (uint32_t methodId, Args& /*args*/, s
else
status = Manageable::STATUS_USER;
break;
+
+ case _qmf::Acl::METHOD_LOOKUP :
+ status = lookup(args, text);
+ break;
+
+ case _qmf::Acl::METHOD_LOOKUPPUBLISH :
+ status = lookupPublish(args, text);
+ break;
}
return status;
diff --git a/cpp/src/qpid/acl/Acl.h b/cpp/src/qpid/acl/Acl.h
index 77f43838de..c3451018ef 100644
--- a/cpp/src/qpid/acl/Acl.h
+++ b/cpp/src/qpid/acl/Acl.h
@@ -30,6 +30,7 @@
#include "qmf/org/apache/qpid/acl/Acl.h"
#include "qpid/sys/Mutex.h"
+#include <boost/shared_ptr.hpp>
#include <map>
#include <string>
@@ -40,9 +41,12 @@ class Broker;
}
namespace acl {
+class ConnectionCounter;
struct AclValues {
- std::string aclFile;
+ std::string aclFile;
+ uint32_t aclMaxConnectPerUser;
+ uint32_t aclMaxConnectPerIp;
};
@@ -50,37 +54,56 @@ class Acl : public broker::AclModule, public RefCounted, public management::Mana
{
private:
- acl::AclValues aclValues;
- broker::Broker* broker;
- bool transferAcl;
- boost::shared_ptr<AclData> data;
- qmf::org::apache::qpid::acl::Acl* mgmtObject; // mgnt owns lifecycle
- qpid::management::ManagementAgent* agent;
- mutable qpid::sys::Mutex dataLock;
+ acl::AclValues aclValues;
+ broker::Broker* broker;
+ bool transferAcl;
+ boost::shared_ptr<AclData> data;
+ qmf::org::apache::qpid::acl::Acl* mgmtObject; // mgnt owns lifecycle
+ qpid::management::ManagementAgent* agent;
+ mutable qpid::sys::Mutex dataLock;
+ boost::shared_ptr<ConnectionCounter> connectionCounter;
public:
- Acl (AclValues& av, broker::Broker& b);
-
- void initialize();
-
- inline virtual bool doTransferAcl() {return transferAcl;};
-
- // create specilied authorise methods for cases that need faster matching as needed.
- virtual bool authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params=0);
- virtual bool authorise(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName,const std::string& RoutingKey);
-
- virtual ~Acl();
+ Acl (AclValues& av, broker::Broker& b);
+
+ void reportConnectLimit(const std::string user, const std::string addr);
+
+ inline virtual bool doTransferAcl() {
+ return transferAcl;
+ };
+
+// create specilied authorise methods for cases that need faster matching as needed.
+ virtual bool authorise(
+ const std::string& id,
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& name,
+ std::map<Property, std::string>* params=0);
+
+ virtual bool authorise(
+ const std::string& id,
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& ExchangeName,
+ const std::string& RoutingKey);
+
+ virtual ~Acl();
private:
- bool result(const AclResult& aclreslt, const std::string& id, const Action& action, const ObjectType& objType, const std::string& name);
- bool readAclFile(std::string& errorText);
- bool readAclFile(std::string& aclFile, std::string& errorText);
- virtual qpid::management::ManagementObject* GetManagementObject(void) const;
- virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+ bool result(
+ const AclResult& aclreslt,
+ const std::string& id,
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& name);
+ bool readAclFile(std::string& errorText);
+ bool readAclFile(std::string& aclFile, std::string& errorText);
+ Manageable::status_t lookup (management::Args& args, std::string& text);
+ Manageable::status_t lookupPublish(management::Args& args, std::string& text);
+ virtual qpid::management::ManagementObject* GetManagementObject(void) const;
+ virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
};
-
-
}} // namespace qpid::acl
#endif // QPID_ACL_ACL_H
diff --git a/cpp/src/qpid/acl/AclConnectionCounter.cpp b/cpp/src/qpid/acl/AclConnectionCounter.cpp
new file mode 100644
index 0000000000..5d4e3c1544
--- /dev/null
+++ b/cpp/src/qpid/acl/AclConnectionCounter.cpp
@@ -0,0 +1,214 @@
+/*
+ *
+ * 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 "AclConnectionCounter.h"
+#include "Acl.h"
+#include "qpid/broker/Connection.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Mutex.h"
+#include <assert.h>
+#include <sstream>
+
+using namespace qpid::sys;
+
+namespace qpid {
+namespace acl {
+
+//
+// This module instantiates a broker::ConnectionObserver and limits client
+// connections by counting connections per user name and per client IP address.
+//
+
+
+//
+//
+//
+ConnectionCounter::ConnectionCounter(Acl& a, uint32_t nl, uint32_t hl) :
+ acl(a), nameLimit(nl), hostLimit(hl) {}
+
+ConnectionCounter::~ConnectionCounter() {}
+
+
+//
+// limitCheckLH
+//
+// Increment the name's count in map and return a comparison against the limit.
+// called with dataLock already taken
+//
+bool ConnectionCounter::limitCheckLH(
+ connectCountsMap_t& theMap, const std::string& theName, uint32_t theLimit) {
+
+ bool result(true);
+ if (theLimit > 0) {
+ connectCountsMap_t::iterator eRef = theMap.find(theName);
+ if (eRef != theMap.end()) {
+ uint32_t count = (uint32_t)(*eRef).second + 1;
+ (*eRef).second = count;
+ result = count <= theLimit;
+ } else {
+ theMap[theName] = 1;
+ }
+ }
+ return result;
+}
+
+
+//
+// releaseLH
+//
+// Decrement the name's count in map.
+// called with dataLock already taken
+//
+void ConnectionCounter::releaseLH(
+ connectCountsMap_t& theMap, const std::string& theName, uint32_t theLimit) {
+
+ if (theLimit > 0) {
+ connectCountsMap_t::iterator eRef = theMap.find(theName);
+ if (eRef != theMap.end()) {
+ uint32_t count = (uint32_t) (*eRef).second;
+ assert (count > 0);
+ if (1 == count) {
+ theMap.erase (eRef);
+ } else {
+ (*eRef).second = count - 1;
+ }
+ } else {
+ // User had no connections.
+ QPID_LOG(notice, "ACL ConnectionCounter Connection for '" << theName
+ << "' not found in connection count pool");
+ }
+ }
+}
+
+
+//
+// connection - called during Connection's constructor
+//
+void ConnectionCounter::connection(broker::Connection& connection) {
+ QPID_LOG(trace, "ACL ConnectionCounter connection IP:" << connection.getMgmtId()
+ << ", userId:" << connection.getUserId());
+
+ Mutex::ScopedLock locker(dataLock);
+
+ connectProgressMap[connection.getMgmtId()] = C_CREATED;
+}
+
+
+//
+// opened - called when first AMQP frame is received over Connection
+//
+void ConnectionCounter::opened(broker::Connection& connection) {
+ QPID_LOG(trace, "ACL ConnectionCounter Opened IP:" << connection.getMgmtId()
+ << ", userId:" << connection.getUserId());
+
+ Mutex::ScopedLock locker(dataLock);
+
+ const std::string& userName( connection.getUserId());
+ const std::string& hostName(getClientHost(connection.getMgmtId()));
+
+ // Bump state from CREATED to OPENED
+ (void) limitCheckLH(connectProgressMap, connection.getMgmtId(), C_OPENED);
+
+ bool nameOk = limitCheckLH(connectByNameMap, userName, nameLimit);
+ bool hostOk = limitCheckLH(connectByHostMap, hostName, hostLimit);
+
+ if (!nameOk) {
+ // User has too many
+ acl.reportConnectLimit(userName, hostName);
+ QPID_LOG(notice, "ACL ConnectionCounter User '" << userName
+ << "' exceeded maximum allowed connections");
+ throw Exception(
+ QPID_MSG("User '" << userName
+ << "' exceeded maximum allowed connections"));
+ }
+
+ if (!hostOk) {
+ // Host has too many
+ acl.reportConnectLimit(userName, hostName);
+ QPID_LOG(notice, "ACL ConnectionCounter Client host '" << hostName
+ << "' exceeded maximum allowed connections");
+ throw Exception(
+ QPID_MSG("Client host '" << hostName
+ << "' exceeded maximum allowed connections"));
+ }
+}
+
+
+//
+// closed - called during Connection's destructor
+//
+void ConnectionCounter::closed(broker::Connection& connection) {
+ QPID_LOG(trace, "ACL ConnectionCounter Closed IP:" << connection.getMgmtId()
+ << ", userId:" << connection.getUserId());
+
+ Mutex::ScopedLock locker(dataLock);
+
+ connectCountsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
+ if (eRef != connectProgressMap.end()) {
+ if ((*eRef).second == C_OPENED){
+ // Normal case: connection was created and opened.
+ // Decrement in-use counts
+ releaseLH(connectByNameMap,
+ connection.getUserId(),
+ nameLimit);
+
+ releaseLH(connectByHostMap,
+ getClientHost(connection.getMgmtId()),
+ hostLimit);
+ } else {
+ // Connection was created but not opened.
+ // Don't decrement any connection counts.
+ }
+ connectProgressMap.erase(eRef);
+
+ } else {
+ // connection not found in progress map
+ QPID_LOG(notice, "ACL ConnectionCounter info for '" << connection.getMgmtId()
+ << "' not found in connection state pool");
+ }
+}
+
+
+//
+// getClientIp - given a connection's mgmtId return the client host part.
+//
+// TODO: Ideally this would be a method of the connection itself.
+//
+std::string ConnectionCounter::getClientHost(const std::string mgmtId)
+{
+ size_t hyphen = mgmtId.find('-');
+ if (std::string::npos != hyphen) {
+ size_t colon = mgmtId.find_last_of(':');
+ if (std::string::npos != colon) {
+ // trailing colon found
+ return mgmtId.substr(hyphen+1, colon - hyphen - 1);
+ } else {
+ // colon not found - use everything after hyphen
+ return mgmtId.substr(hyphen+1);
+ }
+ }
+
+ // no hyphen found - use whole string
+ assert(false);
+ return mgmtId;
+}
+
+}} // namespace qpid::ha
diff --git a/cpp/src/qpid/acl/AclConnectionCounter.h b/cpp/src/qpid/acl/AclConnectionCounter.h
new file mode 100644
index 0000000000..31d11540fd
--- /dev/null
+++ b/cpp/src/qpid/acl/AclConnectionCounter.h
@@ -0,0 +1,81 @@
+#ifndef QPID_ACL_CONNECTIONCOUNTER_H
+#define QPID_ACL_CONNECTIONCOUNTER_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/ConnectionObserver.h"
+#include "qpid/sys/Mutex.h"
+#include <boost/iterator/iterator_concepts.hpp>
+
+#include <map>
+
+namespace qpid {
+
+namespace broker {
+class Connection;
+}
+
+namespace acl {
+class Acl;
+
+ /**
+ * Terminate client connections when a user tries to create 'too many'.
+ * Terminate hostIp connections when an IP host tries to create 'too many'.
+ */
+class ConnectionCounter : public broker::ConnectionObserver
+{
+private:
+ typedef std::map<std::string, uint32_t> connectCountsMap_t;
+ enum CONNECTION_PROGRESS { C_CREATED=1, C_OPENED=2 };
+
+ Acl& acl;
+ uint32_t nameLimit;
+ uint32_t hostLimit;
+ qpid::sys::Mutex dataLock;
+
+ connectCountsMap_t connectProgressMap;
+ connectCountsMap_t connectByNameMap;
+ connectCountsMap_t connectByHostMap;
+
+ std::string getClientHost(const std::string mgmtId);
+
+ bool limitCheckLH(connectCountsMap_t& theMap,
+ const std::string& theName,
+ uint32_t theLimit);
+
+ void releaseLH(connectCountsMap_t& theMap,
+ const std::string& theName,
+ uint32_t theLimit);
+
+public:
+ ConnectionCounter(Acl& acl, uint32_t nl, uint32_t hl);
+ ~ConnectionCounter();
+
+ void connection(broker::Connection& connection);
+ void opened(broker::Connection& connection);
+ void closed(broker::Connection& connection);
+
+};
+
+}} // namespace qpid::ha
+
+#endif /*!QPID_ACL_CONNECTIONCOUNTER_H*/
diff --git a/cpp/src/qpid/acl/AclData.cpp b/cpp/src/qpid/acl/AclData.cpp
index 06fc223a73..da7f240a9b 100644
--- a/cpp/src/qpid/acl/AclData.cpp
+++ b/cpp/src/qpid/acl/AclData.cpp
@@ -24,152 +24,302 @@
namespace qpid {
namespace acl {
- AclData::AclData():decisionMode(qpid::acl::DENY),transferAcl(false),aclSource("UNKNOWN")
+ //
+ // constructor
+ //
+ AclData::AclData():
+ decisionMode(qpid::acl::DENY),
+ transferAcl(false),
+ aclSource("UNKNOWN")
{
- for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++){
+ for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++)
+ {
actionList[cnt]=0;
}
-
}
+
+ //
+ // clear
+ //
void AclData::clear ()
{
- for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++){
- if (actionList[cnt]){
+ for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++)
+ {
+ if (actionList[cnt])
+ {
for (unsigned int cnt1=0; cnt1< qpid::acl::OBJECTSIZE; cnt1++)
- delete actionList[cnt][cnt1];
+ delete actionList[cnt][cnt1];
}
delete[] actionList[cnt];
}
-
}
- bool AclData::matchProp(const std::string & src, const std::string& src1)
+
+ //
+ // matchProp
+ //
+ // Compare a rule's property name with a lookup name,
+ // The rule's name may contain a trailing '*' to specify a wildcard match.
+ //
+ bool AclData::matchProp(const std::string& ruleStr,
+ const std::string& lookupStr)
{
- // allow wildcard on the end of strings...
- if (src.data()[src.size()-1]=='*') {
- return (src.compare(0, src.size()-1, src1, 0,src.size()-1 ) == 0);
- } else {
- return (src.compare(src1)==0) ;
+ // allow wildcard on the end of rule strings...
+ if (ruleStr.data()[ruleStr.size()-1]=='*')
+ {
+ return ruleStr.compare(0,
+ ruleStr.size()-1,
+ lookupStr,
+ 0,
+ ruleStr.size()-1 ) == 0;
+ }
+ else
+ {
+ return ruleStr.compare(lookupStr) == 0;
}
}
- AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType,
- const std::string& name, std::map<Property, std::string>* params) {
-
- QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action)
- << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " name:" << name
- << " with params " << AclHelper::propertyMapToString(params));
-
- AclResult aclresult = decisionMode;
- if (actionList[action] && actionList[action][objType]) {
- AclData::actObjItr itrRule = actionList[action][objType]->find(id);
- if (itrRule == actionList[action][objType]->end())
- itrRule = actionList[action][objType]->find("*");
-
- if (itrRule != actionList[action][objType]->end()) {
-
- QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first );
-
- //loop the vector
- for (ruleSetItr i = itrRule->second.begin(); i < itrRule->second.end(); i++) {
- QPID_LOG(debug, "ACL: checking rule " << i->toString());
- // loop the names looking for match
- bool match = true;
- for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++) {
- //match name is exists first
- if (pMItr->first == acl::PROP_NAME) {
- if (matchProp(pMItr->second, name)){
- QPID_LOG(debug, "ACL: name '" << name << "' matched with name '"
- << pMItr->second << "' given in the rule");
- }else{
+
+ //
+ // lookup
+ //
+ // The ACL main business logic function of matching rules and declaring
+ // an allow or deny result.
+ //
+ AclResult AclData::lookup(
+ const std::string& id,
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& name,
+ std::map<Property, std::string>* params)
+ {
+ QPID_LOG(debug, "ACL: Lookup for id:" << id
+ << " action:" << AclHelper::getActionStr((Action) action)
+ << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType)
+ << " name:" << name
+ << " with params " << AclHelper::propertyMapToString(params));
+
+ // A typical log looks like:
+ // ACL: Lookup for id:bob@QPID action:create objectType:queue name:q2
+ // with params { durable=false passive=false autodelete=false
+ // exclusive=false alternate= policytype= maxqueuesize=0
+ // maxqueuecount=0 }
+
+ // Default result is blanket decision mode for the entire ACL list.
+ AclResult aclresult = decisionMode;
+
+ // Test for lists of rules at the intersection of the Action & Object
+ if (actionList[action] && actionList[action][objType])
+ {
+ // Find the list of rules for this actorId
+ AclData::actObjItr itrRule = actionList[action][objType]->find(id);
+
+ // If individual actorId not found then find a rule set for '*'.
+ if (itrRule == actionList[action][objType]->end())
+ itrRule = actionList[action][objType]->find("*");
+
+ if (itrRule != actionList[action][objType]->end())
+ {
+ // A list of rules exists for this actor/action/object tuple.
+ // Iterate the rule set to search for a matching rule.
+ ruleSetItr rsItr = itrRule->second.end();
+ for (int cnt = itrRule->second.size(); cnt != 0; cnt--)
+ {
+ rsItr--;
+
+ QPID_LOG(debug, "ACL: checking rule " << rsItr->toString());
+
+ bool match = true;
+ bool limitChecked = true;
+
+ // Iterate this rule's properties. A 'match' is true when
+ // all of the rule's properties are found to be satisfied
+ // in the lookup param list. The lookup may specify things
+ // (they usually do) that are not in the rule properties but
+ // these things don't interfere with the rule match.
+
+ for (specPropertyMapItr rulePropMapItr = rsItr->props.begin();
+ (rulePropMapItr != rsItr->props.end()) && match;
+ rulePropMapItr++)
+ {
+ // The rule property map's NAME property is given in
+ // the calling args and not in the param map.
+ if (rulePropMapItr->first == acl::SPECPROP_NAME)
+ {
+ if (matchProp(rulePropMapItr->second, name))
+ {
+ QPID_LOG(debug, "ACL: lookup name '" << name
+ << "' matched with rule name '"
+ << rulePropMapItr->second << "'");
+ }
+ else
+ {
+ match = false;
+ QPID_LOG(debug, "ACL: lookup name '" << name
+ << "' didn't match with rule name '"
+ << rulePropMapItr->second << "'");
+ }
+ }
+ else
+ {
+ if (params)
+ {
+ // The rule's property map non-NAME properties
+ // found in the lookup's params list.
+ // In some cases the param's index is not the same
+ // as rule's index.
+ propertyMapItr lookupParamItr;
+ switch (rulePropMapItr->first)
+ {
+ case acl::SPECPROP_MAXQUEUECOUNTUPPERLIMIT:
+ case acl::SPECPROP_MAXQUEUECOUNTLOWERLIMIT:
+ lookupParamItr = params->find(PROP_MAXQUEUECOUNT);
+ break;
+
+ case acl::SPECPROP_MAXQUEUESIZEUPPERLIMIT:
+ case acl::SPECPROP_MAXQUEUESIZELOWERLIMIT:
+ lookupParamItr = params->find(PROP_MAXQUEUESIZE);
+ break;
+
+ default:
+ lookupParamItr = params->find((Property)rulePropMapItr->first);
+ break;
+ };
+
+ if (lookupParamItr == params->end())
+ {
+ // Now the rule has a specified property
+ // that does not exist in the caller's
+ // lookup params list.
+ // This rule does not match.
match = false;
- QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '"
- << pMItr->second << "' given in the rule");
+ QPID_LOG(debug, "ACL: lookup parameter map doesn't contain the rule property '"
+ << AclHelper::getPropertyStr(rulePropMapItr->first) << "'");
}
- } else if (params) { //match pMItr against params
- propertyMapItr paramItr = params->find(pMItr->first);
- if (paramItr == params->end()) {
- match = false;
- QPID_LOG(debug, "ACL: the given parameter map in lookup doesn't contain the property '"
- << AclHelper::getPropertyStr(pMItr->first) << "'");
- }else if ( pMItr->first == acl::PROP_MAXQUEUECOUNT || pMItr->first == acl::PROP_MAXQUEUESIZE ) {
- if ( pMItr->first == paramItr->first ) {
-
- uint64_t aclMax = 0;
- uint64_t paramMax = 0;
-
- try{
- aclMax = boost::lexical_cast<uint64_t>(pMItr->second);
- }catch(const boost::bad_lexical_cast&){
- match = false;
- QPID_LOG(error,"Error evaluating rule. " <<
- "Illegal value given in ACL source <" << aclSource <<
- "> for property '" <<
- AclHelper::getPropertyStr(pMItr->first) << "' : " <<
- boost::lexical_cast<std::string>(pMItr->second));
- break;
- }
-
- try{
- paramMax = boost::lexical_cast<uint64_t>(paramItr->second);
- }catch(const boost::bad_lexical_cast&){
+ else
+ {
+ // Now account for the business of rules
+ // whose property indexes are mismatched.
+ switch (rulePropMapItr->first)
+ {
+ case acl::SPECPROP_MAXQUEUECOUNTUPPERLIMIT:
+ case acl::SPECPROP_MAXQUEUESIZEUPPERLIMIT:
+ limitChecked &=
+ compareIntMax(
+ rulePropMapItr->first,
+ boost::lexical_cast<std::string>(rulePropMapItr->second),
+ boost::lexical_cast<std::string>(lookupParamItr->second));
+ break;
+
+ case acl::SPECPROP_MAXQUEUECOUNTLOWERLIMIT:
+ case acl::SPECPROP_MAXQUEUESIZELOWERLIMIT:
+ limitChecked &=
+ compareIntMin(
+ rulePropMapItr->first,
+ boost::lexical_cast<std::string>(rulePropMapItr->second),
+ boost::lexical_cast<std::string>(lookupParamItr->second));
+ break;
+
+ default:
+ if (matchProp(rulePropMapItr->second, lookupParamItr->second))
+ {
+ QPID_LOG(debug, "ACL: the pair("
+ << AclHelper::getPropertyStr(lookupParamItr->first)
+ << "," << lookupParamItr->second
+ << ") given in lookup matched the pair("
+ << AclHelper::getPropertyStr(rulePropMapItr->first) << ","
+ << rulePropMapItr->second
+ << ") given in the rule");
+ }
+ else
+ {
match = false;
- QPID_LOG(error,"Error evaluating rule. " <<
- "Illegal value given in lookup for property '" <<
- AclHelper::getPropertyStr(pMItr->first) << "' : " <<
- boost::lexical_cast<std::string>(paramItr->second));
- break;
- }
-
- QPID_LOG(debug, "ACL: Numeric comparison for property " <<
- AclHelper::getPropertyStr(paramItr->first) <<
- " (value given in lookup = " <<
- boost::lexical_cast<std::string>(paramItr->second) <<
- ", value give in rule = " <<
- boost::lexical_cast<std::string>(pMItr->second) << " )");
-
- if (( aclMax ) && ( paramMax == 0 || paramMax > aclMax)){
- match = decisionMode == qpid::acl::ALLOW ;
- QPID_LOG(debug, "ACL: Limit exceeded and match=" <<
- (match ? "true": "false") <<
- " as decision mode is " << AclHelper::getAclResultStr(decisionMode));
+ QPID_LOG(debug, "ACL: the pair("
+ << AclHelper::getPropertyStr(lookupParamItr->first)
+ << "," << lookupParamItr->second
+ << ") given in lookup doesn't match the pair("
+ << AclHelper::getPropertyStr(rulePropMapItr->first)
+ << "," << rulePropMapItr->second
+ << ") given in the rule");
}
- }
- }else if (matchProp(pMItr->second, paramItr->second)) {
- QPID_LOG(debug, "ACL: the pair("
- << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second
- << ") given in lookup matched the pair("
- << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule");
- } else {
- QPID_LOG(debug, "ACL: the pair("
- << AclHelper::getPropertyStr(paramItr->first) << "," << paramItr->second
- << ") given in lookup doesn't match the pair("
- << AclHelper::getPropertyStr(pMItr->first) << "," << pMItr->second << ") given in the rule");
- match = false;
- }
+ break;
+ };
+ }
+ }
+ else
+ {
+ // params don't exist.
}
}
- if (match)
+ }
+ if (match)
+ {
+ aclresult = rsItr->ruleMode;
+ if (!limitChecked)
{
- aclresult = getACLResult(i->logOnly, i->log);
- QPID_LOG(debug,"Successful match, the decision is:" << AclHelper::getAclResultStr(aclresult));
- return aclresult;
+ // Now a lookup matched all rule properties but one
+ // of the numeric limit checks has failed.
+ // Demote allow rules to corresponding deny rules.
+ switch (aclresult)
+ {
+ case acl::ALLOW:
+ aclresult = acl::DENY;
+ break;
+ case acl::ALLOWLOG:
+ aclresult = acl::DENYLOG;
+ break;
+ default:
+ break;
+ };
}
+ QPID_LOG(debug,"ACL: Successful match, the decision is:"
+ << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
+ }
+ else
+ {
+ // This rule did not match the requested lookup and
+ // does not contribute to an ACL decision.
}
}
}
+ else
+ {
+ // The Action-Object list has entries but not for this actorId
+ // nor for *.
+ }
+ }
+ else
+ {
+ // The Action-Object list has no entries.
+ }
- QPID_LOG(debug,"No successful match, defaulting to the decision mode " << AclHelper::getAclResultStr(aclresult));
- return aclresult;
+ QPID_LOG(debug,"ACL: No successful match, defaulting to the decision mode "
+ << AclHelper::getAclResultStr(aclresult));
+ return aclresult;
}
- AclResult AclData::lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& /*Exchange*/ name, const std::string& RoutingKey)
+
+ //
+ // lookup
+ //
+ // The ACL main business logic function of matching rules and declaring
+ // an allow or deny result.
+ //
+ AclResult AclData::lookup(
+ const std::string& id,
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& /*Exchange*/ name,
+ const std::string& routingKey)
{
- QPID_LOG(debug, "ACL: Lookup for id:" << id << " action:" << AclHelper::getActionStr((Action) action)
- << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) << " exchange name:" << name
- << " with routing key " << RoutingKey);
+ QPID_LOG(debug, "ACL: Lookup for id:" << id
+ << " action:" << AclHelper::getActionStr((Action) action)
+ << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType)
+ << " exchange name:" << name
+ << " with routing key " << routingKey);
AclResult aclresult = decisionMode;
@@ -179,83 +329,183 @@ namespace acl {
if (itrRule == actionList[action][objType]->end())
itrRule = actionList[action][objType]->find("*");
- if (itrRule != actionList[action][objType]->end() ) {
-
- QPID_LOG(debug, "ACL: checking the following rules for : " << itrRule->first );
-
+ if (itrRule != actionList[action][objType]->end() )
+ {
//loop the vector
- for (ruleSetItr i=itrRule->second.begin(); i<itrRule->second.end(); i++) {
- QPID_LOG(debug, "ACL: checking rule " << i->toString());
+ ruleSetItr rsItr = itrRule->second.end();
+ for (int cnt = itrRule->second.size(); cnt != 0; cnt--)
+ {
+ rsItr--;
+
+ QPID_LOG(debug, "ACL: checking rule " << rsItr->toString());
// loop the names looking for match
bool match =true;
- for (propertyMapItr pMItr = i->props.begin(); (pMItr != i->props.end()) && match; pMItr++)
+ for (specPropertyMapItr pMItr = rsItr->props.begin();
+ (pMItr != rsItr->props.end()) && match;
+ pMItr++)
{
//match name is exists first
- if (pMItr->first == acl::PROP_NAME){
- if (matchProp(pMItr->second, name)){
- QPID_LOG(debug, "ACL: name '" << name << "' matched with name '"
- << pMItr->second << "' given in the rule");
+ switch (pMItr->first)
+ {
+ case acl::SPECPROP_NAME:
+ if (matchProp(pMItr->second, name))
+ {
+ QPID_LOG(debug, "ACL: lookup exchange name '"
+ << name << "' matched with rule name '"
+ << pMItr->second << "'");
- }else{
+ }
+ else
+ {
match= false;
- QPID_LOG(debug, "ACL: name '" << name << "' didn't match with name '"
- << pMItr->second << "' given in the rule");
- }
- }else if (pMItr->first == acl::PROP_ROUTINGKEY){
- if (matchProp(pMItr->second, RoutingKey)){
- QPID_LOG(debug, "ACL: name '" << name << "' matched with routing_key '"
- << pMItr->second << "' given in the rule");
- }else{
+ QPID_LOG(debug, "ACL: lookup exchange name '"
+ << name << "' did not match with rule name '"
+ << pMItr->second << "'");
+ }
+ break;
+
+ case acl::SPECPROP_ROUTINGKEY:
+ if (matchProp(pMItr->second, routingKey))
+ {
+ QPID_LOG(debug, "ACL: lookup key name '"
+ << routingKey << "' matched with rule routing key '"
+ << pMItr->second << "'");
+ }
+ else
+ {
match= false;
- QPID_LOG(debug, "ACL: name '" << name << "' didn't match with routing_key '"
- << pMItr->second << "' given in the rule");
- }
- }
+ QPID_LOG(debug, "ACL: lookup key name '"
+ << routingKey << "' did not match with rule routing key '"
+ << pMItr->second << "'");
+ }
+ break;
+
+ default:
+ // Don't care
+ break;
+ };
}
if (match){
- aclresult = getACLResult(i->logOnly, i->log);
- QPID_LOG(debug,"Successful match, the decision is:" << AclHelper::getAclResultStr(aclresult));
+ aclresult = rsItr->ruleMode;
+ QPID_LOG(debug,"ACL: Successful match, the decision is:"
+ << AclHelper::getAclResultStr(aclresult));
return aclresult;
}
}
}
}
- QPID_LOG(debug,"No successful match, defaulting to the decision mode " << AclHelper::getAclResultStr(aclresult));
+ QPID_LOG(debug,"ACL: No successful match, defaulting to the decision mode "
+ << AclHelper::getAclResultStr(aclresult));
return aclresult;
}
- AclResult AclData::getACLResult(bool logOnly, bool log)
+ //
+ //
+ //
+ AclData::~AclData()
+ {
+ clear();
+ }
+
+
+ //
+ // Limit check a MAX int limit
+ //
+ bool AclData::compareIntMax(const qpid::acl::SpecProperty theProperty,
+ const std::string theAclValue,
+ const std::string theLookupValue)
{
- switch (decisionMode)
+ uint64_t aclMax (0);
+ uint64_t paramMax (0);
+
+ try
{
- case qpid::acl::ALLOWLOG:
- case qpid::acl::ALLOW:
- if (logOnly) return qpid::acl::ALLOWLOG;
- if (log)
- return qpid::acl::DENYLOG;
- else
- return qpid::acl::DENY;
+ aclMax = boost::lexical_cast<uint64_t>(theAclValue);
+ }
+ catch(const boost::bad_lexical_cast&)
+ {
+ assert (false);
+ return false;
+ }
+
+ try
+ {
+ paramMax = boost::lexical_cast<uint64_t>(theLookupValue);
+ }
+ catch(const boost::bad_lexical_cast&)
+ {
+ QPID_LOG(error,"ACL: Error evaluating rule. "
+ << "Illegal value given in lookup for property '"
+ << AclHelper::getPropertyStr(theProperty)
+ << "' : " << theLookupValue);
+ return false;
+ }
+ QPID_LOG(debug, "ACL: Numeric greater-than comparison for property "
+ << AclHelper::getPropertyStr(theProperty)
+ << " (value given in lookup = " << theLookupValue
+ << ", value give in rule = " << theAclValue << " )");
- case qpid::acl::DENYLOG:
- case qpid::acl::DENY:
- if (logOnly) return qpid::acl::DENYLOG;
- if (log)
- return qpid::acl::ALLOWLOG;
- else
- return qpid::acl::ALLOW;
+ if (( aclMax ) && ( paramMax == 0 || paramMax > aclMax))
+ {
+ QPID_LOG(debug, "ACL: Max limit exceeded for property '"
+ << AclHelper::getPropertyStr(theProperty) << "'");
+ return false;
}
- QPID_LOG(error, "ACL Decision Failed, setting DENY");
- return qpid::acl::DENY;
+ return true;
}
- AclData::~AclData()
+
+ //
+ // limit check a MIN int limit
+ //
+ bool AclData::compareIntMin(const qpid::acl::SpecProperty theProperty,
+ const std::string theAclValue,
+ const std::string theLookupValue)
{
- clear();
+ uint64_t aclMin (0);
+ uint64_t paramMin (0);
+
+ try
+ {
+ aclMin = boost::lexical_cast<uint64_t>(theAclValue);
+ }
+ catch(const boost::bad_lexical_cast&)
+ {
+ assert (false);
+ return false;
+ }
+
+ try
+ {
+ paramMin = boost::lexical_cast<uint64_t>(theLookupValue);
+ }
+ catch(const boost::bad_lexical_cast&)
+ {
+ QPID_LOG(error,"ACL: Error evaluating rule. "
+ << "Illegal value given in lookup for property '"
+ << AclHelper::getPropertyStr(theProperty)
+ << "' : " << theLookupValue);
+ return false;
+ }
+
+ QPID_LOG(debug, "ACL: Numeric less-than comparison for property "
+ << AclHelper::getPropertyStr(theProperty)
+ << " (value given in lookup = " << theLookupValue
+ << ", value give in rule = " << theAclValue << " )");
+
+ if (( aclMin ) && ( paramMin == 0 || paramMin < aclMin))
+ {
+ QPID_LOG(debug, "ACL: Min limit exceeded for property '"
+ << AclHelper::getPropertyStr(theProperty) << "'");
+ return false;
+ }
+
+ return true;
}
-}}
+}}
diff --git a/cpp/src/qpid/acl/AclData.h b/cpp/src/qpid/acl/AclData.h
index 81125fdcbc..1c1cb3e9c6 100644
--- a/cpp/src/qpid/acl/AclData.h
+++ b/cpp/src/qpid/acl/AclData.h
@@ -33,50 +33,91 @@ class AclData {
public:
typedef std::map<qpid::acl::Property, std::string> propertyMap;
- typedef propertyMap::const_iterator propertyMapItr;
+ typedef propertyMap::const_iterator propertyMapItr;
+
+ typedef std::map<qpid::acl::SpecProperty, std::string> specPropertyMap;
+ typedef specPropertyMap::const_iterator specPropertyMapItr;
+
+ //
+ // rule
+ //
+ // Created by AclReader and stored in a ruleSet vector for subsequent
+ // run-time lookup matching and allow/deny decisions.
+ // RuleSet vectors are indexed by Action-Object-actorId so these
+ // attributes are not part of a rule.
+ // A single ACL file entry may create many rule entries in
+ // many ruleset vectors.
+ //
struct rule {
- bool log;
- bool logOnly; // this is a rule is to log only
+ int rawRuleNum; // rule number in ACL file
+ qpid::acl::AclResult ruleMode; // combined allow/deny log/nolog
+ specPropertyMap props; //
- // key value map
- //??
- propertyMap props;
-
- rule (propertyMap& p):log(false),logOnly(false),props(p) {};
+ rule (int ruleNum, qpid::acl::AclResult res, specPropertyMap& p) :
+ rawRuleNum(ruleNum),
+ ruleMode(res),
+ props(p)
+ {};
std::string toString () const {
std::ostringstream ruleStr;
- ruleStr << "[log=" << log << ", logOnly=" << logOnly << " props{";
- for (propertyMapItr pMItr = props.begin(); pMItr != props.end(); pMItr++) {
- ruleStr << " " << AclHelper::getPropertyStr((Property) pMItr-> first) << "=" << pMItr->second;
+ ruleStr << "[rule " << rawRuleNum
+ << " ruleMode = " << AclHelper::getAclResultStr(ruleMode)
+ << " props{";
+ for (specPropertyMapItr pMItr = props.begin();
+ pMItr != props.end();
+ pMItr++) {
+ ruleStr << " "
+ << AclHelper::getPropertyStr((SpecProperty) pMItr-> first)
+ << "=" << pMItr->second;
}
ruleStr << " }]";
return ruleStr.str();
}
};
- typedef std::vector<rule> ruleSet;
- typedef ruleSet::const_iterator ruleSetItr;
- typedef std::map<std::string, ruleSet > actionObject; // user
- typedef actionObject::iterator actObjItr;
- typedef actionObject* aclAction;
- // Action*[] -> Object*[] -> map<user -> set<Rule> >
- aclAction* actionList[qpid::acl::ACTIONSIZE];
- qpid::acl::AclResult decisionMode; // determines if the rule set is a deny or allow mode.
- bool transferAcl;
- std::string aclSource;
+ typedef std::vector<rule> ruleSet;
+ typedef ruleSet::const_iterator ruleSetItr;
+ typedef std::map<std::string, ruleSet > actionObject; // user
+ typedef actionObject::iterator actObjItr;
+ typedef actionObject* aclAction;
- AclResult lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& name, std::map<Property, std::string>* params=0);
- AclResult lookup(const std::string& id, const Action& action, const ObjectType& objType, const std::string& ExchangeName, const std::string& RoutingKey);
- AclResult getACLResult(bool logOnly, bool log);
+ // Action*[] -> Object*[] -> map<user -> set<Rule> >
+ aclAction* actionList[qpid::acl::ACTIONSIZE];
+ qpid::acl::AclResult decisionMode; // allow/deny[-log] if no matching rule found
+ bool transferAcl;
+ std::string aclSource;
+
+ AclResult lookup(
+ const std::string& id, // actor id
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& name, // object name
+ std::map<Property, std::string>* params=0);
+
+ AclResult lookup(
+ const std::string& id, // actor id
+ const Action& action,
+ const ObjectType& objType,
+ const std::string& ExchangeName,
+ const std::string& RoutingKey);
bool matchProp(const std::string & src, const std::string& src1);
void clear ();
AclData();
virtual ~AclData();
+
+private:
+ bool compareIntMax(const qpid::acl::SpecProperty theProperty,
+ const std::string theAclValue,
+ const std::string theLookupValue);
+
+ bool compareIntMin(const qpid::acl::SpecProperty theProperty,
+ const std::string theAclValue,
+ const std::string theLookupValue);
};
}} // namespace qpid::acl
diff --git a/cpp/src/qpid/acl/AclPlugin.cpp b/cpp/src/qpid/acl/AclPlugin.cpp
index d611797c49..6c18cd2749 100644
--- a/cpp/src/qpid/acl/AclPlugin.cpp
+++ b/cpp/src/qpid/acl/AclPlugin.cpp
@@ -40,7 +40,9 @@ struct AclOptions : public Options {
AclOptions(AclValues& v) : Options("ACL Options"), values(v) {
addOptions()
- ("acl-file", optValue(values.aclFile, "FILE"), "The policy file to load from, loaded from data dir");
+ ("acl-file", optValue(values.aclFile, "FILE"), "The policy file to load from, loaded from data dir")
+ ("acl-max-connect-per-user", optValue(values.aclMaxConnectPerUser, "N"), "The maximum number of connections allowed per user")
+ ("acl-max-connect-per-ip" , optValue(values.aclMaxConnectPerIp, "N"), "The maximum number of connections allowed per host IP address");
}
};
diff --git a/cpp/src/qpid/acl/AclReader.cpp b/cpp/src/qpid/acl/AclReader.cpp
index 74358a20c1..80debf1bd1 100644
--- a/cpp/src/qpid/acl/AclReader.cpp
+++ b/cpp/src/qpid/acl/AclReader.cpp
@@ -49,7 +49,7 @@ namespace acl {
objStatus = ALL;
}
- bool AclReader::aclRule::addProperty(const Property p, const std::string v) {
+ bool AclReader::aclRule::addProperty(const SpecProperty p, const std::string v) {
return props.insert(propNvPair(p, v)).second;
}
@@ -85,146 +85,108 @@ namespace acl {
void AclReader::loadDecisionData(boost::shared_ptr<AclData> d) {
d->clear();
- QPID_LOG(debug, "ACL Load Rules");
- int cnt = rules.size();
+ QPID_LOG(debug, "ACL: Load Rules");
bool foundmode = false;
- for (rlCitr i = rules.end(); cnt; cnt--) {
+ rlCitr i = rules.end();
+ for (int cnt = rules.size(); cnt; cnt--) {
i--;
- QPID_LOG(debug, "ACL Processing " << std::setfill(' ') << std::setw(2)
+ QPID_LOG(debug, "ACL: Processing " << std::setfill(' ') << std::setw(2)
<< cnt << " " << (*i)->toString());
if (!foundmode && (*i)->actionAll && (*i)->names.size() == 1
&& (*((*i)->names.begin())).compare("*") == 0) {
d->decisionMode = (*i)->res;
- QPID_LOG(debug, "ACL FoundMode "
+ QPID_LOG(debug, "ACL: FoundMode "
<< AclHelper::getAclResultStr(d->decisionMode));
foundmode = true;
} else {
- AclData::rule rule((*i)->props);
- bool addrule = true;
-
- switch ((*i)->res) {
- case qpid::acl::ALLOWLOG:
- rule.log = true;
- if (d->decisionMode == qpid::acl::ALLOW ||
- d->decisionMode == qpid::acl::ALLOWLOG)
- rule.logOnly = true;
- break;
- case qpid::acl::ALLOW:
- if (d->decisionMode == qpid::acl::ALLOW ||
- d->decisionMode == qpid::acl::ALLOWLOG)
- addrule = false;
- break;
- case qpid::acl::DENYLOG:
- rule.log = true;
- if (d->decisionMode == qpid::acl::DENY ||
- d->decisionMode == qpid::acl::DENYLOG)
- rule.logOnly = true;
- break;
- case qpid::acl::DENY:
- if (d->decisionMode == qpid::acl::DENY ||
- d->decisionMode == qpid::acl::DENYLOG)
- addrule = false;
- break;
- default:
- throw Exception("Invalid ACL Result loading rules.");
- }
+ AclData::rule rule(cnt, (*i)->res, (*i)->props);
// Action -> Object -> map<user -> set<Rule> >
- if (addrule) {
- std::ostringstream actionstr;
- for (int acnt = ((*i)->actionAll ? 0 : (*i)->action);
- acnt < acl::ACTIONSIZE;
- (*i)->actionAll ? acnt++ : acnt = acl::ACTIONSIZE) {
-
- if (acnt == acl::ACT_PUBLISH)
- d->transferAcl = true; // we have transfer ACL
-
- actionstr << AclHelper::getActionStr((Action) acnt) << ",";
-
- //find the Action, create if not exist
- if (d->actionList[acnt] == NULL) {
- d->actionList[acnt] =
- new AclData::aclAction[qpid::acl::OBJECTSIZE];
- for (int j = 0; j < qpid::acl::OBJECTSIZE; j++)
- d->actionList[acnt][j] = NULL;
- }
-
- // optimize this loop to limit to valid options only!!
- for (int ocnt = ((*i)->objStatus != aclRule::VALUE ? 0
- : (*i)->object);
- ocnt < acl::OBJECTSIZE;
- (*i)->objStatus != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) {
-
- //find the Object, create if not exist
- if (d->actionList[acnt][ocnt] == NULL)
- d->actionList[acnt][ocnt] =
- new AclData::actionObject;
-
- // add users and Rule to object set
- bool allNames = false;
- // check to see if names.begin is '*'
- if ((*(*i)->names.begin()).compare("*") == 0)
- allNames = true;
-
- for (nsCitr itr = (allNames ? names.begin()
- : (*i)->names.begin());
- itr != (allNames ? names.end() : (*i)->names.end());
- itr++) {
-
- AclData::actObjItr itrRule =
- d->actionList[acnt][ocnt]->find(*itr);
-
- if (itrRule == d->actionList[acnt][ocnt]->end()) {
- AclData::ruleSet rSet;
- rSet.push_back(rule);
- d->actionList[acnt][ocnt]->insert
- (make_pair(std::string(*itr), rSet));
- } else {
- // TODO add code to check for dead rules
- // allow peter create queue name=tmp <-- dead rule!!
- // allow peter create queue
-
- itrRule->second.push_back(rule);
- }
- }
-
- }
+ std::ostringstream actionstr;
+ for (int acnt = ((*i)->actionAll ? 0 : (*i)->action);
+ acnt < acl::ACTIONSIZE;
+ (*i)->actionAll ? acnt++ : acnt = acl::ACTIONSIZE) {
+
+ if (acnt == acl::ACT_PUBLISH)
+ d->transferAcl = true; // we have transfer ACL
+
+ actionstr << AclHelper::getActionStr((Action) acnt) << ",";
+
+ //find the Action, create if not exist
+ if (d->actionList[acnt] == NULL) {
+ d->actionList[acnt] =
+ new AclData::aclAction[qpid::acl::OBJECTSIZE];
+ for (int j = 0; j < qpid::acl::OBJECTSIZE; j++)
+ d->actionList[acnt][j] = NULL;
}
- std::ostringstream objstr;
- for (int ocnt = ((*i)->objStatus != aclRule::VALUE ? 0 : (*i)->object);
+ // TODO: optimize this loop to limit to valid options only!!
+ for (int ocnt = ((*i)->objStatus != aclRule::VALUE ? 0
+ : (*i)->object);
ocnt < acl::OBJECTSIZE;
- (*i)->objStatus != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) {
- objstr << AclHelper::getObjectTypeStr((ObjectType) ocnt) << ",";
+ (*i)->objStatus != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) {
+
+ //find the Object, create if not exist
+ if (d->actionList[acnt][ocnt] == NULL)
+ d->actionList[acnt][ocnt] =
+ new AclData::actionObject;
+
+ // add users and Rule to object set
+ bool allNames = false;
+ // check to see if names.begin is '*'
+ if ((*(*i)->names.begin()).compare("*") == 0)
+ allNames = true;
+
+ for (nsCitr itr = (allNames ? names.begin() : (*i)->names.begin());
+ itr != (allNames ? names.end() : (*i)->names.end());
+ itr++) {
+ AclData::actObjItr itrRule =
+ d->actionList[acnt][ocnt]->find(*itr);
+
+ if (itrRule == d->actionList[acnt][ocnt]->end()) {
+ AclData::ruleSet rSet;
+ rSet.push_back(rule);
+ d->actionList[acnt][ocnt]->insert
+ (make_pair(std::string(*itr), rSet));
+ } else {
+ // TODO add code to check for dead rules
+ // allow peter create queue name=tmp <-- dead rule!!
+ // allow peter create queue
+
+ itrRule->second.push_back(rule);
+ }
+ }
}
+ }
- bool allNames = ((*(*i)->names.begin()).compare("*") == 0);
- std::ostringstream userstr;
- for (nsCitr itr = (allNames ? names.begin() : (*i)->names.begin());
- itr != (allNames ? names.end() : (*i)->names.end());
- itr++) {
- userstr << *itr << ",";
- }
+ std::ostringstream objstr;
+ for (int ocnt = ((*i)->objStatus != aclRule::VALUE ? 0 : (*i)->object);
+ ocnt < acl::OBJECTSIZE;
+ (*i)->objStatus != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) {
+ objstr << AclHelper::getObjectTypeStr((ObjectType) ocnt) << ",";
+ }
- QPID_LOG(debug, "ACL: Adding actions {" <<
- actionstr.str().substr(0,actionstr.str().length()-1)
- << "} to objects {" <<
- objstr.str().substr(0,objstr.str().length()-1)
- << "} with props " <<
- AclHelper::propertyMapToString(&rule.props)
- << " for users {" <<
- userstr.str().substr(0,userstr.str().length()-1)
- << "}" );
- } else {
- QPID_LOG(debug, "ACL Skipping based on Mode:"
- << AclHelper::getAclResultStr(d->decisionMode));
+ bool allNames = ((*(*i)->names.begin()).compare("*") == 0);
+ std::ostringstream userstr;
+ for (nsCitr itr = (allNames ? names.begin() : (*i)->names.begin());
+ itr != (allNames ? names.end() : (*i)->names.end());
+ itr++) {
+ userstr << *itr << ",";
}
- }
+ QPID_LOG(debug, "ACL: Adding actions {" <<
+ actionstr.str().substr(0,actionstr.str().length()-1)
+ << "} to objects {" <<
+ objstr.str().substr(0,objstr.str().length()-1)
+ << "} with props " <<
+ AclHelper::propertyMapToString(&rule.props)
+ << " for users {" <<
+ userstr.str().substr(0,userstr.str().length()-1)
+ << "}" );
+ }
}
-
}
@@ -277,7 +239,7 @@ namespace acl {
}
ifs.close();
if (err) return -3;
- QPID_LOG(notice, "Read ACL file \"" << fn << "\"");
+ QPID_LOG(notice, "ACL: Read file \"" << fn << "\"");
} catch (const std::exception& e) {
errorStream << "Unable to read ACL file \"" << fn << "\": " << e.what();
ifs.close();
@@ -410,8 +372,8 @@ namespace acl {
// Debug aid
void AclReader::printNames() const {
- QPID_LOG(debug, "Group list: " << groups.size() << " groups found:" );
- std::string tmp;
+ QPID_LOG(debug, "ACL: Group list: " << groups.size() << " groups found:" );
+ std::string tmp("ACL: ");
for (gmCitr i=groups.begin(); i!= groups.end(); i++) {
tmp += " \"";
tmp += i->first;
@@ -421,10 +383,10 @@ namespace acl {
tmp += *j;
}
QPID_LOG(debug, tmp);
- tmp.clear();
+ tmp = "ACL: ";
}
- QPID_LOG(debug, "Name list: " << names.size() << " names found:" );
- tmp.clear();
+ QPID_LOG(debug, "ACL: name list: " << names.size() << " names found:" );
+ tmp = "ACL: ";
for (nsCitr k=names.begin(); k!=names.end(); k++) {
tmp += " ";
tmp += *k;
@@ -501,9 +463,9 @@ namespace acl {
<< propNvp.first << "\". (Must be name=value)";
return false;
}
- Property prop;
+ SpecProperty prop;
try {
- prop = AclHelper::getProperty(propNvp.first);
+ prop = AclHelper::getSpecProperty(propNvp.first);
} catch (...) {
errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Line : " << lineNumber
<< ", Unknown property \"" << propNvp.first << "\".";
@@ -532,10 +494,10 @@ namespace acl {
// Debug aid
void AclReader::printRules() const {
- QPID_LOG(debug, "Rule list: " << rules.size() << " ACL rules found:");
- int cnt = 0;
+ QPID_LOG(debug, "ACL: Rule list: " << rules.size() << " ACL rules found:");
+ int cnt = 1;
for (rlCitr i=rules.begin(); i<rules.end(); i++,cnt++) {
- QPID_LOG(debug, " " << std::setfill(' ') << std::setw(2) << cnt << " " << (*i)->toString());
+ QPID_LOG(debug, "ACL: " << std::setfill(' ') << std::setw(2) << cnt << " " << (*i)->toString());
}
}
diff --git a/cpp/src/qpid/acl/AclReader.h b/cpp/src/qpid/acl/AclReader.h
index 62c6f38f37..730013f4ed 100644
--- a/cpp/src/qpid/acl/AclReader.h
+++ b/cpp/src/qpid/acl/AclReader.h
@@ -33,65 +33,71 @@ namespace qpid {
namespace acl {
class AclReader {
- typedef std::set<std::string> nameSet;
- typedef nameSet::const_iterator nsCitr;
- typedef boost::shared_ptr<nameSet> nameSetPtr;
-
- typedef std::pair<std::string, nameSetPtr> groupPair;
- typedef std::map<std::string, nameSetPtr> groupMap;
- typedef groupMap::const_iterator gmCitr;
- typedef std::pair<gmCitr, bool> gmRes;
-
- typedef std::pair<Property, std::string> propNvPair;
- typedef std::map<Property, std::string> propMap;
- typedef propMap::const_iterator pmCitr;
-
+ typedef std::set<std::string> nameSet;
+ typedef nameSet::const_iterator nsCitr;
+ typedef boost::shared_ptr<nameSet> nameSetPtr;
+
+ typedef std::pair<std::string, nameSetPtr> groupPair;
+ typedef std::map<std::string, nameSetPtr> groupMap;
+ typedef groupMap::const_iterator gmCitr;
+ typedef std::pair<gmCitr, bool> gmRes;
+
+ typedef std::pair<SpecProperty, std::string> propNvPair;
+ typedef std::map<SpecProperty, std::string> propMap;
+ typedef propMap::const_iterator pmCitr;
+
+ //
+ // aclRule
+ //
+ // A temporary rule created during ACL file processing.
+ //
class aclRule {
public:
enum objectStatus {NONE, VALUE, ALL};
- AclResult res;
- nameSet names;
- bool actionAll; // True if action is set to keyword "all"
- Action action; // Ignored if action is set to keyword "all"
- objectStatus objStatus;
- ObjectType object; // Ignored for all status values except VALUE
- propMap props;
+
+ AclResult res;
+ nameSet names;
+ bool actionAll; // True if action is set to keyword "all"
+ Action action; // Ignored if action is set to keyword "all"
+ objectStatus objStatus;
+ ObjectType object; // Ignored for all status values except VALUE
+ propMap props;
public:
aclRule(const AclResult r, const std::string n, const groupMap& groups); // action = "all"
aclRule(const AclResult r, const std::string n, const groupMap& groups, const Action a);
void setObjectType(const ObjectType o);
void setObjectTypeAll();
- bool addProperty(const Property p, const std::string v);
+ bool addProperty(const SpecProperty p, const std::string v);
bool validate(const AclHelper::objectMapPtr& validationMap);
std::string toString(); // debug aid
private:
void processName(const std::string& name, const groupMap& groups);
};
- typedef boost::shared_ptr<aclRule> aclRulePtr;
- typedef std::vector<aclRulePtr> ruleList;
- typedef ruleList::const_iterator rlCitr;
+ typedef boost::shared_ptr<aclRule> aclRulePtr;
+ typedef std::vector<aclRulePtr> ruleList;
+ typedef ruleList::const_iterator rlCitr;
- typedef std::vector<std::string> tokList;
- typedef tokList::const_iterator tlCitr;
+ typedef std::vector<std::string> tokList;
+ typedef tokList::const_iterator tlCitr;
- typedef std::set<std::string> keywordSet;
- typedef keywordSet::const_iterator ksCitr;
+ typedef std::set<std::string> keywordSet;
+ typedef keywordSet::const_iterator ksCitr;
typedef std::pair<std::string, std::string> nvPair; // Name-Value pair
- std::string fileName;
- int lineNumber;
- bool contFlag;
- std::string groupName;
- nameSet names;
- groupMap groups;
- ruleList rules;
+ std::string fileName;
+ int lineNumber;
+ bool contFlag;
+ std::string groupName;
+ nameSet names;
+ groupMap groups;
+ ruleList rules;
AclHelper::objectMapPtr validationMap;
- std::ostringstream errorStream;
+ std::ostringstream errorStream;
public:
AclReader();
virtual ~AclReader();
- int read(const std::string& fn, boost::shared_ptr<AclData> d);
+ int read(const std::string& fn, boost::shared_ptr<AclData> d); // return=0 for success
std::string getError();
private:
diff --git a/cpp/src/qpid/acl/AclValidator.cpp b/cpp/src/qpid/acl/AclValidator.cpp
index d5a00b005b..49bb65db4b 100644
--- a/cpp/src/qpid/acl/AclValidator.cpp
+++ b/cpp/src/qpid/acl/AclValidator.cpp
@@ -29,7 +29,7 @@
namespace qpid {
namespace acl {
- AclValidator::IntPropertyType::IntPropertyType(int64_t i,int64_t j) : min(i), max(j){
+ AclValidator::IntPropertyType::IntPropertyType(int64_t i,int64_t j) : min(i), max(j){
}
bool AclValidator::IntPropertyType::validate(const std::string& val) {
@@ -49,12 +49,12 @@ namespace acl {
}
std::string AclValidator::IntPropertyType::allowedValues() {
- return "values should be between " +
+ return "values should be between " +
boost::lexical_cast<std::string>(min) + " and " +
boost::lexical_cast<std::string>(max);
}
- AclValidator::EnumPropertyType::EnumPropertyType(std::vector<std::string>& allowed): values(allowed){
+ AclValidator::EnumPropertyType::EnumPropertyType(std::vector<std::string>& allowed): values(allowed){
}
bool AclValidator::EnumPropertyType::validate(const std::string& val) {
@@ -78,24 +78,27 @@ namespace acl {
}
AclValidator::AclValidator(){
- validators.insert(Validator(acl::PROP_MAXQUEUESIZE,
- boost::shared_ptr<PropertyType>(
- new IntPropertyType(0,std::numeric_limits<int64_t>::max()))
- )
- );
-
- validators.insert(Validator(acl::PROP_MAXQUEUECOUNT,
- boost::shared_ptr<PropertyType>(
- new IntPropertyType(0,std::numeric_limits<int64_t>::max()))
- )
- );
+ validators.insert(Validator(acl::SPECPROP_MAXQUEUESIZELOWERLIMIT,
+ boost::shared_ptr<PropertyType>(
+ new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
+
+ validators.insert(Validator(acl::SPECPROP_MAXQUEUESIZEUPPERLIMIT,
+ boost::shared_ptr<PropertyType>(
+ new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
+
+ validators.insert(Validator(acl::SPECPROP_MAXQUEUECOUNTLOWERLIMIT,
+ boost::shared_ptr<PropertyType>(
+ new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
+
+ validators.insert(Validator(acl::SPECPROP_MAXQUEUECOUNTUPPERLIMIT,
+ boost::shared_ptr<PropertyType>(
+ new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
std::string policyTypes[] = {"ring", "ring_strict", "flow_to_disk", "reject"};
std::vector<std::string> v(policyTypes, policyTypes + sizeof(policyTypes) / sizeof(std::string));
- validators.insert(Validator(acl::PROP_POLICYTYPE,
- boost::shared_ptr<PropertyType>(new EnumPropertyType(v))
- )
- );
+ validators.insert(Validator(acl::SPECPROP_POLICYTYPE,
+ boost::shared_ptr<PropertyType>(
+ new EnumPropertyType(v))));
}
@@ -114,9 +117,9 @@ namespace acl {
if (d->actionList[cnt][cnt1]){
std::for_each(d->actionList[cnt][cnt1]->begin(),
- d->actionList[cnt][cnt1]->end(),
- boost::bind(&AclValidator::validateRuleSet, this, _1));
- }//if
+ d->actionList[cnt][cnt1]->end(),
+ boost::bind(&AclValidator::validateRuleSet, this, _1));
+ }//if
}//for
}//if
}//for
@@ -125,25 +128,29 @@ namespace acl {
void AclValidator::validateRuleSet(std::pair<const std::string, qpid::acl::AclData::ruleSet>& rules){
std::for_each(rules.second.begin(),
rules.second.end(),
- boost::bind(&AclValidator::validateRule, this, _1));
+ boost::bind(&AclValidator::validateRule, this, _1));
}
void AclValidator::validateRule(qpid::acl::AclData::rule& rule){
std::for_each(rule.props.begin(),
rule.props.end(),
- boost::bind(&AclValidator::validateProperty, this, _1));
+ boost::bind(&AclValidator::validateProperty, this, _1));
}
- void AclValidator::validateProperty(std::pair<const qpid::acl::Property, std::string>& prop){
+ void AclValidator::validateProperty(std::pair<const qpid::acl::SpecProperty, std::string>& prop){
ValidatorItr itr = validators.find(prop.first);
if (itr != validators.end()){
- QPID_LOG(debug,"Found validator for property " << itr->second->allowedValues());
+ QPID_LOG(debug,"ACL: Found validator for property '" << acl::AclHelper::getPropertyStr(itr->first)
+ << "'. " << itr->second->allowedValues());
if (!itr->second->validate(prop.second)){
- throw Exception( prop.second + " is not a valid value for '" +
+ QPID_LOG(debug, "ACL: Property failed validation. '" << prop.second << "' is not a valid value for '"
+ << AclHelper::getPropertyStr(prop.first) << "'");
+
+ throw Exception( prop.second + " is not a valid value for '" +
AclHelper::getPropertyStr(prop.first) + "', " +
itr->second->allowedValues());
- }
+ }
}
}
diff --git a/cpp/src/qpid/acl/AclValidator.h b/cpp/src/qpid/acl/AclValidator.h
index 966e5d326b..f85c241b06 100644
--- a/cpp/src/qpid/acl/AclValidator.h
+++ b/cpp/src/qpid/acl/AclValidator.h
@@ -33,18 +33,18 @@ namespace acl {
class AclValidator {
/* Base Property */
- class PropertyType{
-
+ class PropertyType{
+
public:
virtual ~PropertyType(){};
virtual bool validate(const std::string& val)=0;
virtual std::string allowedValues()=0;
};
- class IntPropertyType : public PropertyType{
+ class IntPropertyType : public PropertyType{
int64_t min;
int64_t max;
-
+
public:
IntPropertyType(int64_t min,int64_t max);
virtual ~IntPropertyType (){};
@@ -53,7 +53,7 @@ class AclValidator {
};
class EnumPropertyType : public PropertyType{
- std::vector<std::string> values;
+ std::vector<std::string> values;
public:
EnumPropertyType(std::vector<std::string>& allowed);
@@ -61,23 +61,23 @@ class AclValidator {
virtual bool validate(const std::string& val);
virtual std::string allowedValues();
};
-
- typedef std::pair<acl::Property,boost::shared_ptr<PropertyType> > Validator;
- typedef std::map<acl::Property,boost::shared_ptr<PropertyType> > ValidatorMap;
+
+ typedef std::pair<acl::SpecProperty,boost::shared_ptr<PropertyType> > Validator;
+ typedef std::map<acl::SpecProperty,boost::shared_ptr<PropertyType> > ValidatorMap;
typedef ValidatorMap::iterator ValidatorItr;
-
+
ValidatorMap validators;
public:
void validateRuleSet(std::pair<const std::string, qpid::acl::AclData::ruleSet>& rules);
void validateRule(qpid::acl::AclData::rule& rule);
- void validateProperty(std::pair<const qpid::acl::Property, std::string>& prop);
- void validate(boost::shared_ptr<AclData> d);
+ void validateProperty(std::pair<const qpid::acl::SpecProperty, std::string>& prop);
+ void validate(boost::shared_ptr<AclData> d);
AclValidator();
~AclValidator();
};
-
+
}} // namespace qpid::acl
#endif // QPID_ACL_ACLVALIDATOR_H
diff --git a/cpp/src/qpid/acl/management-schema.xml b/cpp/src/qpid/acl/management-schema.xml
index 7f48a9be34..19fe37333c 100644
--- a/cpp/src/qpid/acl/management-schema.xml
+++ b/cpp/src/qpid/acl/management-schema.xml
@@ -23,8 +23,40 @@
<property name="transferAcl" type="bool" access="RO" desc="Any transfer ACL rules in force"/>
<property name="lastAclLoad" type="absTime" access="RO" desc="Timestamp of last successful load of ACL"/>
<statistic name="aclDenyCount" type="count64" unit="request" desc="Number of ACL requests denied"/>
+ <statistic name="connectionDenyCount" type="count64" unit="connection" desc="Number of connections denied"/>
<method name="reloadACLFile" desc="Reload the ACL file"/>
+
+ <!--
+ Lookup is a general object lookup
+ User Name
+ Action
+ Object
+ Object Name
+ Property Map consisting of <"name" "value"> string pairs.
+ -->
+ <method name="Lookup" desc="Lookup: user action object [objectName [propertyMap]]">
+ <arg name="userId" dir="I" type="lstr"/>
+ <arg name="action" dir="I" type="lstr"/>
+ <arg name="object" dir="I" type="lstr"/>
+ <arg name="objectName" dir="I" type="lstr"/>
+ <arg name="propertyMap" dir="I" type="map"/>
+ <arg name="result" dir="O" type="lstr"/>
+ </method>
+
+ <!--
+ LookupPublish is a specific lookup for a PUBLISH EXCHANGE fastpath
+ User Name
+ Exchange Name
+ Routing Key
+ -->
+ <method name="LookupPublish" desc="Lookup PUBLISH EXCHANGE: user exchangeName routingKey">
+ <arg name="userId" dir="I" type="lstr"/>
+ <arg name="exchangeName" dir="I" type="lstr"/>
+ <arg name="routingKey" dir="I" type="lstr"/>
+ <arg name="result" dir="O" type="lstr"/>
+ </method>
+
</class>
<eventArguments>
@@ -34,10 +66,12 @@
<arg name="objectType" type="sstr"/>
<arg name="reason" type="lstr"/>
<arg name="userId" type="sstr"/>
+ <arg name="clientAddr" type="sstr"/>
</eventArguments>
<event name="allow" sev="inform" args="userId, action, objectType, objectName, arguments"/>
<event name="deny" sev="notice" args="userId, action, objectType, objectName, arguments"/>
+ <event name="connectionDeny" sev="notice" args="userId, clientAddr"/>
<event name="fileLoaded" sev="inform" args="userId"/>
<event name="fileLoadFailed" sev="error" args="userId, reason"/>
diff --git a/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/cpp/src/qpid/agent/ManagementAgentImpl.cpp
index f183ff8e0c..09b7fa58e9 100644
--- a/cpp/src/qpid/agent/ManagementAgentImpl.cpp
+++ b/cpp/src/qpid/agent/ManagementAgentImpl.cpp
@@ -31,9 +31,11 @@
#include <fstream>
#include <boost/lexical_cast.hpp>
+namespace qpid {
+namespace management {
+
using namespace qpid::client;
using namespace qpid::framing;
-using namespace qpid::management;
using namespace qpid::sys;
using namespace std;
using std::stringstream;
@@ -1260,7 +1262,7 @@ void ManagementAgentImpl::ConnectionThread::run()
int totalSleep = 0;
do {
sys::Mutex::ScopedUnlock _unlock(connLock);
- ::sleep(delayMin);
+ qpid::sys::sleep(delayMin);
totalSleep += delayMin;
} while (totalSleep < delay && !shutdown);
sleeping = false;
@@ -1396,8 +1398,11 @@ void ManagementAgentImpl::PublishThread::run()
sleepTime = 1;
while (totalSleep < agent.getInterval() && !shutdown) {
- ::sleep(sleepTime);
+ qpid::sys::sleep(sleepTime);
totalSleep += sleepTime;
}
}
}
+
+}}
+
diff --git a/cpp/src/qpid/broker/AclModule.h b/cpp/src/qpid/broker/AclModule.h
index e32ff266b9..ff9281b6fc 100644
--- a/cpp/src/qpid/broker/AclModule.h
+++ b/cpp/src/qpid/broker/AclModule.h
@@ -22,6 +22,7 @@
#include "qpid/RefCounted.h"
+#include "qpid/Exception.h"
#include <boost/shared_ptr.hpp>
#include <map>
#include <set>
@@ -32,17 +33,81 @@ namespace qpid {
namespace acl {
- enum ObjectType {OBJ_QUEUE, OBJ_EXCHANGE, OBJ_BROKER, OBJ_LINK,
- OBJ_METHOD, OBJECTSIZE}; // OBJECTSIZE must be last in list
- enum Action {ACT_CONSUME, ACT_PUBLISH, ACT_CREATE, ACT_ACCESS, ACT_BIND,
- ACT_UNBIND, ACT_DELETE, ACT_PURGE, ACT_UPDATE,
- ACTIONSIZE}; // ACTIONSIZE must be last in list
- enum Property {PROP_NAME, PROP_DURABLE, PROP_OWNER, PROP_ROUTINGKEY,
- PROP_PASSIVE, PROP_AUTODELETE, PROP_EXCLUSIVE, PROP_TYPE,
- PROP_ALTERNATE, PROP_QUEUENAME, PROP_SCHEMAPACKAGE,
- PROP_SCHEMACLASS, PROP_POLICYTYPE, PROP_MAXQUEUESIZE,
- PROP_MAXQUEUECOUNT};
- enum AclResult {ALLOW, ALLOWLOG, DENY, DENYLOG};
+ // Interface enumerations.
+ // These enumerations define enum lists and implied text strings
+ // to match. They are used in two areas:
+ // 1. In the ACL specifications in the ACL file, file parsing, and
+ // internal rule storage.
+ // 2. In the authorize interface in the rest of the broker where
+ // code requests the ACL module to authorize an action.
+
+ // ObjectType shared between ACL spec and ACL authorise interface
+ enum ObjectType {
+ OBJ_QUEUE,
+ OBJ_EXCHANGE,
+ OBJ_BROKER,
+ OBJ_LINK,
+ OBJ_METHOD,
+ OBJECTSIZE }; // OBJECTSIZE must be last in list
+
+ // Action shared between ACL spec and ACL authorise interface
+ enum Action {
+ ACT_CONSUME,
+ ACT_PUBLISH,
+ ACT_CREATE,
+ ACT_ACCESS,
+ ACT_BIND,
+ ACT_UNBIND,
+ ACT_DELETE,
+ ACT_PURGE,
+ ACT_UPDATE,
+ ACTIONSIZE }; // ACTIONSIZE must be last in list
+
+ // Property used in ACL authorize interface
+ enum Property {
+ PROP_NAME,
+ PROP_DURABLE,
+ PROP_OWNER,
+ PROP_ROUTINGKEY,
+ PROP_AUTODELETE,
+ PROP_EXCLUSIVE,
+ PROP_TYPE,
+ PROP_ALTERNATE,
+ PROP_QUEUENAME,
+ PROP_SCHEMAPACKAGE,
+ PROP_SCHEMACLASS,
+ PROP_POLICYTYPE,
+ PROP_MAXQUEUESIZE,
+ PROP_MAXQUEUECOUNT };
+
+ // Property used in ACL spec file
+ // Note for properties common to file processing/rule storage and to
+ // broker rule lookups the identical enum values are used.
+ enum SpecProperty {
+ SPECPROP_NAME = PROP_NAME,
+ SPECPROP_DURABLE = PROP_DURABLE,
+ SPECPROP_OWNER = PROP_OWNER,
+ SPECPROP_ROUTINGKEY = PROP_ROUTINGKEY,
+ SPECPROP_AUTODELETE = PROP_AUTODELETE,
+ SPECPROP_EXCLUSIVE = PROP_EXCLUSIVE,
+ SPECPROP_TYPE = PROP_TYPE,
+ SPECPROP_ALTERNATE = PROP_ALTERNATE,
+ SPECPROP_QUEUENAME = PROP_QUEUENAME,
+ SPECPROP_SCHEMAPACKAGE = PROP_SCHEMAPACKAGE,
+ SPECPROP_SCHEMACLASS = PROP_SCHEMACLASS,
+ SPECPROP_POLICYTYPE = PROP_POLICYTYPE,
+
+ SPECPROP_MAXQUEUESIZELOWERLIMIT,
+ SPECPROP_MAXQUEUESIZEUPPERLIMIT,
+ SPECPROP_MAXQUEUECOUNTLOWERLIMIT,
+ SPECPROP_MAXQUEUECOUNTUPPERLIMIT };
+
+// AclResult shared between ACL spec and ACL authorise interface
+ enum AclResult {
+ ALLOW,
+ ALLOWLOG,
+ DENY,
+ DENYLOG };
} // namespace acl
@@ -54,14 +119,25 @@ namespace broker {
public:
- // effienty turn off ACL on message transfer.
+ // Some ACLs are invoked on every message transfer.
+ // doTransferAcl pervents time consuming ACL calls on a per-message basis.
virtual bool doTransferAcl()=0;
- virtual bool authorise(const std::string& id, const acl::Action& action, const acl::ObjectType& objType, const std::string& name,
+ virtual bool authorise(
+ const std::string& id,
+ const acl::Action& action,
+ const acl::ObjectType& objType,
+ const std::string& name,
std::map<acl::Property, std::string>* params=0)=0;
- virtual bool authorise(const std::string& id, const acl::Action& action, const acl::ObjectType& objType, const std::string& ExchangeName,
- const std::string& RoutingKey)=0;
- // create specilied authorise methods for cases that need faster matching as needed.
+
+ virtual bool authorise(
+ const std::string& id,
+ const acl::Action& action,
+ const acl::ObjectType& objType,
+ const std::string& ExchangeName,
+ const std::string& RoutingKey)=0;
+
+ // Add specialized authorise() methods as required.
virtual ~AclModule() {};
};
@@ -79,7 +155,7 @@ namespace acl {
if (str.compare("broker") == 0) return OBJ_BROKER;
if (str.compare("link") == 0) return OBJ_LINK;
if (str.compare("method") == 0) return OBJ_METHOD;
- throw str;
+ throw qpid::Exception(str);
}
static inline std::string getObjectTypeStr(const ObjectType o) {
switch (o) {
@@ -102,7 +178,7 @@ namespace acl {
if (str.compare("delete") == 0) return ACT_DELETE;
if (str.compare("purge") == 0) return ACT_PURGE;
if (str.compare("update") == 0) return ACT_UPDATE;
- throw str;
+ throw qpid::Exception(str);
}
static inline std::string getActionStr(const Action a) {
switch (a) {
@@ -124,7 +200,6 @@ namespace acl {
if (str.compare("durable") == 0) return PROP_DURABLE;
if (str.compare("owner") == 0) return PROP_OWNER;
if (str.compare("routingkey") == 0) return PROP_ROUTINGKEY;
- if (str.compare("passive") == 0) return PROP_PASSIVE;
if (str.compare("autodelete") == 0) return PROP_AUTODELETE;
if (str.compare("exclusive") == 0) return PROP_EXCLUSIVE;
if (str.compare("type") == 0) return PROP_TYPE;
@@ -134,8 +209,8 @@ namespace acl {
if (str.compare("schemaclass") == 0) return PROP_SCHEMACLASS;
if (str.compare("policytype") == 0) return PROP_POLICYTYPE;
if (str.compare("maxqueuesize") == 0) return PROP_MAXQUEUESIZE;
- if (str.compare("maxqueuecount") == 0) return PROP_MAXQUEUECOUNT;
- throw str;
+ if (str.compare("maxqueuecount") == 0) return PROP_MAXQUEUECOUNT;
+ throw qpid::Exception(str);
}
static inline std::string getPropertyStr(const Property p) {
switch (p) {
@@ -143,7 +218,6 @@ namespace acl {
case PROP_DURABLE: return "durable";
case PROP_OWNER: return "owner";
case PROP_ROUTINGKEY: return "routingkey";
- case PROP_PASSIVE: return "passive";
case PROP_AUTODELETE: return "autodelete";
case PROP_EXCLUSIVE: return "exclusive";
case PROP_TYPE: return "type";
@@ -153,17 +227,61 @@ namespace acl {
case PROP_SCHEMACLASS: return "schemaclass";
case PROP_POLICYTYPE: return "policytype";
case PROP_MAXQUEUESIZE: return "maxqueuesize";
- case PROP_MAXQUEUECOUNT: return "maxqueuecount";
+ case PROP_MAXQUEUECOUNT: return "maxqueuecount";
default: assert(false); // should never get here
}
return "";
}
+ static inline SpecProperty getSpecProperty(const std::string& str) {
+ if (str.compare("name") == 0) return SPECPROP_NAME;
+ if (str.compare("durable") == 0) return SPECPROP_DURABLE;
+ if (str.compare("owner") == 0) return SPECPROP_OWNER;
+ if (str.compare("routingkey") == 0) return SPECPROP_ROUTINGKEY;
+ if (str.compare("autodelete") == 0) return SPECPROP_AUTODELETE;
+ if (str.compare("exclusive") == 0) return SPECPROP_EXCLUSIVE;
+ if (str.compare("type") == 0) return SPECPROP_TYPE;
+ if (str.compare("alternate") == 0) return SPECPROP_ALTERNATE;
+ if (str.compare("queuename") == 0) return SPECPROP_QUEUENAME;
+ if (str.compare("schemapackage") == 0) return SPECPROP_SCHEMAPACKAGE;
+ if (str.compare("schemaclass") == 0) return SPECPROP_SCHEMACLASS;
+ if (str.compare("policytype") == 0) return SPECPROP_POLICYTYPE;
+ if (str.compare("queuemaxsizelowerlimit") == 0) return SPECPROP_MAXQUEUESIZELOWERLIMIT;
+ if (str.compare("queuemaxsizeupperlimit") == 0) return SPECPROP_MAXQUEUESIZEUPPERLIMIT;
+ if (str.compare("queuemaxcountlowerlimit") == 0) return SPECPROP_MAXQUEUECOUNTLOWERLIMIT;
+ if (str.compare("queuemaxcountupperlimit") == 0) return SPECPROP_MAXQUEUECOUNTUPPERLIMIT;
+ // Allow old names in ACL file as aliases for newly-named properties
+ if (str.compare("maxqueuesize") == 0) return SPECPROP_MAXQUEUESIZEUPPERLIMIT;
+ if (str.compare("maxqueuecount") == 0) return SPECPROP_MAXQUEUECOUNTUPPERLIMIT;
+ throw qpid::Exception(str);
+ }
+ static inline std::string getPropertyStr(const SpecProperty p) {
+ switch (p) {
+ case SPECPROP_NAME: return "name";
+ case SPECPROP_DURABLE: return "durable";
+ case SPECPROP_OWNER: return "owner";
+ case SPECPROP_ROUTINGKEY: return "routingkey";
+ case SPECPROP_AUTODELETE: return "autodelete";
+ case SPECPROP_EXCLUSIVE: return "exclusive";
+ case SPECPROP_TYPE: return "type";
+ case SPECPROP_ALTERNATE: return "alternate";
+ case SPECPROP_QUEUENAME: return "queuename";
+ case SPECPROP_SCHEMAPACKAGE: return "schemapackage";
+ case SPECPROP_SCHEMACLASS: return "schemaclass";
+ case SPECPROP_POLICYTYPE: return "policytype";
+ case SPECPROP_MAXQUEUESIZELOWERLIMIT: return "queuemaxsizelowerlimit";
+ case SPECPROP_MAXQUEUESIZEUPPERLIMIT: return "queuemaxsizeupperlimit";
+ case SPECPROP_MAXQUEUECOUNTLOWERLIMIT: return "queuemaxcountlowerlimit";
+ case SPECPROP_MAXQUEUECOUNTUPPERLIMIT: return "queuemaxcountupperlimit";
+ default: assert(false); // should never get here
+ }
+ return "";
+ }
static inline AclResult getAclResult(const std::string& str) {
if (str.compare("allow") == 0) return ALLOW;
if (str.compare("allow-log") == 0) return ALLOWLOG;
if (str.compare("deny") == 0) return DENY;
if (str.compare("deny-log") == 0) return DENYLOG;
- throw str;
+ throw qpid::Exception(str);
}
static inline std::string getAclResultStr(const AclResult r) {
switch (r) {
@@ -187,8 +305,11 @@ namespace acl {
typedef boost::shared_ptr<objectMap> objectMapPtr;
typedef std::map<Property, std::string> propMap;
typedef propMap::const_iterator propMapItr;
+ typedef std::map<SpecProperty, std::string> specPropMap;
+ typedef specPropMap::const_iterator specPropMapItr;
- // This map contains the legal combinations of object/action/properties found in an ACL file
+ // This map contains the legal combinations of object/action/properties
+ // found in an ACL file
static void loadValidationMap(objectMapPtr& map) {
if (!map.get()) return;
map->clear();
@@ -199,7 +320,6 @@ namespace acl {
propSetPtr p1(new propSet);
p1->insert(PROP_TYPE);
p1->insert(PROP_ALTERNATE);
- p1->insert(PROP_PASSIVE);
p1->insert(PROP_DURABLE);
propSetPtr p2(new propSet);
@@ -224,7 +344,6 @@ namespace acl {
propSetPtr p4(new propSet);
p4->insert(PROP_ALTERNATE);
- p4->insert(PROP_PASSIVE);
p4->insert(PROP_DURABLE);
p4->insert(PROP_EXCLUSIVE);
p4->insert(PROP_AUTODELETE);
@@ -260,21 +379,31 @@ namespace acl {
map->insert(objectPair(OBJ_METHOD, a4));
}
- static std::string propertyMapToString(const std::map<Property, std::string>* params) {
+ //
+ // properyMapToString
+ //
+ template <typename T>
+ static std::string propertyMapToString(
+ const std::map<T, std::string>* params)
+ {
std::ostringstream ss;
ss << "{";
if (params)
{
- for (propMapItr pMItr = params->begin(); pMItr != params->end(); pMItr++) {
- ss << " " << getPropertyStr((Property) pMItr-> first) << "=" << pMItr->second;
+ for (typename std::map<T, std::string>::const_iterator
+ pMItr = params->begin(); pMItr != params->end(); pMItr++)
+ {
+ ss << " " << getPropertyStr((T) pMItr-> first)
+ << "=" << pMItr->second;
}
}
ss << " }";
return ss.str();
}
+
};
-
+
}} // namespace qpid::acl
#endif // QPID_ACLMODULE_ACL_H
diff --git a/cpp/src/qpid/broker/Bridge.cpp b/cpp/src/qpid/broker/Bridge.cpp
index 9a1f4be468..5b531e4636 100644
--- a/cpp/src/qpid/broker/Bridge.cpp
+++ b/cpp/src/qpid/broker/Bridge.cpp
@@ -62,7 +62,7 @@ Bridge::Bridge(Link* _link, framing::ChannelId _id, CancellationListener l,
InitializeCallback init) :
link(_link), id(_id), args(_args), mgmtObject(0),
listener(l), name(Uuid(true).str()), queueName("qpid.bridge_queue_"), persistenceId(0),
- initialize(init)
+ initialize(init), detached(false)
{
std::stringstream title;
title << id << "_" << name;
@@ -85,11 +85,14 @@ Bridge::~Bridge()
void Bridge::create(Connection& c)
{
+ detached = false; // Reset detached in case we are recovering.
connState = &c;
conn = &c;
FieldTable options;
if (args.i_sync) options.setInt("qpid.sync_frequency", args.i_sync);
SessionHandler& sessionHandler = c.getChannel(id);
+ sessionHandler.setDetachedCallback(
+ boost::bind(&Bridge::sessionDetached, shared_from_this()));
if (args.i_srcIsLocal) {
if (args.i_dynamic)
throw Exception("Dynamic routing not supported for push routes");
@@ -179,12 +182,6 @@ void Bridge::destroy()
listener(this);
}
-bool Bridge::isSessionReady() const
-{
- SessionHandler& sessionHandler = conn->getChannel(id);
- return sessionHandler.ready();
-}
-
void Bridge::setPersistenceId(uint64_t pId) const
{
persistenceId = pId;
@@ -336,4 +333,8 @@ const string& Bridge::getLocalTag() const
return link->getBroker()->getFederationTag();
}
+void Bridge::sessionDetached() {
+ detached = true;
+}
+
}}
diff --git a/cpp/src/qpid/broker/Bridge.h b/cpp/src/qpid/broker/Bridge.h
index b849b11ba8..32b9fd1781 100644
--- a/cpp/src/qpid/broker/Bridge.h
+++ b/cpp/src/qpid/broker/Bridge.h
@@ -33,6 +33,7 @@
#include "qmf/org/apache/qpid/broker/Bridge.h"
#include <boost/function.hpp>
+#include <boost/enable_shared_from_this.hpp>
#include <memory>
namespace qpid {
@@ -44,7 +45,10 @@ class Link;
class LinkRegistry;
class SessionHandler;
-class Bridge : public PersistableConfig, public management::Manageable, public Exchange::DynamicBridge
+class Bridge : public PersistableConfig,
+ public management::Manageable,
+ public Exchange::DynamicBridge,
+ public boost::enable_shared_from_this<Bridge>
{
public:
typedef boost::shared_ptr<Bridge> shared_ptr;
@@ -63,7 +67,7 @@ public:
void destroy();
bool isDurable() { return args.i_durable; }
- bool isSessionReady() const;
+ bool isDetached() const { return detached; }
management::ManagementObject* GetManagementObject() const;
management::Manageable::status_t ManagementMethod(uint32_t methodId,
@@ -90,6 +94,9 @@ public:
const qmf::org::apache::qpid::broker::ArgsLinkBridge& getArgs() { return args; }
private:
+ // Callback when the bridge's session is detached.
+ void sessionDetached();
+
struct PushHandler : framing::FrameHandler {
PushHandler(Connection* c) { conn = c; }
void handle(framing::AMQFrame& frame);
@@ -112,7 +119,7 @@ private:
ConnectionState* connState;
Connection* conn;
InitializeCallback initialize;
-
+ bool detached; // Set when session is detached.
bool resetProxy();
};
diff --git a/cpp/src/qpid/broker/Broker.cpp b/cpp/src/qpid/broker/Broker.cpp
index 0fd31580f6..f20cce18a2 100644
--- a/cpp/src/qpid/broker/Broker.cpp
+++ b/cpp/src/qpid/broker/Broker.cpp
@@ -111,6 +111,7 @@ Broker::Options::Options(const std::string& name) :
maxConnections(500),
connectionBacklog(10),
enableMgmt(1),
+ mgmtPublish(1),
mgmtPubInterval(10),
queueCleanInterval(60*10),//10 minutes
auth(SaslAuthenticator::available()),
@@ -148,6 +149,7 @@ Broker::Options::Options(const std::string& name) :
("max-connections", optValue(maxConnections, "N"), "Sets the maximum allowed connections")
("connection-backlog", optValue(connectionBacklog, "N"), "Sets the connection backlog limit for the server socket")
("mgmt-enable,m", optValue(enableMgmt,"yes|no"), "Enable Management")
+ ("mgmt-publish", optValue(mgmtPublish,"yes|no"), "Enable Publish of Management Data ('no' implies query-only)")
("mgmt-qmf2", optValue(qmf2Support,"yes|no"), "Enable broadcast of management information over QMF v2")
("mgmt-qmf1", optValue(qmf1Support,"yes|no"), "Enable broadcast of management information over QMF v1")
// FIXME aconway 2012-02-13: consistent treatment of values in SECONDS
@@ -213,7 +215,7 @@ Broker::Broker(const Broker::Options& conf) :
try {
if (conf.enableMgmt) {
QPID_LOG(info, "Management enabled");
- managementAgent->configure(dataDir.isEnabled() ? dataDir.getPath() : string(),
+ managementAgent->configure(dataDir.isEnabled() ? dataDir.getPath() : string(), conf.mgmtPublish,
conf.mgmtPubInterval, this, conf.workerThreads + 3);
managementAgent->setName("apache.org", "qpidd");
_qmf::Package packageInitializer(managementAgent.get());
@@ -228,6 +230,7 @@ Broker::Broker(const Broker::Options& conf) :
mgmtObject->set_maxConns(conf.maxConnections);
mgmtObject->set_connBacklog(conf.connectionBacklog);
mgmtObject->set_mgmtPubInterval(conf.mgmtPubInterval);
+ mgmtObject->set_mgmtPublish(conf.mgmtPublish);
mgmtObject->set_version(qpid::version);
if (dataDir.isEnabled())
mgmtObject->set_dataDir(dataDir.getPath());
@@ -885,7 +888,6 @@ std::pair<boost::shared_ptr<Queue>, bool> Broker::createQueue(
if (acl) {
std::map<acl::Property, std::string> params;
params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
- params.insert(make_pair(acl::PROP_PASSIVE, _FALSE));
params.insert(make_pair(acl::PROP_DURABLE, durable ? _TRUE : _FALSE));
params.insert(make_pair(acl::PROP_EXCLUSIVE, owner ? _TRUE : _FALSE));
params.insert(make_pair(acl::PROP_AUTODELETE, autodelete ? _TRUE : _FALSE));
@@ -956,7 +958,6 @@ std::pair<Exchange::shared_ptr, bool> Broker::createExchange(
std::map<acl::Property, std::string> params;
params.insert(make_pair(acl::PROP_TYPE, type));
params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
- params.insert(make_pair(acl::PROP_PASSIVE, _FALSE));
params.insert(make_pair(acl::PROP_DURABLE, durable ? _TRUE : _FALSE));
if (!acl->authorise(userId,acl::ACT_CREATE,acl::OBJ_EXCHANGE,name,&params) )
throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied exchange create request from " << userId));
diff --git a/cpp/src/qpid/broker/Broker.h b/cpp/src/qpid/broker/Broker.h
index cff38eecdd..135b9340f9 100644
--- a/cpp/src/qpid/broker/Broker.h
+++ b/cpp/src/qpid/broker/Broker.h
@@ -106,6 +106,7 @@ public:
int maxConnections;
int connectionBacklog;
bool enableMgmt;
+ bool mgmtPublish;
uint16_t mgmtPubInterval;
uint16_t queueCleanInterval;
bool auth;
@@ -206,7 +207,7 @@ public:
ConsumerFactories consumerFactories;
public:
- virtual ~Broker();
+ QPID_BROKER_EXTERN virtual ~Broker();
QPID_BROKER_EXTERN Broker(const Options& configuration);
static QPID_BROKER_EXTERN boost::intrusive_ptr<Broker> create(const Options& configuration);
@@ -218,16 +219,16 @@ public:
* port, which will be different if the configured port is
* 0.
*/
- virtual uint16_t getPort(const std::string& name) const;
+ QPID_BROKER_EXTERN virtual uint16_t getPort(const std::string& name) const;
/**
* Run the broker. Implements Runnable::run() so the broker
* can be run in a separate thread.
*/
- virtual void run();
+ QPID_BROKER_EXTERN virtual void run();
/** Shut down the broker */
- virtual void shutdown();
+ QPID_BROKER_EXTERN virtual void shutdown();
QPID_BROKER_EXTERN void setStore (boost::shared_ptr<MessageStore>& store);
void setAsyncStore(boost::shared_ptr<AsyncStore>& asyncStore);
@@ -248,14 +249,14 @@ public:
SessionManager& getSessionManager() { return sessionManager; }
const std::string& getFederationTag() const { return federationTag; }
- management::ManagementObject* GetManagementObject (void) const;
- management::Manageable* GetVhostObject (void) const;
- management::Manageable::status_t ManagementMethod (uint32_t methodId,
- management::Args& args,
- std::string& text);
+ QPID_BROKER_EXTERN management::ManagementObject* GetManagementObject() const;
+ QPID_BROKER_EXTERN management::Manageable* GetVhostObject() const;
+ QPID_BROKER_EXTERN management::Manageable::status_t ManagementMethod(
+ uint32_t methodId, management::Args& args, std::string& text);
/** Add to the broker's protocolFactorys */
- void registerProtocolFactory(const std::string& name, boost::shared_ptr<sys::ProtocolFactory>);
+ QPID_BROKER_EXTERN void registerProtocolFactory(
+ const std::string& name, boost::shared_ptr<sys::ProtocolFactory>);
/** Accept connections */
QPID_BROKER_EXTERN void accept();
@@ -273,15 +274,17 @@ public:
/** Move messages from one queue to another.
A zero quantity means to move all messages
*/
- uint32_t queueMoveMessages( const std::string& srcQueue,
- const std::string& destQueue,
- uint32_t qty,
- const qpid::types::Variant::Map& filter);
+ QPID_BROKER_EXTERN uint32_t queueMoveMessages(
+ const std::string& srcQueue,
+ const std::string& destQueue,
+ uint32_t qty,
+ const qpid::types::Variant::Map& filter);
- boost::shared_ptr<sys::ProtocolFactory> getProtocolFactory(const std::string& name = TCP_TRANSPORT) const;
+ QPID_BROKER_EXTERN boost::shared_ptr<sys::ProtocolFactory> getProtocolFactory(
+ const std::string& name = TCP_TRANSPORT) const;
/** Expose poller so plugins can register their descriptors. */
- boost::shared_ptr<sys::Poller> getPoller();
+ QPID_BROKER_EXTERN boost::shared_ptr<sys::Poller> getPoller();
boost::shared_ptr<sys::ConnectionCodec::Factory> getConnectionFactory() { return factory; }
void setConnectionFactory(boost::shared_ptr<sys::ConnectionCodec::Factory> f) { factory = f; }
@@ -291,7 +294,7 @@ public:
/** Timer for tasks that must be synchronized if we are in a cluster */
sys::Timer& getClusterTimer() { return clusterTimer.get() ? *clusterTimer : timer; }
- void setClusterTimer(std::auto_ptr<sys::Timer>);
+ QPID_BROKER_EXTERN void setClusterTimer(std::auto_ptr<sys::Timer>);
boost::function<std::vector<Url> ()> getKnownBrokers;
@@ -322,15 +325,14 @@ public:
* 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 boost::intrusive_ptr<Message>& msg)> deferDelivery;
bool isAuthenticating ( ) { return config.auth; }
bool isTimestamping() { return config.timestampRcvMsgs; }
typedef boost::function1<void, boost::shared_ptr<Queue> > QueueFunctor;
- std::pair<boost::shared_ptr<Queue>, bool> createQueue(
+ QPID_BROKER_EXTERN std::pair<boost::shared_ptr<Queue>, bool> createQueue(
const std::string& name,
bool durable,
bool autodelete,
@@ -339,30 +341,39 @@ public:
const qpid::framing::FieldTable& arguments,
const std::string& userId,
const std::string& connectionId);
- void deleteQueue(const std::string& name,
- const std::string& userId,
- const std::string& connectionId,
- QueueFunctor check = QueueFunctor());
- std::pair<Exchange::shared_ptr, bool> createExchange(
+
+ QPID_BROKER_EXTERN void deleteQueue(
+ const std::string& name,
+ const std::string& userId,
+ const std::string& connectionId,
+ QueueFunctor check = QueueFunctor());
+
+ QPID_BROKER_EXTERN std::pair<Exchange::shared_ptr, bool> createExchange(
const std::string& name,
const std::string& type,
bool durable,
const std::string& alternateExchange,
const qpid::framing::FieldTable& args,
const std::string& userId, const std::string& connectionId);
- void deleteExchange(const std::string& name, const std::string& userId,
- const std::string& connectionId);
- void bind(const std::string& queue,
- const std::string& exchange,
- const std::string& key,
- const qpid::framing::FieldTable& arguments,
- const std::string& userId,
- const std::string& connectionId);
- void unbind(const std::string& queue,
- const std::string& exchange,
- const std::string& key,
- const std::string& userId,
- const std::string& connectionId);
+
+ QPID_BROKER_EXTERN void deleteExchange(
+ const std::string& name, const std::string& userId,
+ const std::string& connectionId);
+
+ QPID_BROKER_EXTERN void bind(
+ const std::string& queue,
+ const std::string& exchange,
+ const std::string& key,
+ const qpid::framing::FieldTable& arguments,
+ const std::string& userId,
+ const std::string& connectionId);
+
+ QPID_BROKER_EXTERN void unbind(
+ const std::string& queue,
+ const std::string& exchange,
+ const std::string& key,
+ const std::string& userId,
+ const std::string& connectionId);
ConsumerFactories& getConsumerFactories() { return consumerFactories; }
ConnectionObservers& getConnectionObservers() { return connectionObservers; }
diff --git a/cpp/src/qpid/broker/Connection.cpp b/cpp/src/qpid/broker/Connection.cpp
index 1e6aab217c..5e339cec03 100644
--- a/cpp/src/qpid/broker/Connection.cpp
+++ b/cpp/src/qpid/broker/Connection.cpp
@@ -185,11 +185,13 @@ void Connection::recordFromServer(const framing::AMQFrame& frame)
// Don't record management stats in cluster-unsafe contexts
if (mgmtObject != 0 && isClusterSafe())
{
- mgmtObject->inc_framesToClient();
- mgmtObject->inc_bytesToClient(frame.encodedSize());
+ qmf::org::apache::qpid::broker::Connection::PerThreadStats *cStats = mgmtObject->getStatistics();
+ cStats->framesToClient += 1;
+ cStats->bytesToClient += frame.encodedSize();
if (isMessage(frame.getMethod())) {
- mgmtObject->inc_msgsToClient();
+ cStats->msgsToClient += 1;
}
+ mgmtObject->statisticsUpdated();
}
}
@@ -198,11 +200,13 @@ void Connection::recordFromClient(const framing::AMQFrame& frame)
// Don't record management stats in cluster-unsafe contexts
if (mgmtObject != 0 && isClusterSafe())
{
- mgmtObject->inc_framesFromClient();
- mgmtObject->inc_bytesFromClient(frame.encodedSize());
+ qmf::org::apache::qpid::broker::Connection::PerThreadStats *cStats = mgmtObject->getStatistics();
+ cStats->framesFromClient += 1;
+ cStats->bytesFromClient += frame.encodedSize();
if (isMessage(frame.getMethod())) {
- mgmtObject->inc_msgsFromClient();
+ cStats->msgsFromClient += 1;
}
+ mgmtObject->statisticsUpdated();
}
}
diff --git a/cpp/src/qpid/broker/Connection.h b/cpp/src/qpid/broker/Connection.h
index 858ab6f7f4..1b8bd83139 100644
--- a/cpp/src/qpid/broker/Connection.h
+++ b/cpp/src/qpid/broker/Connection.h
@@ -113,15 +113,20 @@ class Connection : public sys::ConnectionInputHandler,
void requestIOProcessing (boost::function0<void>);
void recordFromServer (const framing::AMQFrame& frame);
void recordFromClient (const framing::AMQFrame& frame);
+
+ // gets for configured federation links
std::string getAuthMechanism();
std::string getAuthCredentials();
std::string getUsername();
std::string getPassword();
std::string getHost();
uint16_t getPort();
+
void notifyConnectionForced(const std::string& text);
void setUserId(const std::string& uid);
void raiseConnectEvent();
+
+ // credentials for connected client
const std::string& getUserId() const { return ConnectionState::getUserId(); }
const std::string& getMgmtId() const { return mgmtId; }
management::ManagementAgent* getAgent() const { return agent; }
diff --git a/cpp/src/qpid/broker/ConnectionHandler.cpp b/cpp/src/qpid/broker/ConnectionHandler.cpp
index f1d43c5cdb..6894324117 100644
--- a/cpp/src/qpid/broker/ConnectionHandler.cpp
+++ b/cpp/src/qpid/broker/ConnectionHandler.cpp
@@ -28,6 +28,7 @@
#include "qpid/framing/AllInvoker.h"
#include "qpid/framing/ConnectionStartOkBody.h"
#include "qpid/framing/enum.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/log/Statement.h"
#include "qpid/sys/SecurityLayer.h"
#include "qpid/broker/AclModule.h"
diff --git a/cpp/src/qpid/broker/ConnectionHandler.h b/cpp/src/qpid/broker/ConnectionHandler.h
index 05c5f00c57..2e25543308 100644
--- a/cpp/src/qpid/broker/ConnectionHandler.h
+++ b/cpp/src/qpid/broker/ConnectionHandler.h
@@ -35,7 +35,6 @@
#include "qpid/framing/ProtocolInitiation.h"
#include "qpid/framing/ProtocolVersion.h"
#include "qpid/Exception.h"
-#include "qpid/broker/AclModule.h"
#include "qpid/sys/SecurityLayer.h"
diff --git a/cpp/src/qpid/broker/DirectExchange.cpp b/cpp/src/qpid/broker/DirectExchange.cpp
index 5591539853..5d9aea7509 100644
--- a/cpp/src/qpid/broker/DirectExchange.cpp
+++ b/cpp/src/qpid/broker/DirectExchange.cpp
@@ -153,8 +153,9 @@ bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, c
return true;
}
-void DirectExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/)
+void DirectExchange::route(Deliverable& msg)
{
+ const string& routingKey = msg.getMessage().getRoutingKey();
PreRoute pr(msg, this);
ConstBindingList b;
{
diff --git a/cpp/src/qpid/broker/DirectExchange.h b/cpp/src/qpid/broker/DirectExchange.h
index a6f9cf91af..833be52c1c 100644
--- a/cpp/src/qpid/broker/DirectExchange.h
+++ b/cpp/src/qpid/broker/DirectExchange.h
@@ -57,9 +57,7 @@ public:
const std::string& routingKey,
const qpid::framing::FieldTable* args);
virtual bool unbind(boost::shared_ptr<Queue> queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
- QPID_BROKER_EXTERN virtual void route(Deliverable& msg,
- const std::string& routingKey,
- const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual void route(Deliverable& msg);
QPID_BROKER_EXTERN virtual bool isBound(boost::shared_ptr<Queue> queue,
const std::string* const routingKey,
const qpid::framing::FieldTable* const args);
diff --git a/cpp/src/qpid/broker/DtxManager.cpp b/cpp/src/qpid/broker/DtxManager.cpp
index febd547478..d482c2c327 100644
--- a/cpp/src/qpid/broker/DtxManager.cpp
+++ b/cpp/src/qpid/broker/DtxManager.cpp
@@ -21,6 +21,7 @@
#include "qpid/broker/DtxManager.h"
#include "qpid/broker/DtxTimeout.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/StructHelper.h"
#include "qpid/log/Statement.h"
#include "qpid/sys/Timer.h"
#include "qpid/ptr_map.h"
@@ -55,7 +56,7 @@ void DtxManager::recover(const std::string& xid, std::auto_ptr<TPCTransactionCon
bool DtxManager::prepare(const std::string& xid)
{
- QPID_LOG(debug, "preparing: " << xid);
+ QPID_LOG(debug, "preparing: " << convert(xid));
try {
return getWork(xid)->prepare();
} catch (DtxTimeoutException& e) {
@@ -66,7 +67,7 @@ bool DtxManager::prepare(const std::string& xid)
bool DtxManager::commit(const std::string& xid, bool onePhase)
{
- QPID_LOG(debug, "committing: " << xid);
+ QPID_LOG(debug, "committing: " << convert(xid));
try {
bool result = getWork(xid)->commit(onePhase);
remove(xid);
@@ -79,7 +80,7 @@ bool DtxManager::commit(const std::string& xid, bool onePhase)
void DtxManager::rollback(const std::string& xid)
{
- QPID_LOG(debug, "rolling back: " << xid);
+ QPID_LOG(debug, "rolling back: " << convert(xid));
try {
getWork(xid)->rollback();
remove(xid);
@@ -94,7 +95,7 @@ DtxWorkRecord* DtxManager::getWork(const std::string& xid)
Mutex::ScopedLock locker(lock);
WorkMap::iterator i = work.find(xid);
if (i == work.end()) {
- throw NotFoundException(QPID_MSG("Unrecognised xid " << xid));
+ throw NotFoundException(QPID_MSG("Unrecognised xid " << convert(xid)));
}
return ptr_map_ptr(i);
}
@@ -109,7 +110,7 @@ void DtxManager::remove(const std::string& xid)
Mutex::ScopedLock locker(lock);
WorkMap::iterator i = work.find(xid);
if (i == work.end()) {
- throw NotFoundException(QPID_MSG("Unrecognised xid " << xid));
+ throw NotFoundException(QPID_MSG("Unrecognised xid " << convert(xid)));
} else {
work.erase(i);
}
@@ -120,7 +121,7 @@ DtxWorkRecord* DtxManager::createWork(const std::string& xid)
Mutex::ScopedLock locker(lock);
WorkMap::iterator i = work.find(xid);
if (i != work.end()) {
- throw NotAllowedException(QPID_MSG("Xid " << xid << " is already known (use 'join' to add work to an existing xid)"));
+ throw NotAllowedException(QPID_MSG("Xid " << convert(xid) << " is already known (use 'join' to add work to an existing xid)"));
} else {
std::string ncxid = xid; // Work around const correctness problems in ptr_map.
return ptr_map_ptr(work.insert(ncxid, new DtxWorkRecord(ncxid, store)).first);
@@ -175,3 +176,19 @@ void DtxManager::setStore (TransactionalStore* _store)
{
store = _store;
}
+
+std::string DtxManager::convert(const qpid::framing::Xid& xid)
+{
+ qpid::framing::StructHelper helper;
+ std::string encoded;
+ helper.encode(xid, encoded);
+ return encoded;
+}
+
+qpid::framing::Xid DtxManager::convert(const std::string& xid)
+{
+ qpid::framing::StructHelper helper;
+ qpid::framing::Xid decoded;
+ helper.decode(decoded, xid);
+ return decoded;
+}
diff --git a/cpp/src/qpid/broker/DtxManager.h b/cpp/src/qpid/broker/DtxManager.h
index 11895695a3..6f03189f66 100644
--- a/cpp/src/qpid/broker/DtxManager.h
+++ b/cpp/src/qpid/broker/DtxManager.h
@@ -26,6 +26,7 @@
#include "qpid/broker/DtxWorkRecord.h"
#include "qpid/broker/TransactionalStore.h"
#include "qpid/framing/amqp_types.h"
+#include "qpid/framing/Xid.h"
#include "qpid/sys/Mutex.h"
#include "qpid/ptr_map.h"
@@ -74,6 +75,8 @@ public:
}
DtxWorkRecord* getWork(const std::string& xid);
bool exists(const std::string& xid);
+ static std::string convert(const framing::Xid& xid);
+ static framing::Xid convert(const std::string& xid);
};
}
diff --git a/cpp/src/qpid/broker/DtxWorkRecord.cpp b/cpp/src/qpid/broker/DtxWorkRecord.cpp
index a413fe418d..2c26fec49f 100644
--- a/cpp/src/qpid/broker/DtxWorkRecord.cpp
+++ b/cpp/src/qpid/broker/DtxWorkRecord.cpp
@@ -19,6 +19,7 @@
*
*/
#include "qpid/broker/DtxWorkRecord.h"
+#include "qpid/broker/DtxManager.h"
#include "qpid/framing/reply_exceptions.h"
#include <boost/format.hpp>
#include <boost/mem_fn.hpp>
@@ -73,7 +74,7 @@ bool DtxWorkRecord::commit(bool onePhase)
if (prepared) {
//already prepared i.e. 2pc
if (onePhase) {
- throw IllegalStateException(QPID_MSG("Branch with xid " << xid << " has been prepared, one-phase option not valid!"));
+ throw IllegalStateException(QPID_MSG("Branch with xid " << DtxManager::convert(xid) << " has been prepared, one-phase option not valid!"));
}
store->commit(*txn);
@@ -84,7 +85,7 @@ bool DtxWorkRecord::commit(bool onePhase)
} else {
//1pc commit optimisation, don't need a 2pc transaction context:
if (!onePhase) {
- throw IllegalStateException(QPID_MSG("Branch with xid " << xid << " has not been prepared, one-phase option required!"));
+ throw IllegalStateException(QPID_MSG("Branch with xid " << DtxManager::convert(xid) << " has not been prepared, one-phase option required!"));
}
std::auto_ptr<TransactionContext> localtxn = store->begin();
if (prepare(localtxn.get())) {
@@ -116,10 +117,10 @@ void DtxWorkRecord::add(DtxBuffer::shared_ptr ops)
{
Mutex::ScopedLock locker(lock);
if (expired) {
- throw DtxTimeoutException(QPID_MSG("Branch with xid " << xid << " has timed out."));
+ throw DtxTimeoutException(QPID_MSG("Branch with xid " << DtxManager::convert(xid) << " has timed out."));
}
if (completed) {
- throw CommandInvalidException(QPID_MSG("Branch with xid " << xid << " has been completed!"));
+ throw CommandInvalidException(QPID_MSG("Branch with xid " << DtxManager::convert(xid) << " has been completed!"));
}
work.push_back(ops);
}
@@ -133,7 +134,7 @@ bool DtxWorkRecord::check()
//iterate through all DtxBuffers and ensure they are all ended
for (Work::iterator i = work.begin(); i != work.end(); i++) {
if (!(*i)->isEnded()) {
- throw IllegalStateException(QPID_MSG("Branch with xid " << xid << " not completed!"));
+ throw IllegalStateException(QPID_MSG("Branch with xid " << DtxManager::convert(xid) << " not completed!"));
} else if ((*i)->isRollbackOnly()) {
rolledback = true;
}
diff --git a/cpp/src/qpid/broker/Exchange.cpp b/cpp/src/qpid/broker/Exchange.cpp
index ecaa492903..8d20b0df81 100644
--- a/cpp/src/qpid/broker/Exchange.cpp
+++ b/cpp/src/qpid/broker/Exchange.cpp
@@ -32,7 +32,9 @@
#include "qpid/sys/ExceptionHolder.h"
#include <stdexcept>
-using namespace qpid::broker;
+namespace qpid {
+namespace broker {
+
using namespace qpid::framing;
using qpid::framing::Buffer;
using qpid::framing::FieldTable;
@@ -135,20 +137,23 @@ void Exchange::doRoute(Deliverable& msg, ConstBindingList b)
if (mgmtExchange != 0)
{
- mgmtExchange->inc_msgReceives ();
- mgmtExchange->inc_byteReceives (msg.contentSize ());
+ qmf::org::apache::qpid::broker::Exchange::PerThreadStats *eStats = mgmtExchange->getStatistics();
+ uint64_t contentSize = msg.contentSize();
+
+ eStats->msgReceives += 1;
+ eStats->byteReceives += contentSize;
if (count == 0)
{
//QPID_LOG(warning, "Exchange " << getName() << " could not route message; no matching binding found");
- mgmtExchange->inc_msgDrops ();
- mgmtExchange->inc_byteDrops (msg.contentSize ());
+ eStats->msgDrops += 1;
+ eStats->byteDrops += contentSize;
if (brokerMgmtObject)
brokerMgmtObject->inc_discardsNoRoute();
}
else
{
- mgmtExchange->inc_msgRoutes (count);
- mgmtExchange->inc_byteRoutes (count * msg.contentSize ());
+ eStats->msgRoutes += count;
+ eStats->byteRoutes += count * contentSize;
}
}
}
@@ -156,7 +161,7 @@ void Exchange::doRoute(Deliverable& msg, ConstBindingList b)
void Exchange::routeIVE(){
if (ive && lastMsg.get()){
DeliverableMessage dmsg(lastMsg);
- route(dmsg, lastMsg->getRoutingKey(), lastMsg->getApplicationHeaders());
+ route(dmsg);
}
}
@@ -399,9 +404,12 @@ void Exchange::setProperties(const boost::intrusive_ptr<Message>& msg) {
bool Exchange::routeWithAlternate(Deliverable& msg)
{
- route(msg, msg.getMessage().getRoutingKey(), msg.getMessage().getApplicationHeaders());
+ route(msg);
if (!msg.delivered && alternate) {
- alternate->route(msg, msg.getMessage().getRoutingKey(), msg.getMessage().getApplicationHeaders());
+ alternate->route(msg);
}
return msg.delivered;
}
+
+}}
+
diff --git a/cpp/src/qpid/broker/Exchange.h b/cpp/src/qpid/broker/Exchange.h
index 9179dd5c7c..7376f814ed 100644
--- a/cpp/src/qpid/broker/Exchange.h
+++ b/cpp/src/qpid/broker/Exchange.h
@@ -196,7 +196,7 @@ public:
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>&);
- virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0;
+ virtual void route(Deliverable& msg) = 0;
//PersistableExchange:
QPID_BROKER_EXTERN void setPersistenceId(uint64_t id) const;
diff --git a/cpp/src/qpid/broker/ExchangeRegistry.cpp b/cpp/src/qpid/broker/ExchangeRegistry.cpp
index fca77f7ddd..43d7268dfb 100644
--- a/cpp/src/qpid/broker/ExchangeRegistry.cpp
+++ b/cpp/src/qpid/broker/ExchangeRegistry.cpp
@@ -24,6 +24,7 @@
#include "qpid/broker/FanOutExchange.h"
#include "qpid/broker/HeadersExchange.h"
#include "qpid/broker/TopicExchange.h"
+#include "qpid/broker/Link.h"
#include "qpid/management/ManagementDirectExchange.h"
#include "qpid/management/ManagementTopicExchange.h"
#include "qpid/framing/reply_exceptions.h"
@@ -58,6 +59,8 @@ pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, c
exchange = Exchange::shared_ptr(new ManagementDirectExchange(name, durable, args, parent, broker));
}else if (type == ManagementTopicExchange::typeName) {
exchange = Exchange::shared_ptr(new ManagementTopicExchange(name, durable, args, parent, broker));
+ }else if (type == Link::exchangeTypeName) {
+ exchange = Link::linkExchangeFactory(name);
}else{
FunctionMap::iterator i = factory.find(type);
if (i == factory.end()) {
diff --git a/cpp/src/qpid/broker/ExchangeRegistry.h b/cpp/src/qpid/broker/ExchangeRegistry.h
index 90ef81b49e..27b705fbe5 100644
--- a/cpp/src/qpid/broker/ExchangeRegistry.h
+++ b/cpp/src/qpid/broker/ExchangeRegistry.h
@@ -54,7 +54,7 @@ class ExchangeRegistry{
bool durable,
const qpid::framing::FieldTable& args = framing::FieldTable());
QPID_BROKER_EXTERN void destroy(const std::string& name);
- Exchange::shared_ptr getDefault();
+ QPID_BROKER_EXTERN Exchange::shared_ptr getDefault();
/**
* Find the named exchange. Return 0 if not found.
@@ -75,7 +75,7 @@ class ExchangeRegistry{
/** Register an exchange instance.
*@return true if registered, false if exchange with same name is already registered.
*/
- bool registerExchange(const Exchange::shared_ptr&);
+ QPID_BROKER_EXTERN bool registerExchange(const Exchange::shared_ptr&);
QPID_BROKER_EXTERN void registerType(const std::string& type, FactoryFunction);
@@ -85,7 +85,7 @@ class ExchangeRegistry{
for (ExchangeMap::const_iterator i = exchanges.begin(); i != exchanges.end(); ++i)
f(i->second);
}
-
+
private:
typedef std::map<std::string, Exchange::shared_ptr> ExchangeMap;
typedef std::map<std::string, FactoryFunction > FunctionMap;
diff --git a/cpp/src/qpid/broker/Fairshare.cpp b/cpp/src/qpid/broker/Fairshare.cpp
index 313aa746f1..7cdad1a44f 100644
--- a/cpp/src/qpid/broker/Fairshare.cpp
+++ b/cpp/src/qpid/broker/Fairshare.cpp
@@ -21,6 +21,7 @@
#include "qpid/broker/Fairshare.h"
#include "qpid/broker/QueuedMessage.h"
#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/log/Statement.h"
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
diff --git a/cpp/src/qpid/broker/FanOutExchange.cpp b/cpp/src/qpid/broker/FanOutExchange.cpp
index 5879fa0892..2bce99b6fe 100644
--- a/cpp/src/qpid/broker/FanOutExchange.cpp
+++ b/cpp/src/qpid/broker/FanOutExchange.cpp
@@ -101,7 +101,7 @@ bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*key*/, cons
return true;
}
-void FanOutExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* /*args*/)
+void FanOutExchange::route(Deliverable& msg)
{
PreRoute pr(msg, this);
doRoute(msg, bindings.snapshot());
diff --git a/cpp/src/qpid/broker/FanOutExchange.h b/cpp/src/qpid/broker/FanOutExchange.h
index 1a7d486796..c979fdca25 100644
--- a/cpp/src/qpid/broker/FanOutExchange.h
+++ b/cpp/src/qpid/broker/FanOutExchange.h
@@ -54,9 +54,7 @@ class FanOutExchange : public virtual Exchange {
virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
- QPID_BROKER_EXTERN virtual void route(Deliverable& msg,
- const std::string& routingKey,
- const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual void route(Deliverable& msg);
QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue,
const std::string* const routingKey,
diff --git a/cpp/src/qpid/broker/HeadersExchange.cpp b/cpp/src/qpid/broker/HeadersExchange.cpp
index 142c23f276..6648ae0422 100644
--- a/cpp/src/qpid/broker/HeadersExchange.cpp
+++ b/cpp/src/qpid/broker/HeadersExchange.cpp
@@ -191,8 +191,9 @@ bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey,
}
-void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args)
+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) {
diff --git a/cpp/src/qpid/broker/HeadersExchange.h b/cpp/src/qpid/broker/HeadersExchange.h
index 3b939d6851..d10892b9cc 100644
--- a/cpp/src/qpid/broker/HeadersExchange.h
+++ b/cpp/src/qpid/broker/HeadersExchange.h
@@ -98,9 +98,7 @@ class HeadersExchange : public virtual Exchange {
virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
- QPID_BROKER_EXTERN virtual void route(Deliverable& msg,
- const std::string& routingKey,
- const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual void route(Deliverable& msg);
QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue,
const std::string* const routingKey,
diff --git a/cpp/src/qpid/broker/LegacyLVQ.cpp b/cpp/src/qpid/broker/LegacyLVQ.cpp
index 49c0a32c19..f1deddf4c8 100644
--- a/cpp/src/qpid/broker/LegacyLVQ.cpp
+++ b/cpp/src/qpid/broker/LegacyLVQ.cpp
@@ -28,16 +28,26 @@ 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) {
+ if (i != messages.end() && i->second.payload == message.payload && i->second.status == QueuedMessage::AVAILABLE) {
+ i->second.status = QueuedMessage::ACQUIRED;
message = i->second;
- erase(i);
return true;
} else {
return false;
@@ -66,12 +76,17 @@ bool LegacyLVQ::push(const QueuedMessage& added, QueuedMessage& 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);
- i->second = update;
- i->second.position = original.position;
- return i->second;
+ 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)
diff --git a/cpp/src/qpid/broker/LegacyLVQ.h b/cpp/src/qpid/broker/LegacyLVQ.h
index 695e51131d..9355069f37 100644
--- a/cpp/src/qpid/broker/LegacyLVQ.h
+++ b/cpp/src/qpid/broker/LegacyLVQ.h
@@ -40,6 +40,7 @@ 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);
diff --git a/cpp/src/qpid/broker/Link.cpp b/cpp/src/qpid/broker/Link.cpp
index 4af1e6d6bd..f21c861149 100644
--- a/cpp/src/qpid/broker/Link.cpp
+++ b/cpp/src/qpid/broker/Link.cpp
@@ -31,6 +31,8 @@
#include "qpid/framing/enum.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/broker/AclModule.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/UrlArray.h"
namespace qpid {
namespace broker {
@@ -48,6 +50,13 @@ using std::stringstream;
using std::string;
namespace _qmf = ::qmf::org::apache::qpid::broker;
+
+namespace {
+ const std::string FAILOVER_EXCHANGE("amq.failover");
+ const std::string FAILOVER_HEADER_KEY("amq.failover");
+}
+
+
struct LinkTimerTask : public sys::TimerTask {
LinkTimerTask(Link& l, sys::Timer& t)
: TimerTask(int64_t(l.getBroker()->getOptions().linkMaintenanceInterval*
@@ -65,6 +74,57 @@ struct LinkTimerTask : public sys::TimerTask {
sys::Timer& timer;
};
+
+
+/** LinkExchange is used by the link to subscribe to the remote broker's amq.failover exchange.
+ */
+class LinkExchange : public broker::Exchange
+{
+public:
+ LinkExchange(const std::string& name) : Exchange(name), link(0) {}
+ ~LinkExchange() {};
+ std::string getType() const { return Link::exchangeTypeName; }
+
+ // Exchange methods - set up to prevent binding/unbinding etc from clients!
+ bool bind(boost::shared_ptr<broker::Queue>, const std::string&, const framing::FieldTable*) { return false; }
+ bool unbind(boost::shared_ptr<broker::Queue>, const std::string&, const framing::FieldTable*) { return false; }
+ bool isBound(boost::shared_ptr<broker::Queue>, const std::string* const, const framing::FieldTable* const) {return false;}
+
+ // 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)
+ {
+ if (!link) return;
+ const framing::FieldTable* headers = 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():
+ std::vector<Url> urlVec;
+ Url urls;
+ urlVec = urlArrayToVector(addresses);
+ for(size_t i = 0; i < urlVec.size(); ++i)
+ urls.insert(urls.end(), urlVec[i].begin(), urlVec[i].end());
+ QPID_LOG(debug, "Remote broker has provided these failover addresses= " << urls);
+ link->setUrl(urls);
+ }
+ }
+
+ void setLink(Link *_link)
+ {
+ assert(!link);
+ link = _link;
+ }
+
+private:
+ Link *link;
+};
+
+
+boost::shared_ptr<Exchange> Link::linkExchangeFactory( const std::string& _name )
+{
+ return Exchange::shared_ptr(new LinkExchange(_name));
+}
+
Link::Link(LinkRegistry* _links,
MessageStore* _store,
const string& _host,
@@ -76,8 +136,9 @@ Link::Link(LinkRegistry* _links,
const string& _password,
Broker* _broker,
Manageable* parent)
- : links(_links), store(_store), host(_host), port(_port),
- transport(_transport),
+ : links(_links), store(_store),
+ configuredTransport(_transport), configuredHost(_host), configuredPort(_port),
+ host(_host), port(_port), transport(_transport),
durable(_durable),
authMechanism(_authMechanism), username(_username), password(_password),
persistenceId(0), mgmtObject(0), broker(_broker), state(0),
@@ -88,7 +149,8 @@ Link::Link(LinkRegistry* _links,
channelCounter(1),
connection(0),
agent(0),
- timerTask(new LinkTimerTask(*this, broker->getTimer()))
+ timerTask(new LinkTimerTask(*this, broker->getTimer())),
+ failoverChannel(0)
{
if (parent != 0 && broker != 0)
{
@@ -106,15 +168,26 @@ Link::Link(LinkRegistry* _links,
startConnectionLH();
}
broker->getTimer().add(timerTask);
+
+ stringstream _name;
+ _name << "qpid.link." << transport << ":" << host << ":" << port;
+ std::pair<Exchange::shared_ptr, bool> rc = broker->getExchanges().declare(_name.str(),
+ exchangeTypeName);
+ failoverExchange = boost::static_pointer_cast<LinkExchange>(rc.first);
+ assert(failoverExchange);
+ failoverExchange->setLink(this);
}
Link::~Link ()
{
- if (state == STATE_OPERATIONAL && connection != 0)
- connection->close(CLOSE_CODE_CONNECTION_FORCED, "closed by management");
+ if (state == STATE_OPERATIONAL && connection != 0) {
+ closeConnection("closed by management");
+ }
if (mgmtObject != 0)
mgmtObject->resourceDestroy ();
+
+ broker->getExchanges().destroy(failoverExchange->getName());
}
void Link::setStateLH (int newState)
@@ -180,11 +253,21 @@ void Link::established(Connection* c)
void Link::setUrl(const Url& u) {
+ QPID_LOG(info, "Setting remote broker failover addresses for link '" << getName() << "' to these urls: " << u);
Mutex::ScopedLock mutex(lock);
url = u;
reconnectNext = 0;
}
+
+namespace {
+ /** invoked when session used to subscribe to remote's amq.failover exchange detaches */
+ void sessionDetached(Link *link) {
+ QPID_LOG(debug, "detached from 'amq.failover' for link: " << link->getName());
+ }
+}
+
+
void Link::opened() {
Mutex::ScopedLock mutex(lock);
if (!connection) return;
@@ -198,37 +281,74 @@ void Link::opened() {
reconnectNext = 0;
QPID_LOG(debug, "Known hosts for peer of inter-broker link: " << url);
}
+
+ //
+ // attempt to subscribe to failover exchange for updates from remote
+ //
+
+ const std::string queueName = "qpid.link." + framing::Uuid(true).str();
+ failoverChannel = nextChannel();
+
+ SessionHandler& sessionHandler = connection->getChannel(failoverChannel);
+ sessionHandler.setDetachedCallback( boost::bind(&sessionDetached, this) );
+ failoverSession = queueName;
+ sessionHandler.attachAs(failoverSession);
+
+ framing::AMQP_ServerProxy remoteBroker(sessionHandler.out);
+
+ remoteBroker.getQueue().declare(queueName,
+ "", // alt-exchange
+ false, // passive
+ false, // durable
+ true, // exclusive
+ true, // auto-delete
+ FieldTable());
+ remoteBroker.getExchange().bind(queueName,
+ FAILOVER_EXCHANGE,
+ "", // no key
+ FieldTable());
+ remoteBroker.getMessage().subscribe(queueName,
+ failoverExchange->getName(),
+ 1, // implied-accept mode
+ 0, // pre-acquire mode
+ false, // exclusive
+ "", // resume-id
+ 0, // resume-ttl
+ FieldTable());
+ remoteBroker.getMessage().flow(failoverExchange->getName(), 0, 0xFFFFFFFF);
+ remoteBroker.getMessage().flow(failoverExchange->getName(), 1, 0xFFFFFFFF);
}
void Link::closed(int, std::string text)
{
- Mutex::ScopedLock mutex(lock);
- QPID_LOG (info, "Inter-broker link disconnected from " << host << ":" << port << " " << text);
-
- connection = 0;
+ bool isClosing = false;
+ {
+ Mutex::ScopedLock mutex(lock);
+ QPID_LOG (info, "Inter-broker link disconnected from " << host << ":" << port << " " << text);
- if (state == STATE_OPERATIONAL) {
- stringstream addr;
- addr << host << ":" << port;
- QPID_LOG(warning, "Inter-broker link disconnected from " << addr.str());
- if (!hideManagement() && agent)
- agent->raiseEvent(_qmf::EventBrokerLinkDown(addr.str()));
- }
+ connection = 0;
+ if (state == STATE_OPERATIONAL) {
+ stringstream addr;
+ addr << host << ":" << port;
+ if (!hideManagement() && agent)
+ agent->raiseEvent(_qmf::EventBrokerLinkDown(addr.str()));
+ }
- for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
- (*i)->closed();
- created.push_back(*i);
- }
- active.clear();
+ for (Bridges::iterator i = active.begin(); i != active.end(); i++) {
+ (*i)->closed();
+ created.push_back(*i);
+ }
+ active.clear();
- if (state != STATE_FAILED && state != STATE_PASSIVE)
- {
- setStateLH(STATE_WAITING);
- if (!hideManagement())
- mgmtObject->set_lastError (text);
+ if (state != STATE_FAILED && state != STATE_PASSIVE)
+ {
+ setStateLH(STATE_WAITING);
+ if (!hideManagement())
+ mgmtObject->set_lastError (text);
+ }
}
-
- if (closing)
+ // Call destroy outside of the lock, don't want to be deleted with lock held.
+ if (isClosing)
destroy();
}
@@ -239,10 +359,8 @@ void Link::destroy ()
{
Mutex::ScopedLock mutex(lock);
- QPID_LOG (info, "Inter-broker link to " << host << ":" << port << " removed by management");
- if (connection)
- connection->close(CLOSE_CODE_CONNECTION_FORCED, "closed by management");
- connection = 0;
+ QPID_LOG (info, "Inter-broker link to " << configuredHost << ":" << configuredPort << " removed by management");
+ closeConnection("closed by management");
setStateLH(STATE_CLOSED);
// Move the bridges to be deleted into a local vector so there is no
@@ -263,7 +381,7 @@ void Link::destroy ()
for (Bridges::iterator i = toDelete.begin(); i != toDelete.end(); i++)
(*i)->destroy();
toDelete.clear();
- links->destroy (host, port);
+ links->destroy (configuredHost, configuredPort);
}
void Link::add(Bridge::shared_ptr bridge)
@@ -311,7 +429,7 @@ void Link::ioThreadProcessing()
// check for bridge session errors and recover
if (!active.empty()) {
Bridges::iterator removed = std::remove_if(
- active.begin(), active.end(), !boost::bind(&Bridge::isSessionReady, _1));
+ active.begin(), active.end(), boost::bind(&Bridge::isDetached, _1));
for (Bridges::iterator i = removed; i != active.end(); ++i) {
Bridge::shared_ptr bridge = *i;
bridge->closed();
@@ -398,14 +516,14 @@ bool Link::hideManagement() const {
uint Link::nextChannel()
{
Mutex::ScopedLock mutex(lock);
-
+ if (channelCounter >= framing::CHANNEL_MAX)
+ channelCounter = 1;
return channelCounter++;
}
void Link::notifyConnectionForced(const string text)
{
Mutex::ScopedLock mutex(lock);
-
setStateLH(STATE_FAILED);
if (!hideManagement())
mgmtObject->set_lastError(text);
@@ -418,7 +536,7 @@ void Link::setPersistenceId(uint64_t id) const
const string& Link::getName() const
{
- return host;
+ return configuredHost;
}
Link::shared_ptr Link::decode(LinkRegistry& links, Buffer& buffer)
@@ -444,9 +562,9 @@ Link::shared_ptr Link::decode(LinkRegistry& links, Buffer& buffer)
void Link::encode(Buffer& buffer) const
{
buffer.putShortString(string("link"));
- buffer.putShortString(host);
- buffer.putShort(port);
- buffer.putShortString(transport);
+ buffer.putShortString(configuredHost);
+ buffer.putShort(configuredPort);
+ buffer.putShortString(configuredTransport);
buffer.putOctet(durable ? 1 : 0);
buffer.putShortString(authMechanism);
buffer.putShortString(username);
@@ -455,10 +573,10 @@ void Link::encode(Buffer& buffer) const
uint32_t Link::encodedSize() const
{
- return host.size() + 1 // short-string (host)
+ return configuredHost.size() + 1 // short-string (host)
+ 5 // short-string ("link")
+ 2 // port
- + transport.size() + 1 // short-string(transport)
+ + configuredTransport.size() + 1 // short-string(transport)
+ 1 // durable
+ authMechanism.size() + 1
+ username.size() + 1
@@ -513,7 +631,7 @@ Manageable::status_t Link::ManagementMethod (uint32_t op, Args& args, string& te
}
std::pair<Bridge::shared_ptr, bool> result =
- links->declare (host, port, iargs.i_durable, iargs.i_src,
+ links->declare (configuredHost, configuredPort, iargs.i_durable, iargs.i_src,
iargs.i_dest, iargs.i_key, iargs.i_srcIsQueue,
iargs.i_srcIsLocal, iargs.i_tag, iargs.i_excludes,
iargs.i_dynamic, iargs.i_sync);
@@ -542,4 +660,63 @@ void Link::setPassive(bool passive)
}
}
+
+/** utility to clean up connection resources correctly */
+void Link::closeConnection( const std::string& reason)
+{
+ if (connection != 0) {
+ // cancel our subscription to the failover exchange
+ SessionHandler& sessionHandler = connection->getChannel(failoverChannel);
+ if (sessionHandler.getSession()) {
+ framing::AMQP_ServerProxy remoteBroker(sessionHandler.out);
+ remoteBroker.getMessage().cancel(failoverExchange->getName());
+ remoteBroker.getSession().detach(failoverSession);
+ }
+ connection->close(CLOSE_CODE_CONNECTION_FORCED, reason);
+ connection = 0;
+ }
+}
+
+/** returns the current remote's address, and connection state */
+bool Link::getRemoteAddress(qpid::Address& addr) const
+{
+ addr.protocol = transport;
+ addr.host = host;
+ addr.port = port;
+
+ return state == STATE_OPERATIONAL;
+}
+
+
+// FieldTable keys for internal state data
+namespace {
+ const std::string FAILOVER_ADDRESSES("failover-addresses");
+ const std::string FAILOVER_INDEX("failover-index");
+}
+
+void Link::getState(framing::FieldTable& state) const
+{
+ state.clear();
+ Mutex::ScopedLock mutex(lock);
+ if (!url.empty()) {
+ state.setString(FAILOVER_ADDRESSES, url.str());
+ state.setInt(FAILOVER_INDEX, reconnectNext);
+ }
+}
+
+void Link::setState(const framing::FieldTable& state)
+{
+ Mutex::ScopedLock mutex(lock);
+ if (state.isSet(FAILOVER_ADDRESSES)) {
+ Url failovers(state.getAsString(FAILOVER_ADDRESSES));
+ setUrl(failovers);
+ }
+ if (state.isSet(FAILOVER_INDEX)) {
+ reconnectNext = state.getAsInt(FAILOVER_INDEX);
+ }
+}
+
+
+const std::string Link::exchangeTypeName("qpid.LinkExchange");
+
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/Link.h b/cpp/src/qpid/broker/Link.h
index 4085c3bfcf..a97fa48664 100644
--- a/cpp/src/qpid/broker/Link.h
+++ b/cpp/src/qpid/broker/Link.h
@@ -24,9 +24,11 @@
#include <boost/shared_ptr.hpp>
#include "qpid/Url.h"
+#include "qpid/broker/BrokerImportExport.h"
#include "qpid/broker/MessageStore.h"
#include "qpid/broker/PersistableConfig.h"
#include "qpid/broker/Bridge.h"
+#include "qpid/broker/BrokerImportExport.h"
#include "qpid/sys/Mutex.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/management/Manageable.h"
@@ -45,15 +47,23 @@ namespace broker {
class LinkRegistry;
class Broker;
class Connection;
+class LinkExchange;
class Link : public PersistableConfig, public management::Manageable {
private:
- sys::Mutex lock;
+ mutable sys::Mutex lock;
LinkRegistry* links;
MessageStore* store;
- std::string host;
- uint16_t port;
- std::string transport;
+
+ // these remain constant across failover - used to identify this link
+ const std::string configuredTransport;
+ const std::string configuredHost;
+ const uint16_t configuredPort;
+ // these reflect the current address of remote - will change during failover
+ std::string host;
+ uint16_t port;
+ std::string transport;
+
bool durable;
std::string authMechanism;
std::string username;
@@ -75,8 +85,10 @@ class Link : public PersistableConfig, public management::Manageable {
uint channelCounter;
Connection* connection;
management::ManagementAgent* agent;
-
boost::intrusive_ptr<sys::TimerTask> timerTask;
+ boost::shared_ptr<broker::LinkExchange> failoverExchange; // subscribed to remote's amq.failover exchange
+ uint failoverChannel;
+ std::string failoverSession;
static const int STATE_WAITING = 1;
static const int STATE_CONNECTING = 2;
@@ -94,6 +106,14 @@ class Link : public PersistableConfig, public management::Manageable {
bool tryFailoverLH(); // Called during maintenance visit
bool hideManagement() const;
+ void established(Connection*); // Called when connection is create
+ void opened(); // Called when connection is open (after create)
+ void closed(int, std::string); // Called when connection goes away
+ void reconnectLH(const Address&); //called by LinkRegistry
+ void closeConnection(const std::string& reason);
+
+ friend class LinkRegistry; // to call established, opened, closed
+
public:
typedef boost::shared_ptr<Link> shared_ptr;
@@ -110,22 +130,25 @@ class Link : public PersistableConfig, public management::Manageable {
management::Manageable* parent = 0);
virtual ~Link();
- std::string getHost() { return host; }
- uint16_t getPort() { return port; }
- std::string getTransport() { return transport; }
+ /** these return the *configured* transport/host/port, which does not change over the
+ lifetime of the Link */
+ std::string getHost() const { return configuredHost; }
+ uint16_t getPort() const { return configuredPort; }
+ std::string getTransport() const { return configuredTransport; }
+
+ /** returns the current address of the remote, which may be different from the
+ configured transport/host/port due to failover. Returns true if connection is
+ active */
+ bool getRemoteAddress(qpid::Address& addr) const;
bool isDurable() { return durable; }
void maintenanceVisit ();
uint nextChannel();
void add(Bridge::shared_ptr);
void cancel(Bridge::shared_ptr);
- void setUrl(const Url&); // Set URL for reconnection.
- void established(Connection*); // Called when connection is create
- void opened(); // Called when connection is open (after create)
- void closed(int, std::string); // Called when connection goes away
- void reconnectLH(const Address&); //called by LinkRegistry
- void close(); // Close the link from within the broker.
+ QPID_BROKER_EXTERN void setUrl(const Url&); // Set URL for reconnection.
+ QPID_BROKER_EXTERN void close(); // Close the link from within the broker.
std::string getAuthMechanism() { return authMechanism; }
std::string getUsername() { return username; }
@@ -148,6 +171,13 @@ class Link : public PersistableConfig, public management::Manageable {
management::ManagementObject* GetManagementObject(void) const;
management::Manageable::status_t ManagementMethod(uint32_t, management::Args&, std::string&);
+ // manage the exchange owned by this link
+ static const std::string exchangeTypeName;
+ static boost::shared_ptr<Exchange> linkExchangeFactory(const std::string& name);
+
+ // replicate internal state of this Link for clustering
+ void getState(framing::FieldTable& state) const;
+ void setState(const framing::FieldTable& state);
};
}
}
diff --git a/cpp/src/qpid/broker/LinkRegistry.cpp b/cpp/src/qpid/broker/LinkRegistry.cpp
index bb602bb953..d89f220d1b 100644
--- a/cpp/src/qpid/broker/LinkRegistry.cpp
+++ b/cpp/src/qpid/broker/LinkRegistry.cpp
@@ -25,7 +25,9 @@
#include <iostream>
#include <boost/format.hpp>
-using namespace qpid::broker;
+namespace qpid {
+namespace broker {
+
using namespace qpid::sys;
using std::string;
using std::pair;
@@ -45,16 +47,15 @@ LinkRegistry::LinkRegistry () :
{
}
-namespace {
-struct ConnectionObserverImpl : public ConnectionObserver {
+class LinkRegistryConnectionObserver : public ConnectionObserver {
LinkRegistry& links;
- ConnectionObserverImpl(LinkRegistry& l) : links(l) {}
+ public:
+ LinkRegistryConnectionObserver(LinkRegistry& l) : links(l) {}
void connection(Connection& c) { links.notifyConnection(c.getMgmtId(), &c); }
void opened(Connection& c) { links.notifyOpened(c.getMgmtId()); }
void closed(Connection& c) { links.notifyClosed(c.getMgmtId()); }
void forced(Connection& c, const string& text) { links.notifyConnectionForced(c.getMgmtId(), text); }
};
-}
LinkRegistry::LinkRegistry (Broker* _broker) :
broker(_broker),
@@ -62,7 +63,7 @@ LinkRegistry::LinkRegistry (Broker* _broker) :
realm(broker->getOptions().realm)
{
broker->getConnectionObservers().add(
- boost::shared_ptr<ConnectionObserver>(new ConnectionObserverImpl(*this)));
+ boost::shared_ptr<ConnectionObserver>(new LinkRegistryConnectionObserver(*this)));
}
LinkRegistry::~LinkRegistry() {}
@@ -298,22 +299,29 @@ std::string LinkRegistry::getUsername(const std::string& key)
return link->getUsername();
}
+/** note: returns the current remote host (may be different from the host originally
+ configured for the Link due to failover) */
std::string LinkRegistry::getHost(const std::string& key)
{
- Link::shared_ptr link = findLink(key);
- if (!link)
- return string();
+ Link::shared_ptr link = findLink(key);
+ if (!link)
+ return string();
- return link->getHost();
+ qpid::Address addr;
+ link->getRemoteAddress(addr);
+ return addr.host;
}
+/** returns the current remote port (ditto above) */
uint16_t LinkRegistry::getPort(const std::string& key)
{
Link::shared_ptr link = findLink(key);
if (!link)
return 0;
- return link->getPort();
+ qpid::Address addr;
+ link->getRemoteAddress(addr);
+ return addr.port;
}
std::string LinkRegistry::getPassword(const std::string& key)
@@ -368,3 +376,4 @@ void LinkRegistry::eachBridge(boost::function<void(boost::shared_ptr<Bridge>)> f
for (BridgeMap::iterator i = bridges.begin(); i != bridges.end(); ++i) f(i->second);
}
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/LinkRegistry.h b/cpp/src/qpid/broker/LinkRegistry.h
index 753f6bfe9e..8e9d2f4b0d 100644
--- a/cpp/src/qpid/broker/LinkRegistry.h
+++ b/cpp/src/qpid/broker/LinkRegistry.h
@@ -23,6 +23,7 @@
*/
#include <map>
+#include "qpid/broker/BrokerImportExport.h"
#include "qpid/broker/Bridge.h"
#include "qpid/broker/MessageStore.h"
#include "qpid/Address.h"
@@ -56,43 +57,50 @@ namespace broker {
static std::string createKey(const Address& address);
static std::string createKey(const std::string& host, uint16_t port);
+ // Methods called by the connection observer.
+ void notifyConnection (const std::string& key, Connection* c);
+ void notifyOpened (const std::string& key);
+ void notifyClosed (const std::string& key);
+ void notifyConnectionForced (const std::string& key, const std::string& text);
+ friend class LinkRegistryConnectionObserver;
+
public:
- LinkRegistry (); // Only used in store tests
- LinkRegistry (Broker* _broker);
- ~LinkRegistry();
-
- std::pair<boost::shared_ptr<Link>, bool>
- declare(const std::string& host,
- uint16_t port,
- const std::string& transport,
- bool durable,
- const std::string& authMechanism,
- const std::string& username,
- const std::string& password);
-
- std::pair<Bridge::shared_ptr, bool>
- declare(const std::string& host,
- uint16_t port,
- bool durable,
- const std::string& src,
- const std::string& dest,
- const std::string& key,
- bool isQueue,
- bool isLocal,
- const std::string& id,
- const std::string& excludes,
- bool dynamic,
- uint16_t sync,
- Bridge::InitializeCallback=0
- );
-
- void destroy(const std::string& host, const uint16_t port);
-
- void destroy(const std::string& host,
- const uint16_t port,
- const std::string& src,
- const std::string& dest,
- const std::string& key);
+ QPID_BROKER_EXTERN LinkRegistry (); // Only used in store tests
+ QPID_BROKER_EXTERN LinkRegistry (Broker* _broker);
+ QPID_BROKER_EXTERN ~LinkRegistry();
+
+ QPID_BROKER_EXTERN std::pair<boost::shared_ptr<Link>, bool>
+ declare(const std::string& host,
+ uint16_t port,
+ const std::string& transport,
+ bool durable,
+ const std::string& authMechanism,
+ const std::string& username,
+ const std::string& password);
+
+ QPID_BROKER_EXTERN std::pair<Bridge::shared_ptr, bool>
+ declare(const std::string& host,
+ uint16_t port,
+ bool durable,
+ const std::string& src,
+ const std::string& dest,
+ const std::string& key,
+ bool isQueue,
+ bool isLocal,
+ const std::string& id,
+ const std::string& excludes,
+ bool dynamic,
+ uint16_t sync,
+ Bridge::InitializeCallback=0
+ );
+
+ QPID_BROKER_EXTERN void destroy(const std::string& host, const uint16_t port);
+
+ QPID_BROKER_EXTERN void destroy(const std::string& host,
+ const uint16_t port,
+ const std::string& src,
+ const std::string& dest,
+ const std::string& key);
/**
* Register the manageable parent for declared queues
@@ -102,24 +110,20 @@ namespace broker {
/**
* Set the store to use. May only be called once.
*/
- void setStore (MessageStore*);
+ QPID_BROKER_EXTERN void setStore (MessageStore*);
/**
* Return the message store used.
*/
- MessageStore* getStore() const;
+ QPID_BROKER_EXTERN MessageStore* getStore() const;
- void notifyConnection (const std::string& key, Connection* c);
- void notifyOpened (const std::string& key);
- void notifyClosed (const std::string& key);
- void notifyConnectionForced (const std::string& key, const std::string& text);
- std::string getAuthMechanism (const std::string& key);
- std::string getAuthCredentials (const std::string& key);
- std::string getAuthIdentity (const std::string& key);
- std::string getUsername (const std::string& key);
- std::string getPassword (const std::string& key);
- std::string getHost (const std::string& key);
- uint16_t getPort (const std::string& key);
+ QPID_BROKER_EXTERN std::string getAuthMechanism (const std::string& key);
+ QPID_BROKER_EXTERN std::string getAuthCredentials (const std::string& key);
+ QPID_BROKER_EXTERN std::string getAuthIdentity (const std::string& key);
+ QPID_BROKER_EXTERN std::string getUsername (const std::string& key);
+ QPID_BROKER_EXTERN std::string getPassword (const std::string& key);
+ QPID_BROKER_EXTERN std::string getHost (const std::string& key);
+ QPID_BROKER_EXTERN uint16_t getPort (const std::string& key);
/**
* Called by links failing over to new address
@@ -132,13 +136,13 @@ namespace broker {
* updated but links won't actually establish connections and
* bridges won't therefore pull or push any messages.
*/
- void setPassive(bool);
- bool isPassive() { return passive; }
+ QPID_BROKER_EXTERN void setPassive(bool);
+ QPID_BROKER_EXTERN bool isPassive() { return passive; }
/** Iterate over each link in the registry. Used for cluster updates. */
- void eachLink(boost::function<void(boost::shared_ptr<Link>)> f);
+ QPID_BROKER_EXTERN void eachLink(boost::function<void(boost::shared_ptr<Link>)> f);
/** Iterate over each bridge in the registry. Used for cluster updates. */
- void eachBridge(boost::function<void(boost::shared_ptr< Bridge>)> f);
+ QPID_BROKER_EXTERN void eachBridge(boost::function<void(boost::shared_ptr< Bridge>)> f);
};
}
}
diff --git a/cpp/src/qpid/broker/Message.cpp b/cpp/src/qpid/broker/Message.cpp
index ae4503328a..40dfba39f4 100644
--- a/cpp/src/qpid/broker/Message.cpp
+++ b/cpp/src/qpid/broker/Message.cpp
@@ -131,6 +131,7 @@ uint32_t Message::getRequiredCredit()
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>());
@@ -142,6 +143,7 @@ void Message::encode(framing::Buffer& buffer) const
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>());
@@ -154,11 +156,13 @@ uint32_t Message::encodedSize() const
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>());
@@ -218,8 +222,9 @@ void Message::releaseContent()
store->stage(pmsg);
staged = true;
}
- //ensure required credit is cached before content frames are released
+ //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();
@@ -354,6 +359,7 @@ public:
AMQHeaderBody* Message::getHeaderBody()
{
+ // expects lock to be held
if (copyHeaderOnWrite) {
CloneHeaderBody f;
frames.map_if(f, TypeFilter<HEADER_BODY>());
diff --git a/cpp/src/qpid/broker/MessageDeque.cpp b/cpp/src/qpid/broker/MessageDeque.cpp
index 709d99876b..f70c996975 100644
--- a/cpp/src/qpid/broker/MessageDeque.cpp
+++ b/cpp/src/qpid/broker/MessageDeque.cpp
@@ -21,6 +21,7 @@
#include "qpid/broker/MessageDeque.h"
#include "qpid/broker/QueuedMessage.h"
#include "qpid/log/Statement.h"
+#include "assert.h"
namespace qpid {
namespace broker {
@@ -39,7 +40,7 @@ size_t MessageDeque::index(const framing::SequenceNumber& position)
bool MessageDeque::deleted(const QueuedMessage& m)
{
size_t i = index(m.position);
- if (i < messages.size()) {
+ if (i < messages.size() && messages[i].status != QueuedMessage::DELETED) {
messages[i].status = QueuedMessage::DELETED;
clean();
return true;
@@ -53,7 +54,7 @@ size_t MessageDeque::size()
return available;
}
-void MessageDeque::release(const QueuedMessage& message)
+QueuedMessage* MessageDeque::releasePtr(const QueuedMessage& message)
{
size_t i = index(message.position);
if (i < messages.size()) {
@@ -62,12 +63,17 @@ void MessageDeque::release(const QueuedMessage& message)
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;
}
+void MessageDeque::release(const QueuedMessage& message) { releasePtr(message); }
+
bool MessageDeque::acquire(const framing::SequenceNumber& position, QueuedMessage& message)
{
if (position < messages.front().position) return false;
@@ -129,8 +135,7 @@ QueuedMessage padding(uint32_t pos) {
}
} // namespace
-bool MessageDeque::push(const QueuedMessage& added, QueuedMessage& /*not needed*/)
-{
+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)
@@ -139,7 +144,12 @@ bool MessageDeque::push(const QueuedMessage& added, QueuedMessage& /*not needed*
messages.back().status = QueuedMessage::AVAILABLE;
if (head >= messages.size()) head = messages.size() - 1;
++available;
- return false;//adding a message never causes one to be removed for deque
+ 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)
diff --git a/cpp/src/qpid/broker/MessageDeque.h b/cpp/src/qpid/broker/MessageDeque.h
index bb5943b09b..9b53716d4e 100644
--- a/cpp/src/qpid/broker/MessageDeque.h
+++ b/cpp/src/qpid/broker/MessageDeque.h
@@ -48,6 +48,12 @@ class MessageDeque : public Messages
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);
+
private:
typedef std::deque<QueuedMessage> Deque;
Deque messages;
@@ -55,7 +61,6 @@ class MessageDeque : public Messages
size_t head;
size_t index(const framing::SequenceNumber&);
- void clean();
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/MessageGroupManager.cpp b/cpp/src/qpid/broker/MessageGroupManager.cpp
index 5f450cd556..15cd56a676 100644
--- a/cpp/src/qpid/broker/MessageGroupManager.cpp
+++ b/cpp/src/qpid/broker/MessageGroupManager.cpp
@@ -19,11 +19,13 @@
*
*/
+#include "qpid/broker/MessageGroupManager.h"
+
+#include "qpid/broker/Queue.h"
#include "qpid/framing/FieldTable.h"
-#include "qpid/types/Variant.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/log/Statement.h"
-#include "qpid/broker/Queue.h"
-#include "qpid/broker/MessageGroupManager.h"
+#include "qpid/types/Variant.h"
using namespace qpid::broker;
@@ -43,9 +45,18 @@ const std::string MessageGroupManager::qpidSharedGroup("qpid.shared_msg_group");
const std::string MessageGroupManager::qpidMessageGroupTimestamp("qpid.group_timestamp");
+/** return an iterator to the message at position, or members.end() if not found */
+MessageGroupManager::GroupState::MessageFifo::iterator
+MessageGroupManager::GroupState::findMsg(const qpid::framing::SequenceNumber &position)
+{
+ MessageState mState(position);
+ MessageFifo::iterator found = std::lower_bound(members.begin(), members.end(), mState);
+ return (found->position == position) ? found : members.end();
+}
+
void MessageGroupManager::unFree( const GroupState& state )
{
- GroupFifo::iterator pos = freeGroups.find( state.members.front() );
+ GroupFifo::iterator pos = freeGroups.find( state.members.front().position );
assert( pos != freeGroups.end() && pos->second == &state );
freeGroups.erase( pos );
}
@@ -60,8 +71,8 @@ void MessageGroupManager::disown( GroupState& state )
{
state.owner.clear();
assert(state.members.size());
- assert(freeGroups.find(state.members.front()) == freeGroups.end());
- freeGroups[state.members.front()] = &state;
+ assert(freeGroups.find(state.members.front().position) == freeGroups.end());
+ freeGroups[state.members.front().position] = &state;
}
MessageGroupManager::GroupState& MessageGroupManager::findGroup( const QueuedMessage& qm )
@@ -106,7 +117,8 @@ void MessageGroupManager::enqueued( const QueuedMessage& qm )
// @todo KAG optimization - store reference to group state in QueuedMessage
// issue: const-ness??
GroupState& state = findGroup(qm);
- state.members.push_back(qm.position);
+ GroupState::MessageState mState(qm.position);
+ 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 );
@@ -123,7 +135,9 @@ void MessageGroupManager::acquired( const QueuedMessage& qm )
// @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage
// issue: const-ness??
GroupState& state = findGroup(qm);
- assert(state.members.size()); // there are msgs present
+ GroupState::MessageFifo::iterator m = state.findMsg(qm.position);
+ assert(m != state.members.end());
+ m->acquired = true;
state.acquired += 1;
QPID_LOG( trace, "group queue " << qName <<
": acquired message in group id=" << state.group << " acquired=" << state.acquired );
@@ -137,6 +151,9 @@ void MessageGroupManager::requeued( const QueuedMessage& qm )
GroupState& state = findGroup(qm);
assert( state.acquired != 0 );
state.acquired -= 1;
+ GroupState::MessageFifo::iterator m = state.findMsg(qm.position);
+ assert(m != state.members.end());
+ m->acquired = false;
if (state.acquired == 0 && state.owned()) {
QPID_LOG( trace, "group queue " << qName <<
": consumer name=" << state.owner << " released group id=" << state.group);
@@ -152,13 +169,17 @@ void MessageGroupManager::dequeued( const QueuedMessage& qm )
// @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage
// issue: const-ness??
GroupState& state = findGroup(qm);
- assert( state.members.size() != 0 );
- assert( state.acquired != 0 );
- state.acquired -= 1;
+ GroupState::MessageFifo::iterator m = state.findMsg(qm.position);
+ assert(m != state.members.end());
+ if (m->acquired) {
+ assert( state.acquired != 0 );
+ state.acquired -= 1;
+ }
- // likely to be at or near begin() if dequeued in order
+ // 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 (state.members.front() == qm.position) {
+ if (m == 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!
@@ -167,15 +188,7 @@ void MessageGroupManager::dequeued( const QueuedMessage& qm )
}
state.members.pop_front();
} else {
- GroupState::PositionFifo::iterator pos = state.members.begin() + 1;
- GroupState::PositionFifo::iterator end = state.members.end();
- while (pos != end) {
- if (*pos == qm.position) {
- state.members.erase(pos);
- break;
- }
- ++pos;
- }
+ state.members.erase(m);
}
uint32_t total = state.members.size();
@@ -220,11 +233,11 @@ bool MessageGroupManager::nextConsumableMessage( Consumer::shared_ptr& c, Queued
GroupState& group = findGroup(next);
if (!group.owned()) {
//TODO: make acquire more efficient when we already have the message in question
- if (group.members.front() == next.position && messages.acquire(next.position, next)) { // only take from head!
+ 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());
+ << "'s head message still pending. pos=" << group.members.front().position);
} else if (group.owner == c->getName() && messages.acquire(next.position, next)) {
return true;
}
@@ -284,7 +297,7 @@ void MessageGroupManager::query(qpid::types::Variant::Map& status) const
info[GROUP_TIMESTAMP] = 0;
if (g->second.members.size() != 0) {
QueuedMessage qm;
- if (messages.find(g->second.members.front(), 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();
@@ -353,6 +366,7 @@ namespace {
const std::string GROUP_OWNER("owner");
const std::string GROUP_ACQUIRED_CT("acquired-ct");
const std::string GROUP_POSITIONS("positions");
+ const std::string GROUP_ACQUIRED_MSGS("acquired-msgs");
const std::string GROUP_STATE("group-state");
}
@@ -371,10 +385,14 @@ void MessageGroupManager::getState(qpid::framing::FieldTable& state ) const
group.setString(GROUP_OWNER, g->second.owner);
group.setInt(GROUP_ACQUIRED_CT, g->second.acquired);
framing::Array positions(TYPE_CODE_UINT32);
- for (GroupState::PositionFifo::const_iterator p = g->second.members.begin();
- p != g->second.members.end(); ++p)
- positions.push_back(framing::Array::ValuePtr(new IntegerValue( *p )));
+ framing::Array acquiredMsgs(TYPE_CODE_BOOLEAN);
+ for (GroupState::MessageFifo::const_iterator p = g->second.members.begin();
+ p != g->second.members.end(); ++p) {
+ positions.push_back(framing::Array::ValuePtr(new IntegerValue( p->position )));
+ acquiredMsgs.push_back(framing::Array::ValuePtr(new BoolValue( p->acquired )));
+ }
group.setArray(GROUP_POSITIONS, positions);
+ group.setArray(GROUP_ACQUIRED_MSGS, acquiredMsgs);
groupState.push_back(framing::Array::ValuePtr(new FieldTableValue(group)));
}
state.setArray(GROUP_STATE, groupState);
@@ -425,13 +443,25 @@ void MessageGroupManager::setState(const qpid::framing::FieldTable& state)
qName << "\": position encoding error!");
return;
}
+ framing::Array acquiredMsgs(TYPE_CODE_BOOLEAN);
+ ok = group.getArray(GROUP_ACQUIRED_MSGS, acquiredMsgs);
+ if (!ok || positions.count() != acquiredMsgs.count()) {
+ QPID_LOG(error, "Invalid message group state information for queue \"" <<
+ qName << "\": acquired flag encoding error!");
+ return;
+ }
+
+ Array::const_iterator a = acquiredMsgs.begin();
+ for (Array::const_iterator p = positions.begin(); p != positions.end(); ++p) {
+ GroupState::MessageState mState((*p)->getIntegerValue<uint32_t, 4>());
+ mState.acquired = (*a++)->getIntegerValue<bool>();
+ state.members.push_back(mState);
+ }
- for (Array::const_iterator p = positions.begin(); p != positions.end(); ++p)
- state.members.push_back((*p)->getIntegerValue<uint32_t, 4>());
messageGroups[state.group] = state;
if (!state.owned()) {
assert(state.members.size());
- freeGroups[state.members.front()] = &messageGroups[state.group];
+ freeGroups[state.members.front().position] = &messageGroups[state.group];
}
}
diff --git a/cpp/src/qpid/broker/MessageGroupManager.h b/cpp/src/qpid/broker/MessageGroupManager.h
index f4bffc4760..2dd97ea2ff 100644
--- a/cpp/src/qpid/broker/MessageGroupManager.h
+++ b/cpp/src/qpid/broker/MessageGroupManager.h
@@ -28,11 +28,14 @@
#include "qpid/broker/MessageDistributor.h"
#include "qpid/sys/unordered_map.h"
+#include <deque>
+
namespace qpid {
namespace broker {
class QueueObserver;
class MessageDistributor;
+class Messages;
class MessageGroupManager : public StatefulQueueObserver, public MessageDistributor
{
@@ -45,19 +48,29 @@ class MessageGroupManager : public StatefulQueueObserver, public MessageDistribu
struct GroupState {
// note: update getState()/setState() when changing this object's state implementation
- typedef std::deque<framing::SequenceNumber> PositionFifo;
+
+ // track which messages are in this group, and if they have been acquired
+ struct MessageState {
+ qpid::framing::SequenceNumber position;
+ bool acquired;
+ MessageState() : acquired(false) {}
+ MessageState(const qpid::framing::SequenceNumber& p) : position(p), acquired(false) {}
+ bool operator<(const MessageState& b) const { return position < b.position; }
+ };
+ typedef std::deque<MessageState> MessageFifo;
std::string group; // group identifier
std::string owner; // consumer with outstanding acquired messages
uint32_t acquired; // count of outstanding acquired messages
- PositionFifo members; // msgs belonging to this group
+ MessageFifo members; // msgs belonging to this group, in enqueue order
GroupState() : acquired(0) {}
bool owned() const {return !owner.empty();}
+ MessageFifo::iterator findMsg(const qpid::framing::SequenceNumber &);
};
typedef sys::unordered_map<std::string, struct GroupState> GroupMap;
- typedef std::map<framing::SequenceNumber, struct GroupState *> GroupFifo;
+ typedef std::map<qpid::framing::SequenceNumber, struct GroupState *> GroupFifo;
GroupMap messageGroups; // index: group name
GroupFifo freeGroups; // ordered by oldest free msg
diff --git a/cpp/src/qpid/broker/MessageMap.cpp b/cpp/src/qpid/broker/MessageMap.cpp
index 048df45434..9b164d4e5c 100644
--- a/cpp/src/qpid/broker/MessageMap.cpp
+++ b/cpp/src/qpid/broker/MessageMap.cpp
@@ -20,6 +20,7 @@
*/
#include "qpid/broker/MessageMap.h"
#include "qpid/broker/QueuedMessage.h"
+#include "qpid/log/Statement.h"
namespace qpid {
namespace broker {
@@ -27,7 +28,16 @@ namespace {
const std::string EMPTY;
}
-bool MessageMap::deleted(const QueuedMessage&) { return true; }
+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)
{
@@ -38,30 +48,32 @@ std::string MessageMap::getKey(const QueuedMessage& message)
size_t MessageMap::size()
{
- return messages.size();
+ size_t count(0);
+ for (Ordering::iterator i = messages.begin(); i != messages.end(); ++i) {
+ if (i->second.status == QueuedMessage::AVAILABLE) ++count;
+ }
+ return count;
}
bool MessageMap::empty()
{
- return messages.empty();
+ return size() == 0;//TODO: more efficient implementation
}
void MessageMap::release(const QueuedMessage& message)
{
- std::string key = getKey(message);
- Index::iterator i = index.find(key);
- if (i == index.end()) {
- index[key] = message;
- messages[message.position] = message;
- } //else message has already been replaced
+ 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()) {
+ if (i != messages.end() && i->second.status == QueuedMessage::AVAILABLE) {
+ i->second.status = QueuedMessage::ACQUIRED;
message = i->second;
- erase(i);
return true;
} else {
return false;
@@ -71,7 +83,7 @@ bool MessageMap::acquire(const framing::SequenceNumber& position, QueuedMessage&
bool MessageMap::find(const framing::SequenceNumber& position, QueuedMessage& message)
{
Ordering::iterator i = messages.find(position);
- if (i != messages.end()) {
+ if (i != messages.end() && i->second.status == QueuedMessage::AVAILABLE) {
message = i->second;
return true;
} else {
@@ -79,10 +91,10 @@ bool MessageMap::find(const framing::SequenceNumber& position, QueuedMessage& me
}
}
-bool MessageMap::browse(const framing::SequenceNumber& position, QueuedMessage& message, bool)
+bool MessageMap::browse(const framing::SequenceNumber& position, QueuedMessage& message, bool unacquired)
{
Ordering::iterator i = messages.lower_bound(position+1);
- if (i != messages.end()) {
+ if (i != messages.end() && (i->second.status == QueuedMessage::AVAILABLE || (!unacquired && i->second.status == QueuedMessage::ACQUIRED))) {
message = i->second;
return true;
} else {
@@ -92,14 +104,14 @@ bool MessageMap::browse(const framing::SequenceNumber& position, QueuedMessage&
bool MessageMap::consume(QueuedMessage& message)
{
- Ordering::iterator i = messages.begin();
- if (i != messages.end()) {
- message = i->second;
- erase(i);
- return true;
- } else {
- return false;
+ 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;
+ }
}
+ return false;
}
const QueuedMessage& MessageMap::replace(const QueuedMessage& original, const QueuedMessage& update)
@@ -115,12 +127,17 @@ bool MessageMap::push(const QueuedMessage& added, QueuedMessage& removed)
if (result.second) {
//there was no previous message for this key; nothing needs to
//be removed, just add the message into its correct position
- messages[added.position] = added;
+ QueuedMessage& a = messages[added.position];
+ a = added;
+ a.status = QueuedMessage::AVAILABLE;
+ QPID_LOG(debug, "Added message at " << a.position);
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 at " << removed.position << " with " << result.first->second.position << ": " << result.first->first);
return true;
}
}
@@ -128,15 +145,24 @@ bool MessageMap::push(const QueuedMessage& added, QueuedMessage& removed)
void MessageMap::foreach(Functor f)
{
for (Ordering::iterator i = messages.begin(); i != messages.end(); ++i) {
- f(i->second);
+ if (i->second.status == QueuedMessage::AVAILABLE) f(i->second);
}
}
void MessageMap::removeIf(Predicate p)
{
- for (Ordering::iterator i = messages.begin(); i != messages.end(); i++) {
- if (p(i->second)) {
- erase(i);
+ 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;
}
}
}
diff --git a/cpp/src/qpid/broker/MessageMap.h b/cpp/src/qpid/broker/MessageMap.h
index d1b8217f9b..a668450250 100644
--- a/cpp/src/qpid/broker/MessageMap.h
+++ b/cpp/src/qpid/broker/MessageMap.h
@@ -43,7 +43,7 @@ class MessageMap : public Messages
size_t size();
bool empty();
- bool deleted(const QueuedMessage&);
+ virtual bool deleted(const QueuedMessage&);
void release(const QueuedMessage&);
virtual bool acquire(const framing::SequenceNumber&, QueuedMessage&);
bool find(const framing::SequenceNumber&, QueuedMessage&);
diff --git a/cpp/src/qpid/broker/PriorityQueue.cpp b/cpp/src/qpid/broker/PriorityQueue.cpp
index d807ef22b1..ab5ec7235a 100644
--- a/cpp/src/qpid/broker/PriorityQueue.cpp
+++ b/cpp/src/qpid/broker/PriorityQueue.cpp
@@ -3,13 +3,13 @@
* 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
+ * regarding copyright ownersip. 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
@@ -22,96 +22,87 @@
#include "qpid/broker/Queue.h"
#include "qpid/broker/QueuedMessage.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/log/Statement.h"
#include <cmath>
namespace qpid {
namespace broker {
-PriorityQueue::PriorityQueue(int l) :
+PriorityQueue::PriorityQueue(int l) :
levels(l),
messages(levels, Deque()),
frontLevel(0), haveFront(false), cached(false) {}
-bool PriorityQueue::deleted(const QueuedMessage&) { return true; }
+bool PriorityQueue::deleted(const QueuedMessage& qm) {
+ bool deleted = fifo.deleted(qm);
+ if (deleted) erase(qm);
+ return deleted;
+}
size_t PriorityQueue::size()
{
- size_t total(0);
- for (int i = 0; i < levels; ++i) {
- total += messages[i].size();
- }
- return total;
+ return fifo.size();
+}
+
+namespace {
+bool before(QueuedMessage* a, QueuedMessage* b) { return *a < *b; }
}
void PriorityQueue::release(const QueuedMessage& message)
{
- uint p = getPriorityLevel(message);
- messages[p].insert(lower_bound(messages[p].begin(), messages[p].end(), message), message);
- clearCache();
+ 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();
+ }
}
-bool PriorityQueue::find(const framing::SequenceNumber& position, QueuedMessage& message, bool remove)
-{
- QueuedMessage comp;
- comp.position = position;
- for (int i = 0; i < levels; ++i) {
- if (!messages[i].empty()) {
- unsigned long diff = position.getValue() - messages[i].front().position.getValue();
- long maxEnd = diff < messages[i].size() ? diff : messages[i].size();
- Deque::iterator l = lower_bound(messages[i].begin(),messages[i].begin()+maxEnd,comp);
- if (l != messages[i].end() && l->position == position) {
- message = *l;
- if (remove) {
- messages[i].erase(l);
- clearCache();
- }
- return true;
- }
+
+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;
}
}
- return false;
}
bool PriorityQueue::acquire(const framing::SequenceNumber& position, QueuedMessage& message)
{
- return find(position, message, true);
+ bool acquired = fifo.acquire(position, message);
+ if (acquired) erase(message); // No longer available
+ return acquired;
}
bool PriorityQueue::find(const framing::SequenceNumber& position, QueuedMessage& message)
{
- return find(position, message, false);
+ return fifo.find(position, message);
}
-bool PriorityQueue::browse(const framing::SequenceNumber& position, QueuedMessage& message, bool)
+bool PriorityQueue::browse(
+ const framing::SequenceNumber& position, QueuedMessage& message, bool unacquired)
{
- QueuedMessage match;
- match.position = position+1;
- Deque::iterator lowest;
- bool found = false;
- for (int i = 0; i < levels; ++i) {
- Deque::iterator m = lower_bound(messages[i].begin(), messages[i].end(), match);
- if (m != messages[i].end()) {
- if (m->position == match.position) {
- message = *m;
- return true;
- } else if (!found || m->position < lowest->position) {
- lowest = m;
- found = true;
- }
- }
- }
- if (found) {
- message = *lowest;
- }
- return found;
+ return fifo.browse(position, message, unacquired);
}
bool PriorityQueue::consume(QueuedMessage& message)
{
if (checkFront()) {
- message = messages[frontLevel].front();
+ QueuedMessage* pm = messages[frontLevel].front();
messages[frontLevel].pop_front();
clearCache();
+ pm->status = QueuedMessage::ACQUIRED; // Updates FIFO index
+ message = *pm;
return true;
} else {
return false;
@@ -120,23 +111,27 @@ bool PriorityQueue::consume(QueuedMessage& message)
bool PriorityQueue::push(const QueuedMessage& added, QueuedMessage& /*not needed*/)
{
- messages[getPriorityLevel(added)].push_back(added);
+ 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
+ return false; // Adding a message never causes one to be removed for deque
+}
+
+void PriorityQueue::updateAcquired(const QueuedMessage& acquired) {
+ fifo.updateAcquired(acquired);
}
void PriorityQueue::foreach(Functor f)
{
- for (int i = 0; i < levels; ++i) {
- std::for_each(messages[i].begin(), messages[i].end(), 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)) {
+ if (p(**i)) {
+ (*i)->status = QueuedMessage::DELETED; // Updates fifo index
i = messages[priority].erase(i);
clearCache();
} else {
@@ -144,6 +139,7 @@ void PriorityQueue::removeIf(Predicate p)
}
}
}
+ fifo.clean();
}
uint PriorityQueue::getPriorityLevel(const QueuedMessage& m) const
diff --git a/cpp/src/qpid/broker/PriorityQueue.h b/cpp/src/qpid/broker/PriorityQueue.h
index 67c31468d2..8628745db1 100644
--- a/cpp/src/qpid/broker/PriorityQueue.h
+++ b/cpp/src/qpid/broker/PriorityQueue.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,7 +21,7 @@
* under the License.
*
*/
-#include "qpid/broker/Messages.h"
+#include "qpid/broker/MessageDeque.h"
#include "qpid/sys/IntegerTypes.h"
#include <deque>
#include <vector>
@@ -32,7 +32,10 @@ namespace broker {
/**
* Basic priority queue with a configurable number of recognised
* priority levels. This is implemented as a separate deque per
- * priority level. Browsing is FIFO not priority order.
+ * priority level.
+ *
+ * Browsing is FIFO not priority order. There is a MessageDeque
+ * for fast browsing.
*/
class PriorityQueue : public Messages
{
@@ -48,23 +51,31 @@ class PriorityQueue : public Messages
bool browse(const framing::SequenceNumber&, QueuedMessage&, bool);
bool consume(QueuedMessage&);
bool push(const QueuedMessage& added, QueuedMessage& removed);
-
+ void updateAcquired(const QueuedMessage& acquired);
void foreach(Functor);
void removeIf(Predicate);
+
static uint getPriority(const QueuedMessage&);
+
protected:
- typedef std::deque<QueuedMessage> Deque;
+ typedef std::deque<QueuedMessage*> Deque;
typedef std::vector<Deque> PriorityLevels;
virtual bool findFrontLevel(uint& p, PriorityLevels&);
const int levels;
+
private:
+ /** Available messages separated by priority and sorted in priority order.
+ * Holds pointers to the QueuedMessages in fifo
+ */
PriorityLevels messages;
+ /** FIFO index of all messsagse (including acquired messages) for fast browsing and indexing */
+ MessageDeque fifo;
uint frontLevel;
bool haveFront;
bool cached;
-
- bool find(const framing::SequenceNumber&, QueuedMessage&, bool remove);
+
+ void erase(const QueuedMessage&);
uint getPriorityLevel(const QueuedMessage&) const;
void clearCache();
bool checkFront();
diff --git a/cpp/src/qpid/broker/Queue.cpp b/cpp/src/qpid/broker/Queue.cpp
index 015957927f..e7305c021d 100644
--- a/cpp/src/qpid/broker/Queue.cpp
+++ b/cpp/src/qpid/broker/Queue.cpp
@@ -19,8 +19,9 @@
*
*/
-#include "qpid/broker/Broker.h"
#include "qpid/broker/Queue.h"
+
+#include "qpid/broker/Broker.h"
#include "qpid/broker/QueueEvents.h"
#include "qpid/broker/Exchange.h"
#include "qpid/broker/Fairshare.h"
@@ -41,6 +42,7 @@
#include "qpid/management/ManagementAgent.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/sys/ClusterSafe.h"
#include "qpid/sys/Monitor.h"
#include "qpid/sys/Time.h"
@@ -56,7 +58,9 @@
#include <boost/intrusive_ptr.hpp>
-using namespace qpid::broker;
+namespace qpid {
+namespace broker {
+
using namespace qpid::sys;
using namespace qpid::framing;
using qpid::management::ManagementAgent;
@@ -88,8 +92,57 @@ 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,
+ _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();
+ qStats->msgTotalEnqueues +=1;
+ bStats->msgTotalEnqueues += 1;
+ qStats->byteTotalEnqueues += contentSize;
+ bStats->byteTotalEnqueues += contentSize;
+ if (msg->isPersistent ()) {
+ qStats->msgPersistEnqueues += 1;
+ bStats->msgPersistEnqueues += 1;
+ qStats->bytePersistEnqueues += contentSize;
+ bStats->bytePersistEnqueues += contentSize;
+ }
+ mgmtObject->statisticsUpdated();
+ brokerMgmtObject->statisticsUpdated();
+ }
+}
+
+inline void mgntDeqStats(const boost::intrusive_ptr<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();
+
+ qStats->msgTotalDequeues += 1;
+ bStats->msgTotalDequeues += 1;
+ qStats->byteTotalDequeues += contentSize;
+ bStats->byteTotalDequeues += contentSize;
+ if (msg->isPersistent ()){
+ qStats->msgPersistDequeues += 1;
+ bStats->msgPersistDequeues += 1;
+ qStats->bytePersistDequeues += contentSize;
+ bStats->bytePersistDequeues += contentSize;
+ }
+ mgmtObject->statisticsUpdated();
+ brokerMgmtObject->statisticsUpdated();
+ }
}
+} // namespace
+
Queue::Queue(const string& _name, bool _autodelete,
MessageStore* const _store,
const OwnershipToken* const _owner,
@@ -101,6 +154,7 @@ Queue::Queue(const string& _name, bool _autodelete,
store(_store),
owner(_owner),
consumerCount(0),
+ browserCount(0),
exclusive(0),
noLocal(false),
persistLastNode(false),
@@ -166,7 +220,7 @@ void Queue::deliver(boost::intrusive_ptr<Message> msg){
if (msg->isImmediate() && getConsumerCount() == 0) {
if (alternateExchange) {
DeliverableMessage deliverable(msg);
- alternateExchange->route(deliverable, msg->getRoutingKey(), msg->getApplicationHeaders());
+ alternateExchange->route(deliverable);
}
} else if (isLocal(msg)) {
//drop message
@@ -183,11 +237,16 @@ void Queue::deliver(boost::intrusive_ptr<Message> msg){
void Queue::recoverPrepared(boost::intrusive_ptr<Message>& msg)
{
+ Mutex::ScopedLock locker(messageLock);
if (policy.get()) policy->recoverEnqueued(msg);
}
-void Queue::recover(boost::intrusive_ptr<Message>& msg){
- if (policy.get()) policy->recoverEnqueued(msg);
+void Queue::recover(boost::intrusive_ptr<Message>& msg)
+{
+ {
+ Mutex::ScopedLock locker(messageLock);
+ if (policy.get()) policy->recoverEnqueued(msg);
+ }
push(msg, true);
if (store){
@@ -209,11 +268,16 @@ void Queue::recover(boost::intrusive_ptr<Message>& msg){
void Queue::process(boost::intrusive_ptr<Message>& msg){
push(msg);
if (mgmtObject != 0){
- mgmtObject->inc_msgTxnEnqueues ();
- mgmtObject->inc_byteTxnEnqueues (msg->contentSize ());
+ _qmf::Queue::PerThreadStats *qStats = mgmtObject->getStatistics();
+ const uint64_t contentSize = msg->contentSize();
+ qStats->msgTxnEnqueues += 1;
+ qStats->byteTxnEnqueues += contentSize;
+ mgmtObject->statisticsUpdated();
if (brokerMgmtObject) {
- brokerMgmtObject->inc_msgTxnEnqueues ();
- brokerMgmtObject->inc_byteTxnEnqueues (msg->contentSize ());
+ _qmf::Broker::PerThreadStats *bStats = brokerMgmtObject->getStatistics();
+ bStats->msgTxnEnqueues += 1;
+ bStats->byteTxnEnqueues += contentSize;
+ brokerMgmtObject->statisticsUpdated();
}
}
}
@@ -222,7 +286,6 @@ void Queue::requeue(const QueuedMessage& msg){
assertClusterSafe();
QueueListeners::NotificationSet copy;
{
- Mutex::ScopedLock locker(messageLock);
if (!isEnqueued(msg)) return;
if (deleted) {
//
@@ -238,10 +301,20 @@ void Queue::requeue(const QueuedMessage& msg){
if (brokerMgmtObject)
brokerMgmtObject->inc_abandoned();
}
- mgntDeqStats(msg.payload);
+ mgntDeqStats(msg.payload, mgmtObject, brokerMgmtObject);
} else {
- messages->release(msg);
- listeners.populate(copy);
+ {
+ Mutex::ScopedLock locker(messageLock);
+ messages->release(msg);
+ observeRequeue(msg, locker);
+ 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())) {
@@ -251,7 +324,6 @@ void Queue::requeue(const QueuedMessage& msg){
enqueue(0, payload);
}
}
- observeRequeue(msg, locker);
}
}
copy.notify();
@@ -259,10 +331,9 @@ void Queue::requeue(const QueuedMessage& msg){
bool Queue::acquireMessageAt(const SequenceNumber& position, QueuedMessage& message)
{
- Mutex::ScopedLock locker(messageLock);
assertClusterSafe();
QPID_LOG(debug, "Attempting to acquire message at " << position);
- if (acquire(position, message, locker)) {
+ if (acquire(position, message)) {
QPID_LOG(debug, "Acquired message at " << position << " from " << name);
return true;
} else {
@@ -273,17 +344,20 @@ bool Queue::acquireMessageAt(const SequenceNumber& position, QueuedMessage& mess
bool Queue::acquire(const QueuedMessage& msg, const std::string& consumer)
{
- Mutex::ScopedLock locker(messageLock);
assertClusterSafe();
QPID_LOG(debug, consumer << " attempting to acquire message at " << msg.position);
-
- if (!allocator->allocate( consumer, msg )) {
+ bool ok;
+ {
+ 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, locker)) {
+ if (acquire( msg.position, copy)) {
QPID_LOG(debug, "Acquired message at " << msg.position << " from " << name);
return true;
}
@@ -325,59 +399,73 @@ bool Queue::getNextMessage(QueuedMessage& m, Consumer::shared_ptr& c)
Queue::ConsumeCode Queue::consumeNextMessage(QueuedMessage& m, Consumer::shared_ptr& c)
{
while (true) {
- Mutex::ScopedLock locker(messageLock);
QueuedMessage msg;
- if (allocator->nextConsumableMessage(c, msg)) {
- 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();
- }
+ 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;
+ }
- continue;
+ 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)) {
+ 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);
- 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->release(msg);
- return CANT_CONSUME;
}
+ if (mgmtObject) {
+ mgmtObject->inc_acquires();
+ if (brokerMgmtObject)
+ brokerMgmtObject->inc_acquires();
+ }
+ m = msg;
+ return CONSUMED;
} else {
- //consumer will never want this message
- QPID_LOG(debug, "Consumer doesn't want message from '" << name << "'");
- messages->release(msg);
- return CANT_CONSUME;
+ //message(s) are available but consumer hasn't got enough credit
+ QPID_LOG(debug, "Consumer can't currently accept message from '" << name << "'");
}
} else {
- QPID_LOG(debug, "No messages to dispatch on queue '" << name << "'");
- listeners.addListener(c);
- return NO_MESSAGES;
+ //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) {
- Mutex::ScopedLock locker(messageLock);
QueuedMessage msg;
-
- if (!allocator->nextBrowsableMessage(c, msg)) { // no next available
+ 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 << "'");
- listeners.addListener(c);
return false;
}
@@ -435,60 +523,67 @@ bool Queue::find(SequenceNumber pos, QueuedMessage& msg) const {
void Queue::consume(Consumer::shared_ptr c, bool requestExclusive){
assertClusterSafe();
{
- Mutex::ScopedLock locker(consumerLock);
- if(exclusive) {
- throw ResourceLockedException(
- QPID_MSG("Queue " << getName() << " has an exclusive consumer. No more consumers allowed."));
- } else if(requestExclusive) {
- if(consumerCount) {
+ Mutex::ScopedLock locker(messageLock);
+ // NOTE: consumerCount is actually a count of all
+ // subscriptions, both acquiring and non-acquiring (browsers).
+ // Check for exclusivity of acquiring consumers.
+ size_t acquiringConsumers = consumerCount - browserCount;
+ if (c->preAcquires()) {
+ if(exclusive) {
throw ResourceLockedException(
- QPID_MSG("Queue " << getName() << " already has consumers. Exclusive access denied."));
- } else {
- exclusive = c->getSession();
+ QPID_MSG("Queue " << getName()
+ << " has an exclusive consumer. No more consumers allowed."));
+ } else if(requestExclusive) {
+ if(acquiringConsumers) {
+ throw ResourceLockedException(
+ QPID_MSG("Queue " << getName()
+ << " already has consumers. Exclusive access denied."));
+ } else {
+ exclusive = c->getSession();
+ }
}
}
+ else
+ browserCount++;
consumerCount++;
- if (mgmtObject != 0)
- mgmtObject->inc_consumerCount ();
//reset auto deletion timer if necessary
if (autoDeleteTimeout && autoDeleteTask) {
autoDeleteTask->cancel();
}
+ observeConsumerAdd(*c, locker);
}
- Mutex::ScopedLock locker(messageLock);
- for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
- try{
- (*i)->consumerAdded(*c);
- } catch (const std::exception& e) {
- QPID_LOG(warning, "Exception on notification of new consumer for queue " << getName() << ": " << e.what());
- }
- }
+ if (mgmtObject != 0)
+ mgmtObject->inc_consumerCount ();
}
void Queue::cancel(Consumer::shared_ptr c){
removeListener(c);
{
- Mutex::ScopedLock locker(consumerLock);
+ Mutex::ScopedLock locker(messageLock);
consumerCount--;
+ if (!c->preAcquires()) browserCount--;
if(exclusive) exclusive = 0;
- if (mgmtObject != 0)
- mgmtObject->dec_consumerCount ();
- }
- Mutex::ScopedLock locker(messageLock);
- for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
- try{
- (*i)->consumerRemoved(*c);
- } catch (const std::exception& e) {
- QPID_LOG(warning, "Exception on notification of removed consumer for queue " << getName() << ": " << e.what());
- }
+ observeConsumerRemove(*c, locker);
}
+ if (mgmtObject != 0)
+ mgmtObject->dec_consumerCount ();
}
QueuedMessage Queue::get(){
- Mutex::ScopedLock locker(messageLock);
QueuedMessage msg(this);
- if (messages->consume(msg))
- observeAcquire(msg, locker);
+ 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;
}
@@ -520,22 +615,26 @@ void Queue::purgeExpired(qpid::sys::Duration lapse)
messages->removeIf(boost::bind(&collect_if_expired, boost::ref(expired), _1));
}
- //
- // Report the count of discarded-by-ttl messages
- //
- if (mgmtObject && !expired.empty()) {
- mgmtObject->inc_discardsTtl(expired.size());
- if (brokerMgmtObject)
- brokerMgmtObject->inc_discardsTtl(expired.size());
- }
+ if (!expired.empty()) {
+ if (mgmtObject) {
+ mgmtObject->inc_acquires(expired.size());
+ mgmtObject->inc_discardsTtl(expired.size());
+ if (brokerMgmtObject) {
+ brokerMgmtObject->inc_acquires(expired.size());
+ brokerMgmtObject->inc_discardsTtl(expired.size());
+ }
+ }
- for (std::deque<QueuedMessage>::const_iterator i = expired.begin();
- i != expired.end(); ++i) {
- {
- Mutex::ScopedLock locker(messageLock);
- observeAcquire(*i, locker);
+ for (std::deque<QueuedMessage>::const_iterator i = expired.begin();
+ i != expired.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 );
}
- dequeue( 0, *i );
}
}
}
@@ -661,32 +760,46 @@ uint32_t Queue::purge(const uint32_t purge_request, boost::shared_ptr<Exchange>
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) );
+ {
+ Mutex::ScopedLock locker(messageLock);
+ messages->removeIf( boost::bind<bool>(boost::ref(c), _1) );
+ }
- if (mgmtObject && !c.matches.empty()) {
- if (dest.get()) {
- mgmtObject->inc_reroutes(c.matches.size());
- if (brokerMgmtObject)
- brokerMgmtObject->inc_reroutes(c.matches.size());
- } else {
- mgmtObject->inc_discardsPurge(c.matches.size());
- if (brokerMgmtObject)
- brokerMgmtObject->inc_discardsPurge(c.matches.size());
+ 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) {
- // Update observers and message state:
- observeAcquire(*qmsg, locker);
- dequeue(0, *qmsg);
- QPID_LOG(debug, "Purged message at " << qmsg->position << " from " << getName());
- // now reroute if necessary
- if (dest.get()) {
- assert(qmsg->payload);
- DeliverableMessage dmsg(qmsg->payload);
- dest->routeWithAlternate(dmsg);
+ 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);
+ }
+ dequeue(0, *qmsg);
+ QPID_LOG(debug, "Purged message at " << qmsg->position << " from " << getName());
+ // now reroute if necessary
+ if (dest.get()) {
+ assert(qmsg->payload);
+ DeliverableMessage dmsg(qmsg->payload);
+ dest->routeWithAlternate(dmsg);
+ }
}
}
return c.matches.size();
@@ -698,27 +811,51 @@ uint32_t Queue::move(const Queue::shared_ptr destq, uint32_t qty,
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) );
+ {
+ Mutex::ScopedLock locker(messageLock);
+ messages->removeIf( boost::bind<bool>(boost::ref(c), _1) );
+ }
+
- for (std::deque<QueuedMessage>::iterator qmsg = c.matches.begin();
- qmsg != c.matches.end(); ++qmsg) {
+ if (!c.matches.empty()) {
// Update observers and message state:
- observeAcquire(*qmsg, locker);
- dequeue(0, *qmsg);
- // and move to destination Queue.
- assert(qmsg->payload);
- destq->deliver(qmsg->payload);
+
+ 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();
}
/** Acquire the message at the given position, return true and msg if acquire succeeds */
-bool Queue::acquire(const qpid::framing::SequenceNumber& position, QueuedMessage& msg,
- const Mutex::ScopedLock& locker)
+bool Queue::acquire(const qpid::framing::SequenceNumber& position, QueuedMessage& msg)
{
- if (messages->acquire(position, msg)) {
- observeAcquire(msg, locker);
+ 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;
}
@@ -728,35 +865,43 @@ bool Queue::acquire(const qpid::framing::SequenceNumber& position, QueuedMessage
void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){
assertClusterSafe();
QueueListeners::NotificationSet copy;
- QueuedMessage removed;
+ QueuedMessage removed, qm(this, msg);
bool dequeueRequired = false;
{
Mutex::ScopedLock locker(messageLock);
- QueuedMessage qm(this, msg, ++sequence);
- if (insertSeqNo) msg->insertCustomProperty(seqNoKey, sequence);
-
- dequeueRequired = messages->push(qm, removed);
- if (dequeueRequired) {
+ qm.position = ++sequence;
+ if (messages->push(qm, removed)) {
+ dequeueRequired = true;
observeAcquire(removed, locker);
- if (mgmtObject) {
- mgmtObject->inc_discardsLvq();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_discardsLvq();
- }
}
- listeners.populate(copy);
observeEnqueue(qm, locker);
+ if (policy.get()) {
+ policy->enqueued(qm);
+ }
+ listeners.populate(copy);
}
- copy.notify();
+ 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);
}
}
+ copy.notify();
}
void isEnqueueComplete(uint32_t* result, const QueuedMessage& message)
@@ -767,8 +912,8 @@ void isEnqueueComplete(uint32_t* result, const QueuedMessage& message)
/** function only provided for unit tests, or code not in critical message path */
uint32_t Queue::getEnqueueCompleteMessageCount() const
{
- Mutex::ScopedLock locker(messageLock);
uint32_t count = 0;
+ Mutex::ScopedLock locker(messageLock);
messages->foreach(boost::bind(&isEnqueueComplete, &count, _1));
return count;
}
@@ -781,13 +926,13 @@ uint32_t Queue::getMessageCount() const
uint32_t Queue::getConsumerCount() const
{
- Mutex::ScopedLock locker(consumerLock);
+ Mutex::ScopedLock locker(messageLock);
return consumerCount;
}
bool Queue::canAutoDelete() const
{
- Mutex::ScopedLock locker(consumerLock);
+ Mutex::ScopedLock locker(messageLock);
return autodelete && !consumerCount && !owner;
}
@@ -894,14 +1039,20 @@ bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& 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);
}
}
+
+ 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();
@@ -918,14 +1069,24 @@ bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg)
void Queue::dequeueCommitted(const QueuedMessage& msg)
{
- Mutex::ScopedLock locker(messageLock);
- observeDequeue(msg, locker);
+ {
+ Mutex::ScopedLock locker(messageLock);
+ if (policy.get()) policy->dequeued(msg);
+ messages->deleted(msg);
+ observeDequeue(msg, locker);
+ }
+ mgntDeqStats(msg.payload, mgmtObject, brokerMgmtObject);
if (mgmtObject != 0) {
- mgmtObject->inc_msgTxnDequeues();
- mgmtObject->inc_byteTxnDequeues(msg.payload->contentSize());
+ _qmf::Queue::PerThreadStats *qStats = mgmtObject->getStatistics();
+ const uint64_t contentSize = msg.payload->contentSize();
+ qStats->msgTxnDequeues += 1;
+ qStats->byteTxnDequeues += contentSize;
+ mgmtObject->statisticsUpdated();
if (brokerMgmtObject) {
- brokerMgmtObject->inc_msgTxnDequeues();
- brokerMgmtObject->inc_byteTxnDequeues(msg.payload->contentSize());
+ _qmf::Broker::PerThreadStats *bStats = brokerMgmtObject->getStatistics();
+ bStats->msgTxnDequeues += 1;
+ bStats->byteTxnDequeues += contentSize;
+ brokerMgmtObject->statisticsUpdated();
}
}
}
@@ -934,10 +1095,20 @@ void Queue::dequeueCommitted(const QueuedMessage& msg)
* 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, const Mutex::ScopedLock& locker)
+bool Queue::popAndDequeue(QueuedMessage& msg)
{
- if (messages->consume(msg)) {
- observeAcquire(msg, locker);
+ 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;
} else {
@@ -947,13 +1118,10 @@ bool Queue::popAndDequeue(QueuedMessage& msg, const Mutex::ScopedLock& locker)
/**
* Updates policy and management when a message has been dequeued,
- * expects messageLock to be held
+ * Requires messageLock be held by caller.
*/
-void Queue::observeDequeue(const QueuedMessage& msg, const Mutex::ScopedLock&)
+void Queue::observeDequeue(const QueuedMessage& msg, const qpid::sys::Mutex::ScopedLock&)
{
- mgntDeqStats(msg.payload);
- if (policy.get()) policy->dequeued(msg);
- messages->deleted(msg);
for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
try{
(*i)->dequeued(msg);
@@ -963,17 +1131,11 @@ void Queue::observeDequeue(const QueuedMessage& msg, const Mutex::ScopedLock&)
}
}
-/** updates queue observers when a message has become unavailable for transfer,
- * expects messageLock to be held
+/** updates queue observers when a message has become unavailable for transfer.
+ * Requires messageLock be held by caller.
*/
-void Queue::observeAcquire(const QueuedMessage& msg, const Mutex::ScopedLock&)
+void Queue::observeAcquire(const QueuedMessage& msg, const qpid::sys::Mutex::ScopedLock&)
{
- if (mgmtObject) {
- mgmtObject->inc_acquires();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_acquires();
- }
-
for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
try{
(*i)->acquired(msg);
@@ -983,17 +1145,11 @@ void Queue::observeAcquire(const QueuedMessage& msg, const Mutex::ScopedLock&)
}
}
-/** updates queue observers when a message has become re-available for transfer,
- * expects messageLock to be held
+/** 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 Mutex::ScopedLock&)
+void Queue::observeRequeue(const QueuedMessage& msg, const qpid::sys::Mutex::ScopedLock&)
{
- if (mgmtObject) {
- mgmtObject->inc_releases();
- if (brokerMgmtObject)
- brokerMgmtObject->inc_releases();
- }
-
for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
try{
(*i)->requeued(msg);
@@ -1003,6 +1159,33 @@ void Queue::observeRequeue(const QueuedMessage& msg, const Mutex::ScopedLock&)
}
}
+/** updates queue observers when a new consumer has subscribed to this queue.
+ */
+void Queue::observeConsumerAdd( const Consumer& c, const qpid::sys::Mutex::ScopedLock&)
+{
+ for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
+ try{
+ (*i)->consumerAdded(c);
+ } catch (const std::exception& e) {
+ QPID_LOG(warning, "Exception on notification of new consumer for queue " << getName() << ": " << e.what());
+ }
+ }
+}
+
+/** updates queue observers when a consumer has unsubscribed from this queue.
+ */
+void Queue::observeConsumerRemove( const Consumer& c, const qpid::sys::Mutex::ScopedLock&)
+{
+ for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) {
+ try{
+ (*i)->consumerRemoved(c);
+ } catch (const std::exception& e) {
+ QPID_LOG(warning, "Exception on notification of removed consumer for queue " << getName() << ": " << e.what());
+ }
+ }
+}
+
+
void Queue::create(const FieldTable& _settings)
{
settings = _settings;
@@ -1150,23 +1333,21 @@ void Queue::configureImpl(const FieldTable& _settings)
void Queue::destroyed()
{
unbind(broker->getExchanges());
- {
- Mutex::ScopedLock locker(messageLock);
- QueuedMessage m;
- while(popAndDequeue(m, locker)) {
- DeliverableMessage msg(m.payload);
- if (alternateExchange.get()) {
- if (brokerMgmtObject)
- brokerMgmtObject->inc_abandonedViaAlt();
- alternateExchange->routeWithAlternate(msg);
- } else {
- if (brokerMgmtObject)
- brokerMgmtObject->inc_abandoned();
- }
+
+ 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())
- alternateExchange->decAlternateUsers();
}
+ if (alternateExchange.get())
+ alternateExchange->decAlternateUsers();
if (store) {
barrier.destroy();
@@ -1177,7 +1358,7 @@ void Queue::destroyed()
if (autoDeleteTask) autoDeleteTask = boost::intrusive_ptr<TimerTask>();
notifyDeleted();
{
- Mutex::ScopedLock locker(messageLock);
+ Mutex::ScopedLock lock(messageLock);
observers.clear();
}
}
@@ -1187,8 +1368,8 @@ void Queue::notifyDeleted()
QueueListeners::ListenerSet set;
{
Mutex::ScopedLock locker(messageLock);
- listeners.snapshot(set);
deleted = true;
+ listeners.snapshot(set);
}
set.notifyAll();
}
@@ -1206,6 +1387,7 @@ void Queue::unbind(ExchangeRegistry& exchanges)
void Queue::setPolicy(std::auto_ptr<QueuePolicy> _policy)
{
+ Mutex::ScopedLock locker(messageLock);
policy = _policy;
if (policy.get())
policy->setQueue(this);
@@ -1213,6 +1395,7 @@ void Queue::setPolicy(std::auto_ptr<QueuePolicy> _policy)
const QueuePolicy* Queue::getPolicy()
{
+ Mutex::ScopedLock locker(messageLock);
return policy.get();
}
@@ -1302,7 +1485,7 @@ struct AutoDeleteTask : qpid::sys::TimerTask
Queue::shared_ptr queue;
AutoDeleteTask(Broker& b, Queue::shared_ptr q, AbsTime fireTime)
- : qpid::sys::TimerTask(fireTime, "DelayedAutoDeletion"), broker(b), queue(q) {}
+ : qpid::sys::TimerTask(fireTime, "DelayedAutoDeletion:"+q->getName()), broker(b), queue(q) {}
void fire()
{
@@ -1388,11 +1571,15 @@ void Queue::countRejected() const
void Queue::countFlowedToDisk(uint64_t size) const
{
if (mgmtObject) {
- mgmtObject->inc_msgFtdEnqueues();
- mgmtObject->inc_byteFtdEnqueues(size);
+ _qmf::Queue::PerThreadStats *qStats = mgmtObject->getStatistics();
+ qStats->msgFtdEnqueues += 1;
+ qStats->byteFtdEnqueues += size;
+ mgmtObject->statisticsUpdated();
if (brokerMgmtObject) {
- brokerMgmtObject->inc_msgFtdEnqueues();
- brokerMgmtObject->inc_byteFtdEnqueues(size);
+ _qmf::Broker::PerThreadStats *bStats = brokerMgmtObject->getStatistics();
+ bStats->msgFtdEnqueues += 1;
+ bStats->byteFtdEnqueues += size;
+ brokerMgmtObject->statisticsUpdated();
}
}
}
@@ -1400,11 +1587,15 @@ void Queue::countFlowedToDisk(uint64_t size) const
void Queue::countLoadedFromDisk(uint64_t size) const
{
if (mgmtObject) {
- mgmtObject->inc_msgFtdDequeues();
- mgmtObject->inc_byteFtdDequeues(size);
+ _qmf::Queue::PerThreadStats *qStats = mgmtObject->getStatistics();
+ qStats->msgFtdDequeues += 1;
+ qStats->byteFtdDequeues += size;
+ mgmtObject->statisticsUpdated();
if (brokerMgmtObject) {
- brokerMgmtObject->inc_msgFtdDequeues();
- brokerMgmtObject->inc_byteFtdDequeues(size);
+ _qmf::Broker::PerThreadStats *bStats = brokerMgmtObject->getStatistics();
+ bStats->msgFtdDequeues += 1;
+ bStats->byteFtdDequeues += size;
+ brokerMgmtObject->statisticsUpdated();
}
}
}
@@ -1434,9 +1625,14 @@ Manageable::status_t Queue::ManagementMethod (uint32_t methodId, Args& args, str
{
_qmf::ArgsQueueReroute& rerouteArgs = (_qmf::ArgsQueueReroute&) args;
boost::shared_ptr<Exchange> dest;
- if (rerouteArgs.i_useAltExchange)
+ if (rerouteArgs.i_useAltExchange) {
+ if (!alternateExchange) {
+ status = Manageable::STATUS_PARAMETER_INVALID;
+ etext = "No alternate-exchange defined";
+ break;
+ }
dest = alternateExchange;
- else {
+ } else {
try {
dest = broker->getExchanges().get(rerouteArgs.i_exchange);
} catch(const std::exception&) {
@@ -1486,8 +1682,12 @@ void Queue::recoveryComplete(ExchangeRegistry& exchanges)
<< "\": exchange does not exist.");
}
//process any pending dequeues
- for_each(pendingDequeues.begin(), pendingDequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
- pendingDequeues.clear();
+ std::deque<QueuedMessage> pd;
+ {
+ Mutex::ScopedLock locker(messageLock);
+ pendingDequeues.swap(pd);
+ }
+ for_each(pd.begin(), pd.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1));
}
void Queue::insertSequenceNumbers(const std::string& key)
@@ -1497,10 +1697,10 @@ void Queue::insertSequenceNumbers(const std::string& key)
QPID_LOG(debug, "Inserting sequence numbers as " << key);
}
-/** updates queue observers and state when a message has become available for transfer,
- * expects messageLock to be held
+/** 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 Mutex::ScopedLock&)
+void Queue::observeEnqueue(const QueuedMessage& m, const qpid::sys::Mutex::ScopedLock&)
{
for (Observers::iterator i = observers.begin(); i != observers.end(); ++i) {
try {
@@ -1509,10 +1709,6 @@ void Queue::observeEnqueue(const QueuedMessage& m, const Mutex::ScopedLock&)
QPID_LOG(warning, "Exception on notification of enqueue for queue " << getName() << ": " << e.what());
}
}
- if (policy.get()) {
- policy->enqueued(m);
- }
- mgntEnqStats(m.payload);
}
void Queue::updateEnqueued(const QueuedMessage& m)
@@ -1520,12 +1716,16 @@ void Queue::updateEnqueued(const QueuedMessage& m)
if (m.payload) {
boost::intrusive_ptr<Message> payload = m.payload;
enqueue(0, payload, true);
- messages->updateAcquired(m);
- if (policy.get()) {
- policy->recoverEnqueued(payload);
+ {
+ Mutex::ScopedLock locker(messageLock);
+ messages->updateAcquired(m);
+ observeEnqueue(m, locker);
+ if (policy.get()) {
+ policy->recoverEnqueued(payload);
+ policy->enqueued(m);
+ }
}
- Mutex::ScopedLock locker(messageLock);
- observeEnqueue(m, locker);
+ mgntEnqStats(m.payload, mgmtObject, brokerMgmtObject);
} else {
QPID_LOG(warning, "Queue informed of enqueued message that has no payload");
}
@@ -1533,10 +1733,16 @@ void Queue::updateEnqueued(const QueuedMessage& m)
bool Queue::isEnqueued(const QueuedMessage& msg)
{
+ Mutex::ScopedLock locker(messageLock);
return !policy.get() || policy->isEnqueued(msg);
}
+// Note: accessing listeners outside of lock is dangerous. Caller must ensure the queue's
+// state is not changed while listeners is referenced.
QueueListeners& Queue::getListeners() { return listeners; }
+
+// Note: accessing messages outside of lock is dangerous. Caller must ensure the queue's
+// state is not changed while messages is referenced.
Messages& Queue::getMessages() { return *messages; }
const Messages& Queue::getMessages() const { return *messages; }
@@ -1549,13 +1755,13 @@ void Queue::checkNotDeleted(const Consumer::shared_ptr& c)
void Queue::addObserver(boost::shared_ptr<QueueObserver> observer)
{
- Mutex::ScopedLock locker(messageLock);
+ Mutex::ScopedLock lock(messageLock);
observers.insert(observer);
}
void Queue::removeObserver(boost::shared_ptr<QueueObserver> observer)
{
- Mutex::ScopedLock locker(messageLock);
+ Mutex::ScopedLock lock(messageLock);
observers.erase(observer);
}
@@ -1618,7 +1824,7 @@ Queue::UsageBarrier::UsageBarrier(Queue& q) : parent(q), count(0) {}
bool Queue::UsageBarrier::acquire()
{
- Monitor::ScopedLock l(parent.messageLock);
+ Monitor::ScopedLock l(parent.messageLock); /** @todo: use a dedicated lock instead of messageLock */
if (parent.deleted) {
return false;
} else {
@@ -1639,3 +1845,6 @@ void Queue::UsageBarrier::destroy()
parent.deleted = true;
while (count) parent.messageLock.wait();
}
+
+}}
+
diff --git a/cpp/src/qpid/broker/Queue.h b/cpp/src/qpid/broker/Queue.h
index e8573c17cc..9869a698c1 100644
--- a/cpp/src/qpid/broker/Queue.h
+++ b/cpp/src/qpid/broker/Queue.h
@@ -97,7 +97,8 @@ class Queue : public boost::enable_shared_from_this<Queue>,
const bool autodelete;
MessageStore* store;
const OwnershipToken* owner;
- uint32_t consumerCount;
+ 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;
@@ -107,7 +108,22 @@ class Queue : public boost::enable_shared_from_this<Queue>,
QueueListeners listeners;
std::auto_ptr<Messages> messages;
std::deque<QueuedMessage> pendingDequeues;//used to avoid dequeuing during recovery
- mutable qpid::sys::Mutex consumerLock;
+ /** 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
+ * o observers
+ * o pendingDequeues (TBD: move under separate lock)
+ * o exclusive OwnershipToken (TBD: move under separate lock)
+ * o consumerCount (TBD: move under separate lock)
+ * o Queue::UsageBarrier (TBD: move under separate lock)
+ */
mutable qpid::sys::Monitor messageLock;
mutable qpid::sys::Mutex ownershipLock;
mutable uint64_t persistenceId;
@@ -143,52 +159,20 @@ class Queue : public boost::enable_shared_from_this<Queue>,
bool isExcluded(boost::intrusive_ptr<Message>& msg);
- /** update queue observers, stats, policy, etc when the messages' state changes. Lock
- * must be held by caller */
+ /** 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);
- bool popAndDequeue(QueuedMessage&, const sys::Mutex::ScopedLock& lock);
- // acquire message @ position, return true and set msg if acquire succeeds
- bool acquire(const qpid::framing::SequenceNumber& position, QueuedMessage& msg,
- const sys::Mutex::ScopedLock& held);
+ 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);
int getEventMode();
void configureImpl(const qpid::framing::FieldTable& settings);
-
- inline void mgntEnqStats(const boost::intrusive_ptr<Message>& msg)
- {
- if (mgmtObject != 0) {
- mgmtObject->inc_msgTotalEnqueues ();
- mgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
- brokerMgmtObject->inc_msgTotalEnqueues ();
- brokerMgmtObject->inc_byteTotalEnqueues (msg->contentSize ());
- if (msg->isPersistent ()) {
- mgmtObject->inc_msgPersistEnqueues ();
- mgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
- brokerMgmtObject->inc_msgPersistEnqueues ();
- brokerMgmtObject->inc_bytePersistEnqueues (msg->contentSize ());
- }
- }
- }
- inline void mgntDeqStats(const boost::intrusive_ptr<Message>& msg)
- {
- if (mgmtObject != 0){
- mgmtObject->inc_msgTotalDequeues ();
- mgmtObject->inc_byteTotalDequeues (msg->contentSize());
- brokerMgmtObject->inc_msgTotalDequeues ();
- brokerMgmtObject->inc_byteTotalDequeues (msg->contentSize());
- if (msg->isPersistent ()){
- mgmtObject->inc_msgPersistDequeues ();
- mgmtObject->inc_bytePersistDequeues (msg->contentSize());
- brokerMgmtObject->inc_msgPersistDequeues ();
- brokerMgmtObject->inc_bytePersistDequeues (msg->contentSize());
- }
- }
- }
-
void checkNotDeleted(const Consumer::shared_ptr& c);
void notifyDeleted();
@@ -235,8 +219,9 @@ class Queue : public boost::enable_shared_from_this<Queue>,
/**
* Bind self to specified exchange, and record that binding for unbinding on delete.
*/
- bool bind(boost::shared_ptr<Exchange> exchange, const std::string& key,
- const qpid::framing::FieldTable& arguments=qpid::framing::FieldTable());
+ QPID_BROKER_EXTERN bool bind(
+ 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.
@@ -271,28 +256,29 @@ class Queue : public boost::enable_shared_from_this<Queue>,
bool exclusive = false);
QPID_BROKER_EXTERN void cancel(Consumer::shared_ptr c);
- uint32_t purge(const uint32_t purge_request=0, //defaults to all messages
+ QPID_BROKER_EXTERN uint32_t purge(const uint32_t purge_request=0, //defaults to all messages
boost::shared_ptr<Exchange> dest=boost::shared_ptr<Exchange>(),
const ::qpid::types::Variant::Map *filter=0);
QPID_BROKER_EXTERN void purgeExpired(sys::Duration);
//move qty # of messages to destination Queue destq
- uint32_t move(const Queue::shared_ptr destq, uint32_t qty,
- const qpid::types::Variant::Map *filter=0);
+ QPID_BROKER_EXTERN uint32_t move(
+ const Queue::shared_ptr destq, uint32_t qty,
+ 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; }
- bool isExclusiveOwner(const OwnershipToken* const o) const;
- void releaseExclusiveOwnership();
- bool setExclusiveOwner(const OwnershipToken* const o);
- bool hasExclusiveConsumer() const;
- bool hasExclusiveOwner() const;
+ QPID_BROKER_EXTERN bool isExclusiveOwner(const OwnershipToken* const o) const;
+ QPID_BROKER_EXTERN void releaseExclusiveOwnership();
+ QPID_BROKER_EXTERN bool setExclusiveOwner(const OwnershipToken* const o);
+ 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; }
- bool canAutoDelete() const;
+ QPID_BROKER_EXTERN bool canAutoDelete() const;
const QueueBindings& getBindings() const { return bindings; }
/**
@@ -301,8 +287,8 @@ class Queue : public boost::enable_shared_from_this<Queue>,
QPID_BROKER_EXTERN void setLastNodeFailure();
QPID_BROKER_EXTERN void clearLastNodeFailure();
- bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg, bool suppressPolicyCheck = false);
- void enqueueAborted(boost::intrusive_ptr<Message> msg);
+ 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)
*/
@@ -311,7 +297,7 @@ class Queue : public boost::enable_shared_from_this<Queue>,
* Inform the queue that a previous transactional dequeue
* committed.
*/
- void dequeueCommitted(const QueuedMessage& msg);
+ QPID_BROKER_EXTERN void dequeueCommitted(const QueuedMessage& msg);
/**
* Inform queue of messages that were enqueued, have since
@@ -319,7 +305,7 @@ class Queue : public boost::enable_shared_from_this<Queue>,
* thus are still logically on the queue) - used in
* clustered broker.
*/
- void updateEnqueued(const QueuedMessage& msg);
+ QPID_BROKER_EXTERN void updateEnqueued(const QueuedMessage& msg);
/**
* Test whether the specified message (identified by its
@@ -328,7 +314,7 @@ class Queue : public boost::enable_shared_from_this<Queue>,
* have been delievered to a subscriber who has not yet
* accepted it).
*/
- bool isEnqueued(const QueuedMessage& msg);
+ QPID_BROKER_EXTERN bool isEnqueued(const QueuedMessage& msg);
/**
* Acquires the next available (oldest) message
@@ -338,17 +324,17 @@ class Queue : public boost::enable_shared_from_this<Queue>,
/** Get the message at position pos, returns true if found and sets msg */
QPID_BROKER_EXTERN bool find(framing::SequenceNumber pos, QueuedMessage& msg ) const;
- const QueuePolicy* getPolicy();
+ QPID_BROKER_EXTERN const QueuePolicy* getPolicy();
- void setAlternateExchange(boost::shared_ptr<Exchange> exchange);
- boost::shared_ptr<Exchange> getAlternateExchange();
- bool isLocal(boost::intrusive_ptr<Message>& msg);
+ 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);
//PersistableQueue support:
- uint64_t getPersistenceId() const;
- void setPersistenceId(uint64_t persistenceId) const;
- void encode(framing::Buffer& buffer) const;
- uint32_t encodedSize() const;
+ QPID_BROKER_EXTERN uint64_t getPersistenceId() const;
+ QPID_BROKER_EXTERN void setPersistenceId(uint64_t persistenceId) const;
+ QPID_BROKER_EXTERN void encode(framing::Buffer& buffer) const;
+ QPID_BROKER_EXTERN uint32_t encodedSize() const;
/**
* Restores a queue from encoded data (used in recovery)
@@ -362,15 +348,15 @@ class Queue : public boost::enable_shared_from_this<Queue>,
virtual void setExternalQueueStore(ExternalQueueStore* inst);
// Increment the rejected-by-consumer counter.
- void countRejected() const;
- void countFlowedToDisk(uint64_t size) const;
- void countLoadedFromDisk(uint64_t size) const;
+ QPID_BROKER_EXTERN void countRejected() const;
+ QPID_BROKER_EXTERN void countFlowedToDisk(uint64_t size) const;
+ QPID_BROKER_EXTERN void countLoadedFromDisk(uint64_t size) const;
// Manageable entry points
- management::ManagementObject* GetManagementObject (void) const;
+ QPID_BROKER_EXTERN management::ManagementObject* GetManagementObject (void) const;
management::Manageable::status_t
- ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
- void query(::qpid::types::Variant::Map&) const;
+ QPID_BROKER_EXTERN ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+ QPID_BROKER_EXTERN void query(::qpid::types::Variant::Map&) const;
/** Apply f to each Message on the queue. */
template <class F> void eachMessage(F f) {
@@ -385,6 +371,7 @@ class Queue : public boost::enable_shared_from_this<Queue>,
/** Apply f to each Observer on the queue */
template <class F> void eachObserver(F f) {
+ sys::Mutex::ScopedLock l(messageLock);
std::for_each<Observers::iterator, F>(observers.begin(), observers.end(), f);
}
@@ -396,31 +383,31 @@ class Queue : public boost::enable_shared_from_this<Queue>,
/** return current position sequence number for the next message on the queue.
*/
QPID_BROKER_EXTERN framing::SequenceNumber getPosition();
- void addObserver(boost::shared_ptr<QueueObserver>);
- void removeObserver(boost::shared_ptr<QueueObserver>);
+ QPID_BROKER_EXTERN void addObserver(boost::shared_ptr<QueueObserver>);
+ QPID_BROKER_EXTERN void removeObserver(boost::shared_ptr<QueueObserver>);
QPID_BROKER_EXTERN void insertSequenceNumbers(const std::string& key);
/**
* Notify queue that recovery has completed.
*/
- void recoveryComplete(ExchangeRegistry& exchanges);
+ QPID_BROKER_EXTERN void recoveryComplete(ExchangeRegistry& exchanges);
// For cluster update
- QueueListeners& getListeners();
- Messages& getMessages();
- const Messages& getMessages() const;
+ QPID_BROKER_EXTERN QueueListeners& getListeners();
+ QPID_BROKER_EXTERN Messages& getMessages();
+ QPID_BROKER_EXTERN const Messages& getMessages() const;
/**
* Reserve space in policy for an enqueued message that
* has been recovered in the prepared state (dtx only)
*/
- void recoverPrepared(boost::intrusive_ptr<Message>& msg);
+ QPID_BROKER_EXTERN void recoverPrepared(boost::intrusive_ptr<Message>& msg);
- void flush();
+ QPID_BROKER_EXTERN void flush();
- Broker* getBroker();
+ QPID_BROKER_EXTERN Broker* getBroker();
uint32_t getDequeueSincePurge() { return dequeueSincePurge.get(); }
- void setDequeueSincePurge(uint32_t value);
+ QPID_BROKER_EXTERN void setDequeueSincePurge(uint32_t value);
};
}
}
diff --git a/cpp/src/qpid/broker/QueueListeners.cpp b/cpp/src/qpid/broker/QueueListeners.cpp
index 32c208b073..0338a674cf 100644
--- a/cpp/src/qpid/broker/QueueListeners.cpp
+++ b/cpp/src/qpid/broker/QueueListeners.cpp
@@ -79,10 +79,6 @@ void QueueListeners::NotificationSet::notify()
std::for_each(browsers.begin(), browsers.end(), boost::mem_fn(&Consumer::notify));
}
-bool QueueListeners::contains(Consumer::shared_ptr c) const {
- return c->inListeners;
-}
-
void QueueListeners::ListenerSet::notifyAll()
{
std::for_each(listeners.begin(), listeners.end(), boost::mem_fn(&Consumer::notify));
diff --git a/cpp/src/qpid/broker/QueueListeners.h b/cpp/src/qpid/broker/QueueListeners.h
index 0659499253..ca844fd47e 100644
--- a/cpp/src/qpid/broker/QueueListeners.h
+++ b/cpp/src/qpid/broker/QueueListeners.h
@@ -30,7 +30,7 @@ namespace broker {
/**
* Track and notify components that wish to be notified of messages
* that become available on a queue.
- *
+ *
* None of the methods defined here are protected by locking. However
* the populate method allows a 'snapshot' to be taken of the
* listeners to be notified. NotificationSet::notify() may then be
@@ -61,11 +61,10 @@ class QueueListeners
friend class QueueListeners;
};
- void addListener(Consumer::shared_ptr);
- void removeListener(Consumer::shared_ptr);
+ void addListener(Consumer::shared_ptr);
+ void removeListener(Consumer::shared_ptr);
void populate(NotificationSet&);
void snapshot(ListenerSet&);
- bool contains(Consumer::shared_ptr c) const;
void notifyAll();
template <class F> void eachListener(F f) {
diff --git a/cpp/src/qpid/sys/apr/Time.cpp b/cpp/src/qpid/broker/QueuedMessage.cpp
index 34e740b144..d40cc901ff 100644
--- a/cpp/src/qpid/sys/apr/Time.cpp
+++ b/cpp/src/qpid/broker/QueuedMessage.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,19 +18,17 @@
* under the License.
*
*/
-
-#include "qpid/sys/Time.h"
-
-#include <apr_time.h>
+#include "QueuedMessage.h"
+#include "Queue.h"
+#include <iostream>
namespace qpid {
-namespace sys {
-
-AbsTime AbsTime::now() {
- AbsTime time_now;
- time_now.time_ns = apr_time_now() * TIME_USEC;
- return time_now;
+namespace broker {
+
+std::ostream& operator<<(std::ostream& o, const QueuedMessage& qm) {
+ o << (qm.queue ? qm.queue->getName() : std::string()) << "[" << qm.position <<"]";
+ return o;
}
-}}
+}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/QueuedMessage.h b/cpp/src/qpid/broker/QueuedMessage.h
index 806da8e720..9d008193a0 100644
--- a/cpp/src/qpid/broker/QueuedMessage.h
+++ b/cpp/src/qpid/broker/QueuedMessage.h
@@ -22,6 +22,8 @@
#define _QueuedMessage_
#include "qpid/broker/Message.h"
+#include "BrokerImportExport.h"
+#include <iosfwd>
namespace qpid {
namespace broker {
@@ -47,6 +49,7 @@ inline bool operator<(const QueuedMessage& a, const QueuedMessage& b) {
return a.position < b.position;
}
+QPID_BROKER_EXTERN std::ostream& operator<<(std::ostream&, const QueuedMessage&);
}}
diff --git a/cpp/src/qpid/broker/SaslAuthenticator.cpp b/cpp/src/qpid/broker/SaslAuthenticator.cpp
index d7adbd68ab..80fa5e1c0e 100644
--- a/cpp/src/qpid/broker/SaslAuthenticator.cpp
+++ b/cpp/src/qpid/broker/SaslAuthenticator.cpp
@@ -26,6 +26,7 @@
#include "qpid/broker/Connection.h"
#include "qpid/log/Statement.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/sys/SecuritySettings.h"
#include <boost/format.hpp>
diff --git a/cpp/src/qpid/broker/SemanticState.cpp b/cpp/src/qpid/broker/SemanticState.cpp
index e7d2259c80..64924bdd4c 100644
--- a/cpp/src/qpid/broker/SemanticState.cpp
+++ b/cpp/src/qpid/broker/SemanticState.cpp
@@ -489,14 +489,14 @@ void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) {
exchangeName << " with routing-key " << msg->getRoutingKey()));
}
- cacheExchange->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
+ cacheExchange->route(strategy);
if (!strategy.delivered) {
//TODO:if discard-unroutable, just drop it
//TODO:else if accept-mode is explicit, reject it
//else route it to alternate exchange
if (cacheExchange->getAlternate()) {
- cacheExchange->getAlternate()->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders());
+ cacheExchange->getAlternate()->route(strategy);
}
if (!strategy.delivered) {
msg->destroy();
diff --git a/cpp/src/qpid/broker/SemanticState.h b/cpp/src/qpid/broker/SemanticState.h
index 5a83fd0fb3..e5e1d2da16 100644
--- a/cpp/src/qpid/broker/SemanticState.h
+++ b/cpp/src/qpid/broker/SemanticState.h
@@ -22,6 +22,7 @@
*
*/
+#include "qpid/broker/BrokerImportExport.h"
#include "qpid/broker/Consumer.h"
#include "qpid/broker/Credit.h"
#include "qpid/broker/Deliverable.h"
@@ -39,7 +40,6 @@
#include "qpid/sys/AggregateOutput.h"
#include "qpid/sys/Mutex.h"
#include "qpid/sys/AtomicValue.h"
-#include "qpid/broker/AclModule.h"
#include "qmf/org/apache/qpid/broker/Subscription.h"
#include <list>
@@ -99,42 +99,44 @@ class SemanticState : private boost::noncopyable {
bool haveCredit();
protected:
- virtual bool doDispatch();
+ QPID_BROKER_EXTERN virtual bool doDispatch();
size_t unacked() { return parent->unacked.size(); }
public:
typedef boost::shared_ptr<ConsumerImpl> shared_ptr;
- 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);
- virtual ~ConsumerImpl();
- OwnershipToken* getSession();
- virtual bool deliver(QueuedMessage& msg);
- bool filter(boost::intrusive_ptr<Message> msg);
- bool accept(boost::intrusive_ptr<Message> msg);
- void cancel() {}
-
- void disableNotify();
- void enableNotify();
- void notify();
- bool isNotifyEnabled() const;
-
- void requestDispatch();
-
- void setWindowMode();
- void setCreditMode();
- void addByteCredit(uint32_t value);
- void addMessageCredit(uint32_t value);
- void flush();
- void stop();
- void complete(DeliveryRecord&);
+ 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 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 void cancel() {}
+
+ QPID_BROKER_EXTERN void disableNotify();
+ QPID_BROKER_EXTERN void enableNotify();
+ QPID_BROKER_EXTERN void notify();
+ QPID_BROKER_EXTERN bool isNotifyEnabled() const;
+
+ QPID_BROKER_EXTERN void requestDispatch();
+
+ QPID_BROKER_EXTERN void setWindowMode();
+ QPID_BROKER_EXTERN void setCreditMode();
+ QPID_BROKER_EXTERN void addByteCredit(uint32_t value);
+ QPID_BROKER_EXTERN void addMessageCredit(uint32_t value);
+ QPID_BROKER_EXTERN void flush();
+ QPID_BROKER_EXTERN void stop();
+ QPID_BROKER_EXTERN void complete(DeliveryRecord&);
boost::shared_ptr<Queue> getQueue() const { return queue; }
bool isBlocked() const { return blocked; }
bool setBlocked(bool set) { std::swap(set, blocked); return set; }
- bool doOutput();
+ QPID_BROKER_EXTERN bool doOutput();
Credit& getCredit() { return credit; }
const Credit& getCredit() const { return credit; }
@@ -152,8 +154,11 @@ class SemanticState : private boost::noncopyable {
void acknowledged(const broker::QueuedMessage&) {}
// manageable entry points
- management::ManagementObject* GetManagementObject (void) const;
- management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text);
+ QPID_BROKER_EXTERN management::ManagementObject*
+ GetManagementObject(void) const;
+
+ QPID_BROKER_EXTERN management::Manageable::status_t
+ ManagementMethod(uint32_t methodId, management::Args& args, std::string& text);
};
typedef std::map<std::string, DtxBuffer::shared_ptr> DtxBufferMap;
diff --git a/cpp/src/qpid/broker/SessionAdapter.cpp b/cpp/src/qpid/broker/SessionAdapter.cpp
index 4aad46f782..78f2e43ce0 100644
--- a/cpp/src/qpid/broker/SessionAdapter.cpp
+++ b/cpp/src/qpid/broker/SessionAdapter.cpp
@@ -21,8 +21,9 @@
#include "qpid/Exception.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/framing/enum.h"
-#include "qpid/log/Statement.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/framing/SequenceSet.h"
+#include "qpid/log/Statement.h"
#include "qpid/management/ManagementAgent.h"
#include "qpid/broker/SessionState.h"
#include "qmf/org/apache/qpid/broker/EventExchangeDeclare.h"
@@ -73,18 +74,12 @@ void SessionAdapter::ExchangeHandlerImpl::declare(const string& exchange, const
if(passive){
AclModule* acl = getBroker().getAcl();
if (acl) {
- //TODO: why does a passive declare require create
- //permission? The purpose of the passive flag is to state
- //that the exchange should *not* created. For
- //authorisation a passive declare is similar to
- //exchange-query.
std::map<acl::Property, std::string> params;
params.insert(make_pair(acl::PROP_TYPE, type));
params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
- params.insert(make_pair(acl::PROP_PASSIVE, _TRUE));
params.insert(make_pair(acl::PROP_DURABLE, durable ? _TRUE : _FALSE));
- if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_EXCHANGE,exchange,&params) )
- throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied exchange create request from " << getConnection().getUserId()));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_EXCHANGE,exchange,&params) )
+ throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied exchange access request from " << getConnection().getUserId()));
}
Exchange::shared_ptr actual(getBroker().getExchanges().get(exchange));
checkType(actual, type);
@@ -274,22 +269,16 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string&
if (passive && !name.empty()) {
AclModule* acl = getBroker().getAcl();
if (acl) {
- //TODO: why does a passive declare require create
- //permission? The purpose of the passive flag is to state
- //that the queue should *not* created. For
- //authorisation a passive declare is similar to
- //queue-query (or indeed a qmf query).
std::map<acl::Property, std::string> params;
params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange));
- params.insert(make_pair(acl::PROP_PASSIVE, _TRUE));
params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE)));
params.insert(make_pair(acl::PROP_EXCLUSIVE, std::string(exclusive ? _TRUE : _FALSE)));
params.insert(make_pair(acl::PROP_AUTODELETE, std::string(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"))));
- if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_QUEUE,name,&params) )
- throw UnauthorizedAccessException(QPID_MSG("ACL denied queue create request from " << getConnection().getUserId()));
+ if (!acl->authorise(getConnection().getUserId(),acl::ACT_ACCESS,acl::OBJ_QUEUE,name,&params) )
+ throw UnauthorizedAccessException(QPID_MSG("ACL denied queue access request from " << getConnection().getUserId()));
}
queue = getQueue(name);
//TODO: check alternate-exchange is as expected
@@ -409,6 +398,7 @@ SessionAdapter::MessageHandlerImpl::subscribe(const string& queueName,
if(!destination.empty() && state.exists(destination))
throw NotAllowedException(QPID_MSG("Consumer tags must be unique"));
+ // We allow browsing (acquireMode == 1) of exclusive queues, this is required by HA.
if (queue->hasExclusiveOwner() && !queue->isExclusiveOwner(&session) && acquireMode == 0)
throw ResourceLockedException(QPID_MSG("Cannot subscribe to exclusive queue "
<< queue->getName()));
@@ -548,13 +538,6 @@ void SessionAdapter::TxHandlerImpl::rollback()
state.rollback();
}
-std::string SessionAdapter::DtxHandlerImpl::convert(const framing::Xid& xid)
-{
- std::string encoded;
- encode(xid, encoded);
- return encoded;
-}
-
void SessionAdapter::DtxHandlerImpl::select()
{
state.selectDtx();
@@ -566,7 +549,7 @@ XaResult SessionAdapter::DtxHandlerImpl::end(const Xid& xid,
{
try {
if (fail) {
- state.endDtx(convert(xid), true);
+ state.endDtx(DtxManager::convert(xid), true);
if (suspend) {
throw CommandInvalidException(QPID_MSG("End and suspend cannot both be set."));
} else {
@@ -574,9 +557,9 @@ XaResult SessionAdapter::DtxHandlerImpl::end(const Xid& xid,
}
} else {
if (suspend) {
- state.suspendDtx(convert(xid));
+ state.suspendDtx(DtxManager::convert(xid));
} else {
- state.endDtx(convert(xid), false);
+ state.endDtx(DtxManager::convert(xid), false);
}
return XaResult(XA_STATUS_XA_OK);
}
@@ -594,9 +577,9 @@ XaResult SessionAdapter::DtxHandlerImpl::start(const Xid& xid,
}
try {
if (resume) {
- state.resumeDtx(convert(xid));
+ state.resumeDtx(DtxManager::convert(xid));
} else {
- state.startDtx(convert(xid), getBroker().getDtxManager(), join);
+ state.startDtx(DtxManager::convert(xid), getBroker().getDtxManager(), join);
}
return XaResult(XA_STATUS_XA_OK);
} catch (const DtxTimeoutException& /*e*/) {
@@ -607,7 +590,7 @@ XaResult SessionAdapter::DtxHandlerImpl::start(const Xid& xid,
XaResult SessionAdapter::DtxHandlerImpl::prepare(const Xid& xid)
{
try {
- bool ok = getBroker().getDtxManager().prepare(convert(xid));
+ bool ok = getBroker().getDtxManager().prepare(DtxManager::convert(xid));
return XaResult(ok ? XA_STATUS_XA_OK : XA_STATUS_XA_RBROLLBACK);
} catch (const DtxTimeoutException& /*e*/) {
return XaResult(XA_STATUS_XA_RBTIMEOUT);
@@ -618,7 +601,7 @@ XaResult SessionAdapter::DtxHandlerImpl::commit(const Xid& xid,
bool onePhase)
{
try {
- bool ok = getBroker().getDtxManager().commit(convert(xid), onePhase);
+ bool ok = getBroker().getDtxManager().commit(DtxManager::convert(xid), onePhase);
return XaResult(ok ? XA_STATUS_XA_OK : XA_STATUS_XA_RBROLLBACK);
} catch (const DtxTimeoutException& /*e*/) {
return XaResult(XA_STATUS_XA_RBTIMEOUT);
@@ -629,7 +612,7 @@ XaResult SessionAdapter::DtxHandlerImpl::commit(const Xid& xid,
XaResult SessionAdapter::DtxHandlerImpl::rollback(const Xid& xid)
{
try {
- getBroker().getDtxManager().rollback(convert(xid));
+ getBroker().getDtxManager().rollback(DtxManager::convert(xid));
return XaResult(XA_STATUS_XA_OK);
} catch (const DtxTimeoutException& /*e*/) {
return XaResult(XA_STATUS_XA_RBTIMEOUT);
@@ -659,7 +642,7 @@ void SessionAdapter::DtxHandlerImpl::forget(const Xid& xid)
DtxGetTimeoutResult SessionAdapter::DtxHandlerImpl::getTimeout(const Xid& xid)
{
- uint32_t timeout = getBroker().getDtxManager().getTimeout(convert(xid));
+ uint32_t timeout = getBroker().getDtxManager().getTimeout(DtxManager::convert(xid));
return DtxGetTimeoutResult(timeout);
}
@@ -667,7 +650,7 @@ DtxGetTimeoutResult SessionAdapter::DtxHandlerImpl::getTimeout(const Xid& xid)
void SessionAdapter::DtxHandlerImpl::setTimeout(const Xid& xid,
uint32_t timeout)
{
- getBroker().getDtxManager().setTimeout(convert(xid), timeout);
+ getBroker().getDtxManager().setTimeout(DtxManager::convert(xid), timeout);
}
diff --git a/cpp/src/qpid/broker/SessionAdapter.h b/cpp/src/qpid/broker/SessionAdapter.h
index 8987c4812f..bc056538b1 100644
--- a/cpp/src/qpid/broker/SessionAdapter.h
+++ b/cpp/src/qpid/broker/SessionAdapter.h
@@ -226,10 +226,8 @@ class Queue;
void rollback();
};
- class DtxHandlerImpl : public DtxHandler, public HandlerHelper, private framing::StructHelper
+ class DtxHandlerImpl : public DtxHandler, public HandlerHelper
{
- std::string convert(const framing::Xid& xid);
-
public:
DtxHandlerImpl(SemanticState& session) : HandlerHelper(session) {}
diff --git a/cpp/src/qpid/broker/SessionHandler.cpp b/cpp/src/qpid/broker/SessionHandler.cpp
index 752fa55535..b58c7c01c5 100644
--- a/cpp/src/qpid/broker/SessionHandler.cpp
+++ b/cpp/src/qpid/broker/SessionHandler.cpp
@@ -64,6 +64,7 @@ void SessionHandler::handleDetach() {
if (session.get())
connection.getBroker().getSessionManager().detach(session);
assert(!session.get());
+ if (detachedCallback) detachedCallback();
connection.closeChannel(channel.get());
}
@@ -117,4 +118,8 @@ void SessionHandler::attached(const std::string& name)
}
}
+void SessionHandler::setDetachedCallback(boost::function<void()> cb) {
+ detachedCallback = cb;
+}
+
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/SessionHandler.h b/cpp/src/qpid/broker/SessionHandler.h
index 8cd5072574..4e2cfaa963 100644
--- a/cpp/src/qpid/broker/SessionHandler.h
+++ b/cpp/src/qpid/broker/SessionHandler.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
@@ -25,6 +25,7 @@
#include "qpid/amqp_0_10/SessionHandler.h"
#include "qpid/broker/SessionHandler.h"
#include "qpid/framing/AMQP_ClientProxy.h"
+#include <boost/function.hpp>
namespace qpid {
class SessionState;
@@ -61,7 +62,7 @@ class SessionHandler : public amqp_0_10::SessionHandler {
* This proxy is for sending such commands. In a clustered broker it will take steps
* to synchronize command order across the cluster. In a stand-alone broker
* it is just a synonym for getProxy()
- */
+ */
framing::AMQP_ClientProxy& getClusterOrderProxy() {
return clusterOrderProxy.get() ? *clusterOrderProxy : proxy;
}
@@ -70,6 +71,8 @@ class SessionHandler : public amqp_0_10::SessionHandler {
void attached(const std::string& name);//used by 'pushing' inter-broker bridges
void attachAs(const std::string& name);//used by 'pulling' inter-broker bridges
+ void setDetachedCallback(boost::function<void()> cb);
+
protected:
virtual void setState(const std::string& sessionName, bool force);
virtual qpid::SessionState* getState();
@@ -91,6 +94,7 @@ class SessionHandler : public amqp_0_10::SessionHandler {
framing::AMQP_ClientProxy proxy;
std::auto_ptr<SessionState> session;
std::auto_ptr<SetChannelProxy> clusterOrderProxy;
+ boost::function<void ()> detachedCallback;
};
}} // namespace qpid::broker
diff --git a/cpp/src/qpid/broker/TopicExchange.cpp b/cpp/src/qpid/broker/TopicExchange.cpp
index 644a3d628e..dd3ec13019 100644
--- a/cpp/src/qpid/broker/TopicExchange.cpp
+++ b/cpp/src/qpid/broker/TopicExchange.cpp
@@ -350,8 +350,9 @@ TopicExchange::BindingKey *TopicExchange::getQueueBinding(Queue::shared_ptr queu
return (q != qv.end()) ? bk : 0;
}
-void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/)
+void TopicExchange::route(Deliverable& msg)
{
+ const string& routingKey = msg.getMessage().getRoutingKey();
// Note: PERFORMANCE CRITICAL!!!
BindingList b;
std::map<std::string, BindingList>::iterator it;
diff --git a/cpp/src/qpid/broker/TopicExchange.h b/cpp/src/qpid/broker/TopicExchange.h
index 636918f8a1..cc24e1411e 100644
--- a/cpp/src/qpid/broker/TopicExchange.h
+++ b/cpp/src/qpid/broker/TopicExchange.h
@@ -185,9 +185,7 @@ class TopicExchange : public virtual Exchange {
virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
- QPID_BROKER_EXTERN virtual void route(Deliverable& msg,
- const std::string& routingKey,
- const qpid::framing::FieldTable* args);
+ QPID_BROKER_EXTERN virtual void route(Deliverable& msg);
QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue,
const std::string* const routingKey,
diff --git a/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp b/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp
index 2acc09cded..a38e6ac12a 100644
--- a/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp
+++ b/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp
@@ -25,6 +25,7 @@
#include "qpid/broker/Connection.h"
#include "qpid/log/Statement.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/FieldValue.h"
#include <windows.h>
diff --git a/cpp/src/qpid/client/Connection.cpp b/cpp/src/qpid/client/Connection.cpp
index 2882ef5d42..83a4a35b53 100644
--- a/cpp/src/qpid/client/Connection.cpp
+++ b/cpp/src/qpid/client/Connection.cpp
@@ -75,7 +75,7 @@ void Connection::open(const Url& url, const ConnectionSettings& settings) {
i++;
try {
ConnectionSettings cs(settings);
- cs.protocol = addr.protocol;
+ if (addr.protocol.size()) cs.protocol = addr.protocol;
cs.host = addr.host;
cs.port = addr.port;
open(cs);
diff --git a/cpp/src/qpid/client/ConnectionHandler.cpp b/cpp/src/qpid/client/ConnectionHandler.cpp
index ab0d8e0700..94561f8079 100644
--- a/cpp/src/qpid/client/ConnectionHandler.cpp
+++ b/cpp/src/qpid/client/ConnectionHandler.cpp
@@ -28,10 +28,13 @@
#include "qpid/framing/all_method_bodies.h"
#include "qpid/framing/ClientInvoker.h"
#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/log/Helpers.h"
#include "qpid/log/Statement.h"
#include "qpid/sys/SystemInfo.h"
+#include <algorithm>
+
using namespace qpid::client;
using namespace qpid::framing;
using namespace qpid::framing::connection;
@@ -238,15 +241,16 @@ void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& me
);
std::vector<std::string> mechlist;
+ mechlist.reserve(mechanisms.size());
if (mechanism.empty()) {
//mechlist is simply what the server offers
- mechanisms.collect(mechlist);
+ std::transform(mechanisms.begin(), mechanisms.end(), std::back_inserter(mechlist), Array::get<std::string, Array::ValuePtr>);
} else {
//mechlist is the intersection of those indicated by user and
//those supported by server, in the order listed by user
std::vector<std::string> allowed = split(mechanism, " ");
- std::vector<std::string> supported;
- mechanisms.collect(supported);
+ std::vector<std::string> supported(mechanisms.size());
+ std::transform(mechanisms.begin(), mechanisms.end(), std::back_inserter(supported), Array::get<std::string, Array::ValuePtr>);
intersection(allowed, supported, mechlist);
if (mechlist.empty()) {
throw Exception(QPID_MSG("Desired mechanism(s) not valid: " << mechanism << " (supported: " << join(supported) << ")"));
diff --git a/cpp/src/qpid/client/ConnectionImpl.cpp b/cpp/src/qpid/client/ConnectionImpl.cpp
index db97f1e0f4..85b0e8303e 100644
--- a/cpp/src/qpid/client/ConnectionImpl.cpp
+++ b/cpp/src/qpid/client/ConnectionImpl.cpp
@@ -115,8 +115,10 @@ public:
ioThreads(0),
connections(0)
{
+ CommonOptions common("", "", QPIDC_CONF_FILE);
IOThreadOptions options(c);
- options.parse(0, 0, QPIDC_CONF_FILE, true);
+ common.parse(0, 0, common.clientConfig, true);
+ options.parse(0, 0, common.clientConfig, true);
maxIOThreads = (options.maxIOThreads != -1) ?
options.maxIOThreads : 1;
}
diff --git a/cpp/src/qpid/client/LoadPlugins.cpp b/cpp/src/qpid/client/LoadPlugins.cpp
index 246eb60c67..d76e1d458e 100644
--- a/cpp/src/qpid/client/LoadPlugins.cpp
+++ b/cpp/src/qpid/client/LoadPlugins.cpp
@@ -39,10 +39,12 @@ namespace {
struct LoadtimeInitialise {
LoadtimeInitialise() {
+ CommonOptions common("", "", QPIDC_CONF_FILE);
qpid::ModuleOptions moduleOptions(QPIDC_MODULE_DIR);
string defaultPath (moduleOptions.loadDir);
- moduleOptions.parse (0, 0, QPIDC_CONF_FILE, true);
-
+ common.parse(0, 0, common.clientConfig, true);
+ moduleOptions.parse (0, 0, common.clientConfig, true);
+
for (vector<string>::iterator iter = moduleOptions.load.begin();
iter != moduleOptions.load.end();
iter++)
diff --git a/cpp/src/qpid/client/SessionImpl.cpp b/cpp/src/qpid/client/SessionImpl.cpp
index 9ac5323a53..3f3ad617f4 100644
--- a/cpp/src/qpid/client/SessionImpl.cpp
+++ b/cpp/src/qpid/client/SessionImpl.cpp
@@ -324,7 +324,7 @@ struct MethodContentAdaptor : MethodContent
MethodContentAdaptor(const FrameSet& f) : header(*f.getHeaders()), content(f.getContent()) {}
- AMQHeaderBody getHeader() const
+ const AMQHeaderBody& getHeader() const
{
return header;
}
diff --git a/cpp/src/qpid/client/SslConnector.cpp b/cpp/src/qpid/client/SslConnector.cpp
index 6b6bf884ec..ab0c5c4957 100644
--- a/cpp/src/qpid/client/SslConnector.cpp
+++ b/cpp/src/qpid/client/SslConnector.cpp
@@ -148,8 +148,10 @@ namespace {
struct StaticInit {
StaticInit() {
try {
+ CommonOptions common("", "", QPIDC_CONF_FILE);
SslOptions options;
- options.parse (0, 0, QPIDC_CONF_FILE, true);
+ common.parse(0, 0, common.clientConfig, true);
+ options.parse (0, 0, common.clientConfig, true);
if (options.certDbPath.empty()) {
QPID_LOG(info, "SSL connector not enabled, you must set QPID_SSL_CERT_DB to enable it.");
} else {
diff --git a/cpp/src/qpid/client/TCPConnector.cpp b/cpp/src/qpid/client/TCPConnector.cpp
index 51eacf77e8..4660a41c07 100644
--- a/cpp/src/qpid/client/TCPConnector.cpp
+++ b/cpp/src/qpid/client/TCPConnector.cpp
@@ -97,7 +97,7 @@ void TCPConnector::connect(const std::string& host, const std::string& port) {
boost::bind(&TCPConnector::connected, this, _1),
boost::bind(&TCPConnector::connectFailed, this, _3));
closed = false;
- identifier = str(format("[%1%]") % socket.getFullAddress());
+
connector->start(poller);
}
@@ -120,6 +120,8 @@ void TCPConnector::start(sys::AsynchIO* aio_) {
for (int i = 0; i < 4; i++) {
aio->queueReadBuffer(new Buff(maxFrameSize));
}
+
+ identifier = str(format("[%1%]") % socket.getFullAddress());
}
void TCPConnector::initAmqp() {
@@ -129,7 +131,7 @@ void TCPConnector::initAmqp() {
void TCPConnector::connectFailed(const std::string& msg) {
connector = 0;
- QPID_LOG(warning, "Connect failed: " << msg << " " << identifier);
+ QPID_LOG(warning, "Connect failed: " << msg);
socket.close();
if (!closed)
closed = true;
@@ -183,7 +185,7 @@ sys::ShutdownHandler* TCPConnector::getShutdownHandler() const {
return shutdownHandler;
}
-const std::string& TCPConnector::getIdentifier() const {
+const std::string& TCPConnector::getIdentifier() const {
return identifier;
}
diff --git a/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
index 5924e30dd8..a8f4fb5237 100644
--- a/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
+++ b/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp
@@ -32,6 +32,7 @@
#include "qpid/framing/ExchangeBoundResult.h"
#include "qpid/framing/ExchangeQueryResult.h"
#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/framing/QueueQueryResult.h"
#include "qpid/framing/ReplyTo.h"
#include "qpid/framing/reply_exceptions.h"
diff --git a/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
index 3cfd2e37f2..2ea4dc0c61 100644
--- a/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
+++ b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp
@@ -41,6 +41,7 @@ using qpid::framing::Uuid;
namespace {
+const std::string TCP("tcp");
double FOREVER(std::numeric_limits<double>::max());
// Time values in seconds can be specified as integer or floating point values.
@@ -290,7 +291,7 @@ bool ConnectionImpl::tryConnect()
for (std::vector<std::string>::const_iterator i = urls.begin(); i != urls.end(); ++i) {
try {
QPID_LOG(info, "Trying to connect to " << *i << "...");
- Url url(*i);
+ Url url(*i, settings.protocol.size() ? settings.protocol : TCP);
if (url.getUser().size()) settings.username = url.getUser();
if (url.getPass().size()) settings.password = url.getPass();
connection.open(url, settings);
diff --git a/cpp/src/qpid/cluster/Cluster.cpp b/cpp/src/qpid/cluster/Cluster.cpp
index 3c1d23c842..34aaf3d341 100644
--- a/cpp/src/qpid/cluster/Cluster.cpp
+++ b/cpp/src/qpid/cluster/Cluster.cpp
@@ -131,6 +131,7 @@
#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"
@@ -202,7 +203,7 @@ namespace arg=client::arg;
* Currently use SVN revision to avoid clashes with versions from
* different branches.
*/
-const uint32_t Cluster::CLUSTER_VERSION = 1207877;
+const uint32_t Cluster::CLUSTER_VERSION = 1332342;
struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler {
qpid::cluster::Cluster& cluster;
@@ -269,7 +270,6 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) :
"Error delivering frames",
poller),
failoverExchange(new FailoverExchange(broker.GetVhostObject(), &broker)),
- updateDataExchange(new UpdateDataExchange(*this)),
credentialsExchange(new CredentialsExchange(*this)),
quorum(boost::bind(&Cluster::leave, this)),
decoder(boost::bind(&Cluster::deliverFrame, this, _1)),
@@ -295,15 +295,6 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) :
// Failover exchange provides membership updates to clients.
broker.getExchanges().registerExchange(failoverExchange);
- // 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 for passing data that may be too large
- // for single control frame.
- broker.getExchanges().registerExchange(updateDataExchange);
-
// CredentialsExchange is used to authenticate new cluster members
broker.getExchanges().registerExchange(credentialsExchange);
@@ -680,6 +671,17 @@ void Cluster::initMapCompleted(Lock& l) {
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);
@@ -999,6 +1001,10 @@ void Cluster::checkUpdateIn(Lock& l) {
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;
diff --git a/cpp/src/qpid/cluster/ClusterMap.cpp b/cpp/src/qpid/cluster/ClusterMap.cpp
index a8389095c9..d9817db35f 100644
--- a/cpp/src/qpid/cluster/ClusterMap.cpp
+++ b/cpp/src/qpid/cluster/ClusterMap.cpp
@@ -21,6 +21,7 @@
#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>
@@ -29,7 +30,8 @@
#include <ostream>
using namespace std;
-using namespace boost;
+using boost::ref;
+using boost::optional;
namespace qpid {
using namespace framing;
diff --git a/cpp/src/qpid/cluster/ClusterTimer.cpp b/cpp/src/qpid/cluster/ClusterTimer.cpp
index b4f7d00f38..90e4fa9d4d 100644
--- a/cpp/src/qpid/cluster/ClusterTimer.cpp
+++ b/cpp/src/qpid/cluster/ClusterTimer.cpp
@@ -24,6 +24,7 @@
#include "qpid/log/Statement.h"
#include "qpid/framing/ClusterTimerWakeupBody.h"
#include "qpid/framing/ClusterTimerDropBody.h"
+#include "qpid/sys/ClusterSafe.h"
namespace qpid {
namespace cluster {
@@ -107,6 +108,7 @@ void ClusterTimer::drop(intrusive_ptr<TimerTask> t) {
// 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));
diff --git a/cpp/src/qpid/cluster/Connection.cpp b/cpp/src/qpid/cluster/Connection.cpp
index fc6ada096f..512e0f03cb 100644
--- a/cpp/src/qpid/cluster/Connection.cpp
+++ b/cpp/src/qpid/cluster/Connection.cpp
@@ -47,6 +47,7 @@
#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"
@@ -796,6 +797,54 @@ void Connection::config(const std::string& encoded) {
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
diff --git a/cpp/src/qpid/cluster/Connection.h b/cpp/src/qpid/cluster/Connection.h
index 920c4937db..26514c76e2 100644
--- a/cpp/src/qpid/cluster/Connection.h
+++ b/cpp/src/qpid/cluster/Connection.h
@@ -200,6 +200,8 @@ class Connection :
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 );
diff --git a/cpp/src/qpid/cluster/CredentialsExchange.cpp b/cpp/src/qpid/cluster/CredentialsExchange.cpp
index 0fafc521cd..416a3636e9 100644
--- a/cpp/src/qpid/cluster/CredentialsExchange.cpp
+++ b/cpp/src/qpid/cluster/CredentialsExchange.cpp
@@ -62,7 +62,8 @@ bool CredentialsExchange::check(MemberId member) {
return valid;
}
-void CredentialsExchange::route(broker::Deliverable& msg, const string& /*routingKey*/, const framing::FieldTable* args) {
+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());
diff --git a/cpp/src/qpid/cluster/CredentialsExchange.h b/cpp/src/qpid/cluster/CredentialsExchange.h
index 90fd188271..74cf8350a6 100644
--- a/cpp/src/qpid/cluster/CredentialsExchange.h
+++ b/cpp/src/qpid/cluster/CredentialsExchange.h
@@ -50,7 +50,7 @@ class CredentialsExchange : public broker::Exchange
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, const std::string& routingKey, const framing::FieldTable* args);
+ void route(broker::Deliverable& msg);
// Exchange overrides
std::string getType() const;
diff --git a/cpp/src/qpid/cluster/FailoverExchange.cpp b/cpp/src/qpid/cluster/FailoverExchange.cpp
index 43ec27cf2c..87202a887c 100644
--- a/cpp/src/qpid/cluster/FailoverExchange.cpp
+++ b/cpp/src/qpid/cluster/FailoverExchange.cpp
@@ -80,7 +80,7 @@ bool FailoverExchange::isBound(Queue::shared_ptr queue, const string* const, con
return queues.find(queue) != queues.end();
}
-void FailoverExchange::route(Deliverable&, const string& , const framing::FieldTable* ) {
+void FailoverExchange::route(Deliverable&) {
QPID_LOG(warning, "Message received by exchange " << typeName << " ignoring");
}
diff --git a/cpp/src/qpid/cluster/FailoverExchange.h b/cpp/src/qpid/cluster/FailoverExchange.h
index c3e50c6929..5ac734a7ac 100644
--- a/cpp/src/qpid/cluster/FailoverExchange.h
+++ b/cpp/src/qpid/cluster/FailoverExchange.h
@@ -54,7 +54,7 @@ class FailoverExchange : public broker::Exchange
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, const std::string& routingKey, const framing::FieldTable* args);
+ void route(broker::Deliverable& msg);
private:
void sendUpdate(const boost::shared_ptr<broker::Queue>&);
diff --git a/cpp/src/qpid/cluster/InitialStatusMap.cpp b/cpp/src/qpid/cluster/InitialStatusMap.cpp
index eb65005a9e..fc53d1076b 100644
--- a/cpp/src/qpid/cluster/InitialStatusMap.cpp
+++ b/cpp/src/qpid/cluster/InitialStatusMap.cpp
@@ -30,9 +30,9 @@ namespace qpid {
namespace cluster {
using namespace std;
-using namespace boost;
using namespace framing::cluster;
using namespace framing;
+using boost::optional;
InitialStatusMap::InitialStatusMap(const MemberId& self_, size_t size_)
: self(self_), completed(), resendNeeded(), size(size_)
diff --git a/cpp/src/qpid/cluster/UpdateClient.cpp b/cpp/src/qpid/cluster/UpdateClient.cpp
index 95c64ff060..20684fd8a7 100644
--- a/cpp/src/qpid/cluster/UpdateClient.cpp
+++ b/cpp/src/qpid/cluster/UpdateClient.cpp
@@ -57,6 +57,7 @@
#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"
@@ -687,7 +688,15 @@ void UpdateClient::updateLinks() {
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));
+ 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) {
diff --git a/cpp/src/qpid/cluster/UpdateDataExchange.cpp b/cpp/src/qpid/cluster/UpdateDataExchange.cpp
index e5cd82e3d3..31d96c67ca 100644
--- a/cpp/src/qpid/cluster/UpdateDataExchange.cpp
+++ b/cpp/src/qpid/cluster/UpdateDataExchange.cpp
@@ -40,9 +40,9 @@ UpdateDataExchange::UpdateDataExchange(Cluster& cluster) :
Exchange(EXCHANGE_NAME, &cluster)
{}
-void UpdateDataExchange::route(broker::Deliverable& msg, const std::string& routingKey,
- const qpid::framing::FieldTable* )
+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;
diff --git a/cpp/src/qpid/cluster/UpdateDataExchange.h b/cpp/src/qpid/cluster/UpdateDataExchange.h
index d2f6c35ad0..f79430f111 100644
--- a/cpp/src/qpid/cluster/UpdateDataExchange.h
+++ b/cpp/src/qpid/cluster/UpdateDataExchange.h
@@ -50,8 +50,7 @@ class UpdateDataExchange : public broker::Exchange
UpdateDataExchange(Cluster& parent);
- void route(broker::Deliverable& msg, const std::string& routingKey,
- const framing::FieldTable* args);
+ void route(broker::Deliverable& msg);
// Not implemented
std::string getType() const { return EXCHANGE_TYPE; }
diff --git a/cpp/src/qpid/framing/AMQFrame.h b/cpp/src/qpid/framing/AMQFrame.h
index 4f6faf4199..19675ce6ff 100644
--- a/cpp/src/qpid/framing/AMQFrame.h
+++ b/cpp/src/qpid/framing/AMQFrame.h
@@ -43,8 +43,7 @@ class QPID_COMMON_CLASS_EXTERN AMQFrame : public AMQDataBlock
ChannelId getChannel() const { return channel; }
void setChannel(ChannelId c) { channel = c; }
- AMQBody* getBody() { return body.get(); }
- const AMQBody* getBody() const { return body.get(); }
+ AMQBody* getBody() const { return body.get(); }
AMQMethodBody* getMethod() { return getBody() ? getBody()->getMethod() : 0; }
const AMQMethodBody* getMethod() const { return getBody() ? getBody()->getMethod() : 0; }
diff --git a/cpp/src/qpid/framing/BodyHandler.cpp b/cpp/src/qpid/framing/BodyHandler.cpp
deleted file mode 100644
index db302b1e4c..0000000000
--- a/cpp/src/qpid/framing/BodyHandler.cpp
+++ /dev/null
@@ -1,56 +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/BodyHandler.h"
-#include "qpid/framing/AMQMethodBody.h"
-#include "qpid/framing/AMQHeaderBody.h"
-#include "qpid/framing/AMQContentBody.h"
-#include "qpid/framing/AMQHeartbeatBody.h"
-#include <boost/cast.hpp>
-#include "qpid/framing/reply_exceptions.h"
-#include "qpid/Msg.h"
-
-using namespace qpid::framing;
-using namespace boost;
-
-BodyHandler::~BodyHandler() {}
-
-// TODO aconway 2007-08-13: Replace with visitor.
-void BodyHandler::handleBody(AMQBody* body) {
- switch(body->type())
- {
- case METHOD_BODY:
- handleMethod(polymorphic_downcast<AMQMethodBody*>(body));
- break;
- case HEADER_BODY:
- handleHeader(polymorphic_downcast<AMQHeaderBody*>(body));
- break;
- case CONTENT_BODY:
- handleContent(polymorphic_downcast<AMQContentBody*>(body));
- break;
- case HEARTBEAT_BODY:
- handleHeartbeat(polymorphic_downcast<AMQHeartbeatBody*>(body));
- break;
- default:
- throw FramingErrorException(
- QPID_MSG("Invalid frame type " << body->type()));
- }
-}
-
diff --git a/cpp/src/qpid/framing/FieldTable.cpp b/cpp/src/qpid/framing/FieldTable.cpp
index f80d2f9fb1..0f7140b627 100644
--- a/cpp/src/qpid/framing/FieldTable.cpp
+++ b/cpp/src/qpid/framing/FieldTable.cpp
@@ -28,29 +28,93 @@
#include "qpid/Msg.h"
#include <assert.h>
+// The locking rationale in the FieldTable seems a little odd, but it
+// maintains the concurrent guarantees and requirements that were in
+// place before the cachedBytes/cachedSize were added:
+//
+// The FieldTable client code needs to make sure that they call no write
+// operation in parallel with any other operation on the FieldTable.
+// However multiple parallel read operations are safe.
+//
+// To this end the only code that is locked is code that can transparently
+// change the state of the FieldTable during a read only operation.
+// (In other words the code that required the mutable members in the class
+// definition!)
+//
namespace qpid {
+
+using sys::Mutex;
+using sys::ScopedLock;
+
namespace framing {
+FieldTable::FieldTable() :
+ cachedSize(0),
+ newBytes(false)
+{
+}
+
FieldTable::FieldTable(const FieldTable& ft)
{
- *this = ft;
+ ScopedLock<Mutex> l(ft.lock); // lock _source_ FieldTable
+
+ cachedBytes = ft.cachedBytes;
+ cachedSize = ft.cachedSize;
+ newBytes = ft.newBytes;
+
+ // Only copy the values if we have no raw data
+ // - copying the map is expensive and we can
+ // reconstruct it if necessary from the raw data
+ if (cachedBytes) {
+ newBytes = true;
+ return;
+ }
+ // In practice Encoding the source field table and only copying
+ // the encoded bytes is faster than copying the whole value map.
+ // (Because we nearly always copy a field table internally before
+ // encoding it to send, but don't change it after the copy)
+ if (!ft.values.empty()) {
+ // Side effect of getting encoded size will cache it in ft.cachedSize
+ ft.cachedBytes = boost::shared_array<uint8_t>(new uint8_t[ft.encodedSize()]);
+
+ Buffer buffer((char*)&ft.cachedBytes[0], ft.cachedSize);
+
+ // Cut and paste ahead...
+ buffer.putLong(ft.encodedSize() - 4);
+ buffer.putLong(ft.values.size());
+ for (ValueMap::const_iterator i = ft.values.begin(); i!=ft.values.end(); ++i) {
+ buffer.putShortString(i->first);
+ i->second->encode(buffer);
+ }
+
+ cachedBytes = ft.cachedBytes;
+ cachedSize = ft.cachedSize;
+ newBytes = true;
+ }
}
FieldTable& FieldTable::operator=(const FieldTable& ft)
{
- clear();
- values = ft.values;
- return *this;
+ FieldTable nft(ft);
+ values.swap(nft.values);
+ cachedBytes.swap(nft.cachedBytes);
+ cachedSize = nft.cachedSize;
+ newBytes = nft.newBytes;
+ return (*this);
}
-FieldTable::~FieldTable() {}
-
uint32_t FieldTable::encodedSize() const {
+ ScopedLock<Mutex> l(lock);
+
+ if (cachedSize != 0) {
+ return cachedSize;
+ }
uint32_t len(4/*size field*/ + 4/*count field*/);
for(ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
// shortstr_len_byte + key size + value size
- len += 1 + (i->first).size() + (i->second)->encodedSize();
+ len += 1 + (i->first).size() + (i->second)->encodedSize();
}
+ cachedSize = len;
return len;
}
@@ -66,6 +130,7 @@ std::ostream& operator<<(std::ostream& out, const FieldTable::ValueMap::value_ty
}
std::ostream& operator<<(std::ostream& out, const FieldTable& t) {
+ t.realDecode();
out << "{";
FieldTable::ValueMap::const_iterator i = t.begin();
if (i != t.end()) out << *i++;
@@ -77,48 +142,70 @@ std::ostream& operator<<(std::ostream& out, const FieldTable& t) {
}
void FieldTable::set(const std::string& name, const ValuePtr& value){
+ realDecode();
values[name] = value;
+ flushRawCache();
}
void FieldTable::setString(const std::string& name, const std::string& value){
+ realDecode();
values[name] = ValuePtr(new Str16Value(value));
+ flushRawCache();
}
void FieldTable::setInt(const std::string& name, const int value){
+ realDecode();
values[name] = ValuePtr(new IntegerValue(value));
+ flushRawCache();
}
void FieldTable::setInt64(const std::string& name, const int64_t value){
+ realDecode();
values[name] = ValuePtr(new Integer64Value(value));
+ flushRawCache();
}
void FieldTable::setTimestamp(const std::string& name, const uint64_t value){
+ realDecode();
values[name] = ValuePtr(new TimeValue(value));
+ flushRawCache();
}
void FieldTable::setUInt64(const std::string& name, const uint64_t value){
+ realDecode();
values[name] = ValuePtr(new Unsigned64Value(value));
+ flushRawCache();
}
void FieldTable::setTable(const std::string& name, const FieldTable& value)
{
+ realDecode();
values[name] = ValuePtr(new FieldTableValue(value));
+ flushRawCache();
}
void FieldTable::setArray(const std::string& name, const Array& value)
{
+ realDecode();
values[name] = ValuePtr(new ArrayValue(value));
+ flushRawCache();
}
void FieldTable::setFloat(const std::string& name, const float value){
+ realDecode();
values[name] = ValuePtr(new FloatValue(value));
+ flushRawCache();
}
void FieldTable::setDouble(const std::string& name, double value){
+ realDecode();
values[name] = ValuePtr(new DoubleValue(value));
+ flushRawCache();
}
FieldTable::ValuePtr FieldTable::get(const std::string& name) const
{
+ // Ensure we have any values we're trying to read
+ realDecode();
ValuePtr value;
ValueMap::const_iterator i = values.find(name);
if ( i!=values.end() )
@@ -188,37 +275,82 @@ bool FieldTable::getDouble(const std::string& name, double& value) const {
//}
void FieldTable::encode(Buffer& buffer) const {
- buffer.putLong(encodedSize() - 4);
- buffer.putLong(values.size());
- for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
- buffer.putShortString(i->first);
- i->second->encode(buffer);
+ // If we've still got the input field table
+ // we can just copy it directly to the output
+ if (cachedBytes) {
+ ScopedLock<Mutex> l(lock);
+ buffer.putRawData(&cachedBytes[0], cachedSize);
+ } else {
+ buffer.putLong(encodedSize() - 4);
+ buffer.putLong(values.size());
+ for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
+ buffer.putShortString(i->first);
+ i->second->encode(buffer);
+ }
}
}
+// Decode lazily - just record the raw bytes until we need them
void FieldTable::decode(Buffer& buffer){
- clear();
if (buffer.available() < 4)
throw IllegalArgumentException(QPID_MSG("Not enough data for field table."));
+ uint32_t p = buffer.getPosition();
uint32_t len = buffer.getLong();
if (len) {
uint32_t available = buffer.available();
if ((available < len) || (available < 4))
throw IllegalArgumentException(QPID_MSG("Not enough data for field table."));
+ }
+ ScopedLock<Mutex> l(lock);
+ // Throw away previous stored values
+ values.clear();
+ // Copy data into our buffer
+ cachedBytes = boost::shared_array<uint8_t>(new uint8_t[len + 4]);
+ cachedSize = len + 4;
+ newBytes = true;
+ buffer.setPosition(p);
+ buffer.getRawData(&cachedBytes[0], cachedSize);
+}
+
+void FieldTable::realDecode() const
+{
+ ScopedLock<Mutex> l(lock);
+
+ // If we've got no raw data stored up then nothing to do
+ if (!newBytes)
+ return;
+
+ Buffer buffer((char*)&cachedBytes[0], cachedSize);
+ uint32_t len = buffer.getLong();
+ if (len) {
+ uint32_t available = buffer.available();
uint32_t count = buffer.getLong();
uint32_t leftover = available - len;
while(buffer.available() > leftover && count--){
std::string name;
ValuePtr value(new FieldValue);
-
+
buffer.getShortString(name);
value->decode(buffer);
values[name] = ValuePtr(value);
- }
+ }
}
+ newBytes = false;
+}
+
+void FieldTable::flushRawCache()
+{
+ ScopedLock<Mutex> l(lock);
+ // We can only flush the cache if there are no cached bytes to decode
+ assert(newBytes==false);
+ // Avoid recreating shared array unless we actually have one.
+ if (cachedBytes) cachedBytes.reset();
+ cachedSize = 0;
}
bool FieldTable::operator==(const FieldTable& x) const {
+ realDecode();
+ x.realDecode();
if (values.size() != x.values.size()) return false;
for (ValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
ValueMap::const_iterator j = x.values.find(i->first);
@@ -230,20 +362,73 @@ bool FieldTable::operator==(const FieldTable& x) const {
void FieldTable::erase(const std::string& name)
{
- if (values.find(name) != values.end())
+ realDecode();
+ if (values.find(name) != values.end()) {
values.erase(name);
+ flushRawCache();
+ }
+}
+
+void FieldTable::clear()
+{
+ values.clear();
+ newBytes = false;
+ flushRawCache();
+}
+
+// Map-like interface.
+FieldTable::ValueMap::const_iterator FieldTable::begin() const
+{
+ realDecode();
+ return values.begin();
+}
+
+FieldTable::ValueMap::const_iterator FieldTable::end() const
+{
+ realDecode();
+ return values.end();
+}
+
+FieldTable::ValueMap::const_iterator FieldTable::find(const std::string& s) const
+{
+ realDecode();
+ return values.find(s);
+}
+
+FieldTable::ValueMap::iterator FieldTable::begin()
+{
+ realDecode();
+ flushRawCache();
+ return values.begin();
+}
+
+FieldTable::ValueMap::iterator FieldTable::end()
+{
+ realDecode();
+ flushRawCache();
+ return values.end();
+}
+
+FieldTable::ValueMap::iterator FieldTable::find(const std::string& s)
+{
+ realDecode();
+ flushRawCache();
+ return values.find(s);
}
std::pair<FieldTable::ValueMap::iterator, bool> FieldTable::insert(const ValueMap::value_type& value)
{
+ realDecode();
+ flushRawCache();
return values.insert(value);
}
FieldTable::ValueMap::iterator FieldTable::insert(ValueMap::iterator position, const ValueMap::value_type& value)
{
+ realDecode();
+ flushRawCache();
return values.insert(position, value);
}
-
}
}
diff --git a/cpp/src/qpid/framing/FrameSet.cpp b/cpp/src/qpid/framing/FrameSet.cpp
index 255aaf6e6b..9aee7b98b9 100644
--- a/cpp/src/qpid/framing/FrameSet.cpp
+++ b/cpp/src/qpid/framing/FrameSet.cpp
@@ -26,7 +26,6 @@
#include "qpid/framing/TypeFilter.h"
using namespace qpid::framing;
-using namespace boost;
FrameSet::FrameSet(const SequenceNumber& _id) : id(_id),contentSize(0),recalculateSize(true) { }
FrameSet::FrameSet(const FrameSet& original) : id(original.id), contentSize(0), recalculateSize(true)
@@ -103,3 +102,7 @@ std::string FrameSet::getContent() const {
getContent(out);
return out;
}
+
+bool FrameSet::hasContent() const {
+ return parts.size() >= 3;
+}
diff --git a/cpp/src/qpid/framing/FrameSet.h b/cpp/src/qpid/framing/FrameSet.h
index cae75e5ec8..3b9f60950b 100644
--- a/cpp/src/qpid/framing/FrameSet.h
+++ b/cpp/src/qpid/framing/FrameSet.h
@@ -54,6 +54,7 @@ public:
QPID_COMMON_EXTERN void getContent(std::string&) const;
QPID_COMMON_EXTERN std::string getContent() const;
+ QPID_COMMON_EXTERN bool hasContent() const;
bool isContentBearing() const;
diff --git a/cpp/src/qpid/framing/MethodContent.h b/cpp/src/qpid/framing/MethodContent.h
index b290a0c140..58c9143cfa 100644
--- a/cpp/src/qpid/framing/MethodContent.h
+++ b/cpp/src/qpid/framing/MethodContent.h
@@ -32,7 +32,7 @@ class MethodContent
public:
virtual ~MethodContent() {}
//TODO: rethink this interface
- virtual AMQHeaderBody getHeader() const = 0;
+ virtual const AMQHeaderBody& getHeader() const = 0;
virtual const std::string& getData() const = 0;
};
diff --git a/cpp/src/qpid/framing/TransferContent.cpp b/cpp/src/qpid/framing/TransferContent.cpp
index 837d7d346a..d997b24304 100644
--- a/cpp/src/qpid/framing/TransferContent.cpp
+++ b/cpp/src/qpid/framing/TransferContent.cpp
@@ -30,7 +30,7 @@ TransferContent::TransferContent(const std::string& data, const std::string& key
}
-AMQHeaderBody TransferContent::getHeader() const
+const AMQHeaderBody& TransferContent::getHeader() const
{
return header;
}
diff --git a/cpp/src/qpid/framing/TransferContent.h b/cpp/src/qpid/framing/TransferContent.h
index 9a698a1823..32663d7020 100644
--- a/cpp/src/qpid/framing/TransferContent.h
+++ b/cpp/src/qpid/framing/TransferContent.h
@@ -40,7 +40,7 @@ public:
QPID_COMMON_EXTERN TransferContent(const std::string& data = std::string(), const std::string& key=std::string());
///@internal
- QPID_COMMON_EXTERN AMQHeaderBody getHeader() const;
+ QPID_COMMON_EXTERN const AMQHeaderBody& getHeader() const;
QPID_COMMON_EXTERN void setData(const std::string&);
QPID_COMMON_EXTERN const std::string& getData() const;
diff --git a/cpp/src/qpid/framing/amqp_framing.h b/cpp/src/qpid/framing/amqp_framing.h
index 3a8b39afb5..2e58922364 100644
--- a/cpp/src/qpid/framing/amqp_framing.h
+++ b/cpp/src/qpid/framing/amqp_framing.h
@@ -21,7 +21,6 @@
#include "qpid/framing/amqp_types.h"
#include "qpid/framing/AMQFrame.h"
#include "qpid/framing/AMQBody.h"
-#include "qpid/framing/BodyHandler.h"
#include "qpid/framing/AMQMethodBody.h"
#include "qpid/framing/AMQHeaderBody.h"
#include "qpid/framing/AMQContentBody.h"
diff --git a/cpp/src/qpid/ha/Backup.cpp b/cpp/src/qpid/ha/Backup.cpp
index 5acbfb9d5f..3f3fa87a01 100644
--- a/cpp/src/qpid/ha/Backup.cpp
+++ b/cpp/src/qpid/ha/Backup.cpp
@@ -19,10 +19,11 @@
*
*/
#include "Backup.h"
-#include "Settings.h"
#include "BrokerReplicator.h"
-#include "ReplicatingSubscription.h"
#include "ConnectionExcluder.h"
+#include "HaBroker.h"
+#include "ReplicatingSubscription.h"
+#include "Settings.h"
#include "qpid/Url.h"
#include "qpid/amqp_0_10/Codecs.h"
#include "qpid/broker/Bridge.h"
@@ -43,37 +44,44 @@ using namespace broker;
using types::Variant;
using std::string;
-Backup::Backup(broker::Broker& b, const Settings& s) :
- broker(b), settings(s), excluder(new ConnectionExcluder())
+Backup::Backup(HaBroker& hb, const Settings& s) :
+ haBroker(hb), broker(hb.getBroker()), settings(s), excluder(new ConnectionExcluder())
{
+ // Exclude client connections before starting the link to avoid self-connection.
+ broker.getConnectionObservers().add(excluder);
// Empty brokerUrl means delay initialization until setUrl() is called.
if (!s.brokerUrl.empty()) initialize(Url(s.brokerUrl));
}
void Backup::initialize(const Url& url) {
- assert(!url.empty());
- QPID_LOG(notice, "Ha: Backup started: " << url);
+ if (url.empty()) throw Url::Invalid("HA broker URL is empty");
+ QPID_LOG(notice, "HA: Backup initialized: " << url);
string protocol = url[0].protocol.empty() ? "tcp" : url[0].protocol;
// Declare the link
std::pair<Link::shared_ptr, bool> result = broker.getLinks().declare(
url[0].host, url[0].port, protocol,
false, // durable
settings.mechanism, settings.username, settings.password);
- assert(result.second); // FIXME aconway 2011-11-23: error handling
link = result.first;
link->setUrl(url);
-
- replicator.reset(new BrokerReplicator(link));
+ replicator.reset(new BrokerReplicator(haBroker, link));
broker.getExchanges().registerExchange(replicator);
- broker.getConnectionObservers().add(excluder);
}
+Backup::~Backup() {
+ if (link) link->close();
+ if (replicator.get()) broker.getExchanges().destroy(replicator->getName());
+ replicator.reset();
+ broker.getConnectionObservers().remove(excluder); // This allows client connections.
+}
+
+
void Backup::setBrokerUrl(const Url& url) {
// Ignore empty URLs seen during start-up for some tests.
if (url.empty()) return;
sys::Mutex::ScopedLock l(lock);
if (link) { // URL changed after we initialized.
- QPID_LOG(info, "HA: Backup failover URL set to " << url);
+ QPID_LOG(info, "HA: Backup broker URL set to " << url);
link->setUrl(url);
}
else {
@@ -81,10 +89,4 @@ void Backup::setBrokerUrl(const Url& url) {
}
}
-Backup::~Backup() {
- if (link) link->close();
- if (replicator.get()) broker.getExchanges().destroy(replicator->getName());
- broker.getConnectionObservers().remove(excluder); // This allows client connections.
-}
-
}} // namespace qpid::ha
diff --git a/cpp/src/qpid/ha/Backup.h b/cpp/src/qpid/ha/Backup.h
index 526b238b82..6c36996914 100644
--- a/cpp/src/qpid/ha/Backup.h
+++ b/cpp/src/qpid/ha/Backup.h
@@ -38,6 +38,7 @@ namespace ha {
class Settings;
class ConnectionExcluder;
class BrokerReplicator;
+class HaBroker;
/**
* State associated with a backup broker. Manages connections to primary.
@@ -47,7 +48,7 @@ class BrokerReplicator;
class Backup
{
public:
- Backup(broker::Broker&, const Settings&);
+ Backup(HaBroker&, const Settings&);
~Backup();
void setBrokerUrl(const Url&);
@@ -55,6 +56,7 @@ class Backup
void initialize(const Url&);
sys::Mutex lock;
+ HaBroker& haBroker;
broker::Broker& broker;
Settings settings;
boost::shared_ptr<broker::Link> link;
diff --git a/cpp/src/qpid/ha/BrokerReplicator.cpp b/cpp/src/qpid/ha/BrokerReplicator.cpp
index a8f05c1fe3..d0c99cbdb6 100644
--- a/cpp/src/qpid/ha/BrokerReplicator.cpp
+++ b/cpp/src/qpid/ha/BrokerReplicator.cpp
@@ -19,6 +19,7 @@
*
*/
#include "BrokerReplicator.h"
+#include "HaBroker.h"
#include "QueueReplicator.h"
#include "qpid/broker/Broker.h"
#include "qpid/broker/Queue.h"
@@ -37,6 +38,7 @@
#include "qmf/org/apache/qpid/broker/EventQueueDelete.h"
#include "qmf/org/apache/qpid/broker/EventSubscribe.h"
#include <algorithm>
+#include <sstream>
namespace qpid {
namespace ha {
@@ -87,6 +89,7 @@ const string QUEUE("queue");
const string RHOST("rhost");
const string TYPE("type");
const string USER("user");
+const string HA_BROKER("habroker");
const string AGENT_IND_EVENT_ORG_APACHE_QPID_BROKER("agent.ind.event.org_apache_qpid_broker.#");
const string QMF2("qmf2");
@@ -100,6 +103,7 @@ const string _PACKAGE_NAME("_package_name");
const string _SCHEMA_ID("_schema_id");
const string OBJECT("OBJECT");
const string ORG_APACHE_QPID_BROKER("org.apache.qpid.broker");
+const string ORG_APACHE_QPID_HA("org.apache.qpid.ha");
const string QMF_DEFAULT_DIRECT("qmf.default.direct");
const string _QUERY_REQUEST("_query_request");
const string BROKER("broker");
@@ -113,36 +117,13 @@ template <class T> bool match(Variant::Map& schema) {
return T::match(schema[CLASS_NAME], schema[PACKAGE_NAME]);
}
-enum ReplicateLevel { RL_NONE=0, RL_CONFIGURATION, RL_MESSAGES };
-const string S_NONE="none";
-const string S_CONFIGURATION="configuration";
-const string S_MESSAGES="messages";
-
-ReplicateLevel replicateLevel(const string& level) {
- if (level == S_NONE) return RL_NONE;
- if (level == S_CONFIGURATION) return RL_CONFIGURATION;
- if (level == S_MESSAGES) return RL_MESSAGES;
- throw Exception("Invalid value for "+QPID_REPLICATE+": "+level);
-}
-
-ReplicateLevel replicateLevel(const framing::FieldTable& f) {
- if (f.isSet(QPID_REPLICATE)) return replicateLevel(f.getAsString(QPID_REPLICATE));
- else return RL_NONE;
-}
-
-ReplicateLevel replicateLevel(const Variant::Map& m) {
- Variant::Map::const_iterator i = m.find(QPID_REPLICATE);
- if (i != m.end()) return replicateLevel(i->second.asString());
- else return RL_NONE;
-}
-
-void sendQuery(const string className, const string& queueName, SessionHandler& sessionHandler) {
+void sendQuery(const string& packageName, const string& className, const string& queueName, SessionHandler& sessionHandler) {
framing::AMQP_ServerProxy peer(sessionHandler.out);
Variant::Map request;
request[_WHAT] = OBJECT;
Variant::Map schema;
schema[_CLASS_NAME] = className;
- schema[_PACKAGE_NAME] = ORG_APACHE_QPID_BROKER;
+ schema[_PACKAGE_NAME] = packageName;
request[_SCHEMA_ID] = schema;
AMQFrame method((MessageTransferBody(ProtocolVersion(), QMF_DEFAULT_DIRECT, 0, 0)));
@@ -181,13 +162,34 @@ Variant::Map asMapVoid(const Variant& value) {
} // namespace
+
+ReplicateLevel BrokerReplicator::replicateLevel(const std::string& str) {
+ ReplicateLevel rl;
+ if (qpid::ha::replicateLevel(str, rl)) return rl;
+ else return haBroker.getSettings().replicateDefault;
+}
+
+ReplicateLevel BrokerReplicator::replicateLevel(const framing::FieldTable& f) {
+ if (f.isSet(QPID_REPLICATE))
+ return replicateLevel(f.getAsString(QPID_REPLICATE));
+ else
+ return haBroker.getSettings().replicateDefault;
+}
+
+ReplicateLevel BrokerReplicator::replicateLevel(const Variant::Map& m) {
+ Variant::Map::const_iterator i = m.find(QPID_REPLICATE);
+ if (i != m.end())
+ return replicateLevel(i->second.asString());
+ else
+ return haBroker.getSettings().replicateDefault;
+}
+
BrokerReplicator::~BrokerReplicator() {}
-BrokerReplicator::BrokerReplicator(const boost::shared_ptr<Link>& l)
- : Exchange(QPID_CONFIGURATION_REPLICATOR), broker(*l->getBroker()), link(l)
+BrokerReplicator::BrokerReplicator(HaBroker& hb, const boost::shared_ptr<Link>& l)
+ : Exchange(QPID_CONFIGURATION_REPLICATOR),
+ haBroker(hb), broker(hb.getBroker()), link(l)
{
- QPID_LOG(info, "HA: Backup replicating from " <<
- link->getTransport() << ":" << link->getHost() << ":" << link->getPort());
broker.getLinks().declare(
link->getHost(), link->getPort(),
false, // durable
@@ -211,22 +213,26 @@ void BrokerReplicator::initializeBridge(Bridge& bridge, SessionHandler& sessionH
const qmf::org::apache::qpid::broker::ArgsLinkBridge& args(bridge.getArgs());
//declare and bind an event queue
- peer.getQueue().declare(queueName, "", false, false, true, true, FieldTable());
+ FieldTable declareArgs;
+ declareArgs.setString(QPID_REPLICATE, str(RL_NONE));
+ peer.getQueue().declare(queueName, "", false, false, true, true, declareArgs);
peer.getExchange().bind(queueName, QMF_DEFAULT_TOPIC, AGENT_IND_EVENT_ORG_APACHE_QPID_BROKER, FieldTable());
//subscribe to the queue
peer.getMessage().subscribe(queueName, args.i_dest, 1, 0, false, "", 0, FieldTable());
peer.getMessage().flow(args.i_dest, 0, 0xFFFFFFFF);
peer.getMessage().flow(args.i_dest, 1, 0xFFFFFFFF);
- //issue a query request for queues and another for exchanges using event queue as the reply-to address
- sendQuery(QUEUE, queueName, sessionHandler);
- sendQuery(EXCHANGE, queueName, sessionHandler);
- sendQuery(BINDING, queueName, sessionHandler);
- QPID_LOG(debug, "HA: Backup activated configuration bridge: " << queueName);
+ // Issue a query request for queues, exchanges, bindings and the habroker
+ // using event queue as the reply-to address
+ sendQuery(ORG_APACHE_QPID_HA, HA_BROKER, queueName, sessionHandler);
+ sendQuery(ORG_APACHE_QPID_BROKER, QUEUE, queueName, sessionHandler);
+ sendQuery(ORG_APACHE_QPID_BROKER, EXCHANGE, queueName, sessionHandler);
+ sendQuery(ORG_APACHE_QPID_BROKER, BINDING, queueName, sessionHandler);
+ QPID_LOG(debug, "HA: Backup configuration bridge: " << queueName);
}
-// FIXME aconway 2011-12-02: error handling in route.
-void BrokerReplicator::route(Deliverable& msg, const string& /*key*/, const framing::FieldTable* headers) {
+void BrokerReplicator::route(Deliverable& msg) {
+ const framing::FieldTable* headers = msg.getMessage().getApplicationHeaders();
Variant::List list;
try {
if (!isQMFv2(msg.getMessage()) || !headers)
@@ -238,6 +244,7 @@ void BrokerReplicator::route(Deliverable& msg, const string& /*key*/, const fram
if (headers->getAsString(QMF_CONTENT) == EVENT) {
for (Variant::List::iterator i = list.begin(); i != list.end(); ++i) {
Variant::Map& map = i->asMap();
+ QPID_LOG(trace, "HA: Backup received event: " << map);
Variant::Map& schema = map[SCHEMA_ID].asMap();
Variant::Map& values = map[VALUES].asMap();
if (match<EventQueueDeclare>(schema)) doEventQueueDeclare(values);
@@ -249,19 +256,22 @@ void BrokerReplicator::route(Deliverable& msg, const string& /*key*/, const fram
}
} else if (headers->getAsString(QMF_OPCODE) == QUERY_RESPONSE) {
for (Variant::List::iterator i = list.begin(); i != list.end(); ++i) {
- string type = i->asMap()[SCHEMA_ID].asMap()[CLASS_NAME];
- Variant::Map& values = i->asMap()[VALUES].asMap();
+ Variant::Map& map = i->asMap();
+ QPID_LOG(trace, "HA: Backup received event: " << map);
+ string type = map[SCHEMA_ID].asMap()[CLASS_NAME];
+ Variant::Map& values = map[VALUES].asMap();
framing::FieldTable args;
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 QPID_LOG(error, "HA: Backup received unknown response type=" << type
- << " values=" << values);
+ else if (type == HA_BROKER) doResponseHaBroker(values);
}
- } else QPID_LOG(error, "HA: Backup received unexpected message: " << *headers);
+ }
} catch (const std::exception& e) {
- QPID_LOG(error, "HA: Backup replication error: " << e.what() << ": while handling: " << list);
+ QPID_LOG(critical, "HA: Backup configuration failed: " << e.what()
+ << ": while handling: " << list);
+ throw;
}
}
@@ -282,15 +292,13 @@ void BrokerReplicator::doEventQueueDeclare(Variant::Map& values) {
values[USER].asString(),
values[RHOST].asString());
if (result.second) {
- // FIXME aconway 2011-11-22: should delete old queue and
- // re-create from event.
- // Events are always up to date, whereas responses may be
- // out of date.
- QPID_LOG(debug, "HA: Backup created queue: " << name);
+ QPID_LOG(debug, "HA: Backup queue declare event: " << name);
startQueueReplicator(result.first);
} else {
// FIXME aconway 2011-12-02: what's the right way to handle this?
- QPID_LOG(warning, "HA: Backup queue already exists: " << name);
+ // Should we delete the old & re-create form the event? Responses
+ // may be old but events are always up-to-date.
+ QPID_LOG(warning, "HA: Backup queue declare event, already exists: " << name);
}
}
}
@@ -300,8 +308,11 @@ 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 && replicateLevel(queue->getSettings())) {
- QPID_LOG(debug, "HA: Backup deleting queue: " << name);
+ if (!queue) {
+ QPID_LOG(warning, "HA: Backup queue delete event, does not exist: " << name);
+ } else if (!replicateLevel(queue->getSettings())) {
+ QPID_LOG(warning, "HA: Backup queue delete event, not replicated: " << name);
+ } else {
string rname = QueueReplicator::replicatorName(name);
boost::shared_ptr<broker::Exchange> ex = broker.getExchanges().find(rname);
boost::shared_ptr<QueueReplicator> qr = boost::dynamic_pointer_cast<QueueReplicator>(ex);
@@ -310,6 +321,7 @@ void BrokerReplicator::doEventQueueDelete(Variant::Map& values) {
// actually be destroyed, deleting the exhange
broker.getExchanges().destroy(rname);
broker.deleteQueue(name, values[USER].asString(), values[RHOST].asString());
+ QPID_LOG(debug, "HA: Backup queue delete event: " << name);
}
}
@@ -328,27 +340,29 @@ void BrokerReplicator::doEventExchangeDeclare(Variant::Map& values) {
values[USER].asString(),
values[RHOST].asString()).second)
{
- QPID_LOG(debug, "HA: Backup created exchange: " << name);
+ QPID_LOG(debug, "HA: Backup exchange declare event: " << name);
} else {
- // FIXME aconway 2011-11-22: should delete pre-exisitng exchange
+ // FIXME aconway 2011-11-22: should delete pre-existing exchange
// and re-create from event. See comment in doEventQueueDeclare.
- QPID_LOG(warning, "HA: Backup exchange already exists: " << name);
+ QPID_LOG(debug, "HA: Backup exchange declare event, already exists: " << name);
}
}
}
void BrokerReplicator::doEventExchangeDelete(Variant::Map& values) {
string name = values[EXNAME].asString();
- try {
- boost::shared_ptr<Exchange> exchange = broker.getExchanges().find(name);
- if (exchange && replicateLevel(exchange->getArgs())) {
- QPID_LOG(debug, "HA: Backup deleting exchange:" << name);
- broker.deleteExchange(
- name,
- values[USER].asString(),
- values[RHOST].asString());
- }
- } catch (const framing::NotFoundException&) {}
+ boost::shared_ptr<Exchange> exchange = broker.getExchanges().find(name);
+ if (!exchange) {
+ QPID_LOG(warning, "HA: Backup exchange delete event, does not exist: " << name);
+ } else if (!replicateLevel(exchange->getArgs())) {
+ QPID_LOG(warning, "HA: Backup exchange delete event, not replicated: " << name);
+ } else {
+ QPID_LOG(debug, "HA: Backup exchange delete event:" << name);
+ broker.deleteExchange(
+ name,
+ values[USER].asString(),
+ values[RHOST].asString());
+ }
}
void BrokerReplicator::doEventBind(Variant::Map& values) {
@@ -364,10 +378,10 @@ void BrokerReplicator::doEventBind(Variant::Map& values) {
framing::FieldTable args;
amqp_0_10::translate(asMapVoid(values[ARGS]), args);
string key = values[KEY].asString();
- QPID_LOG(debug, "HA: Backup replicated binding exchange=" << exchange->getName()
+ exchange->bind(queue, key, &args);
+ QPID_LOG(debug, "HA: Backup bind event: exchange=" << exchange->getName()
<< " queue=" << queue->getName()
<< " key=" << key);
- exchange->bind(queue, key, &args);
}
}
@@ -384,15 +398,14 @@ void BrokerReplicator::doEventUnbind(Variant::Map& values) {
framing::FieldTable args;
amqp_0_10::translate(asMapVoid(values[ARGS]), args);
string key = values[KEY].asString();
- QPID_LOG(debug, "HA: Backup replicated unbinding exchange=" << exchange->getName()
+ exchange->unbind(queue, key, &args);
+ QPID_LOG(debug, "HA: Backup unbind event: exchange=" << exchange->getName()
<< " queue=" << queue->getName()
<< " key=" << key);
- exchange->unbind(queue, key, &args);
}
}
void BrokerReplicator::doResponseQueue(Variant::Map& values) {
- // FIXME aconway 2011-11-22: more flexible ways & defaults to indicate replication
Variant::Map argsMap(asMapVoid(values[ARGUMENTS]));
if (!replicateLevel(argsMap)) return;
framing::FieldTable args;
@@ -409,12 +422,12 @@ void BrokerReplicator::doResponseQueue(Variant::Map& values) {
""/*TODO: who is the user?*/,
""/*TODO: what should we use as connection id?*/);
if (result.second) {
- QPID_LOG(debug, "HA: Backup created catch-up queue: " << values[NAME]);
+ QPID_LOG(debug, "HA: Backup queue response: " << name);
startQueueReplicator(result.first);
} else {
// FIXME aconway 2011-11-22: Normal to find queue already
// exists if we're failing over.
- QPID_LOG(warning, "HA: Backup catch-up queue already exists: " << name);
+ QPID_LOG(warning, "HA: Backup queue response, already exists: " << name);
}
}
@@ -432,9 +445,10 @@ void BrokerReplicator::doResponseExchange(Variant::Map& values) {
""/*TODO: who is the user?*/,
""/*TODO: what should we use as connection id?*/).second)
{
- QPID_LOG(debug, "HA: Backup catch-up exchange: " << values[NAME]);
+ QPID_LOG(debug, "HA: Backup exchange response: " << values[NAME].asString());
} else {
- QPID_LOG(warning, "HA: Backup catch-up exchange already exists: " << values[QNAME]);
+ QPID_LOG(warning, "HA: Backup exchange query, already exists: " <<
+ values[QNAME].asString());
}
}
@@ -464,7 +478,6 @@ void BrokerReplicator::doResponseBind(Variant::Map& values) {
std::string qName = getRefName(QUEUE_REF_PREFIX, values[QUEUE_REF]);
boost::shared_ptr<Exchange> exchange = broker.getExchanges().find(exName);
boost::shared_ptr<Queue> queue = broker.getQueues().find(qName);
- // FIXME aconway 2011-11-24: more flexible configuration for binding replication.
// Automatically replicate binding if queue and exchange exist and are replicated
if (exchange && replicateLevel(exchange->getArgs()) &&
@@ -474,16 +487,39 @@ void BrokerReplicator::doResponseBind(Variant::Map& values) {
amqp_0_10::translate(asMapVoid(values[ARGUMENTS]), args);
string key = values[KEY].asString();
exchange->bind(queue, key, &args);
- QPID_LOG(debug, "HA: Backup catch-up binding: exchange=" << exchange->getName()
+ QPID_LOG(debug, "HA: Backup bind response: exchange=" << exchange->getName()
<< " queue=" << queue->getName()
<< " key=" << key);
}
}
+namespace {
+const string REPLICATE_DEFAULT="replicateDefault";
+}
+
+// Received the ha-broker configuration object for the primary broker.
+void BrokerReplicator::doResponseHaBroker(Variant::Map& values) {
+ try {
+ ReplicateLevel mine = haBroker.getSettings().replicateDefault;
+ ReplicateLevel primary = replicateLevel(values[REPLICATE_DEFAULT].asString());
+ if (mine != primary) {
+ std::ostringstream os;
+ os << "Replicate default on backup (" << mine
+ << ") does not match primary (" << primary << ")";
+ haBroker.shutdown(os.str());
+ }
+ } catch (const std::exception& e) {
+ std::ostringstream os;
+ os << "Received invalid replicate default from primary: " << e.what();
+ haBroker.shutdown(os.str());
+ }
+}
+
void BrokerReplicator::startQueueReplicator(const boost::shared_ptr<Queue>& queue) {
- if (replicateLevel(queue->getSettings()) == RL_MESSAGES) {
+ if (replicateLevel(queue->getSettings()) == RL_ALL) {
boost::shared_ptr<QueueReplicator> qr(new QueueReplicator(queue, link));
- broker.getExchanges().registerExchange(qr);
+ if (!broker.getExchanges().registerExchange(qr))
+ throw Exception(QPID_MSG("Duplicate queue replicator " << qr->getName()));
qr->activate();
}
}
diff --git a/cpp/src/qpid/ha/BrokerReplicator.h b/cpp/src/qpid/ha/BrokerReplicator.h
index cfb6cf9a28..c9d7b9f74c 100644
--- a/cpp/src/qpid/ha/BrokerReplicator.h
+++ b/cpp/src/qpid/ha/BrokerReplicator.h
@@ -22,6 +22,7 @@
*
*/
+#include "ReplicateLevel.h"
#include "qpid/broker/Exchange.h"
#include "qpid/types/Variant.h"
#include <boost/shared_ptr.hpp>
@@ -35,7 +36,12 @@ class Bridge;
class SessionHandler;
}
+namespace framing {
+class FieldTable;
+}
+
namespace ha {
+class HaBroker;
/**
* Replicate configuration on a backup broker.
@@ -51,19 +57,23 @@ namespace ha {
class BrokerReplicator : public broker::Exchange
{
public:
- BrokerReplicator(const boost::shared_ptr<broker::Link>&);
+ BrokerReplicator(HaBroker&, const boost::shared_ptr<broker::Link>&);
~BrokerReplicator();
std::string getType() const;
// Exchange methods
bool bind(boost::shared_ptr<broker::Queue>, const std::string&, const framing::FieldTable*);
bool unbind(boost::shared_ptr<broker::Queue>, const std::string&, const framing::FieldTable*);
- void route(broker::Deliverable&, const std::string&, const framing::FieldTable*);
+ void route(broker::Deliverable&);
bool isBound(boost::shared_ptr<broker::Queue>, const std::string* const, const framing::FieldTable* const);
private:
void initializeBridge(broker::Bridge&, broker::SessionHandler&);
+ ReplicateLevel replicateLevel(const std::string&);
+ ReplicateLevel replicateLevel(const framing::FieldTable& args);
+ ReplicateLevel replicateLevel(const types::Variant::Map& args);
+
void doEventQueueDeclare(types::Variant::Map& values);
void doEventQueueDelete(types::Variant::Map& values);
void doEventExchangeDeclare(types::Variant::Map& values);
@@ -74,9 +84,11 @@ class BrokerReplicator : public broker::Exchange
void doResponseQueue(types::Variant::Map& values);
void doResponseExchange(types::Variant::Map& values);
void doResponseBind(types::Variant::Map& values);
+ void doResponseHaBroker(types::Variant::Map& values);
void startQueueReplicator(const boost::shared_ptr<broker::Queue>&);
+ HaBroker& haBroker;
broker::Broker& broker;
boost::shared_ptr<broker::Link> link;
};
diff --git a/cpp/src/qpid/ha/HaBroker.cpp b/cpp/src/qpid/ha/HaBroker.cpp
index 0d3bd51439..7d82fb63bd 100644
--- a/cpp/src/qpid/ha/HaBroker.cpp
+++ b/cpp/src/qpid/ha/HaBroker.cpp
@@ -25,10 +25,15 @@
#include "ReplicatingSubscription.h"
#include "qpid/Exception.h"
#include "qpid/broker/Broker.h"
+#include "qpid/broker/Link.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/SignalHandler.h"
#include "qpid/management/ManagementAgent.h"
#include "qmf/org/apache/qpid/ha/Package.h"
-#include "qmf/org/apache/qpid/ha/ArgsHaBrokerSetClientAddresses.h"
-#include "qmf/org/apache/qpid/ha/ArgsHaBrokerSetBrokerAddresses.h"
+#include "qmf/org/apache/qpid/ha/ArgsHaBrokerReplicate.h"
+#include "qmf/org/apache/qpid/ha/ArgsHaBrokerSetBrokers.h"
+#include "qmf/org/apache/qpid/ha/ArgsHaBrokerSetPublicBrokers.h"
+#include "qmf/org/apache/qpid/ha/ArgsHaBrokerSetExpectedBackups.h"
#include "qpid/log/Statement.h"
namespace qpid {
@@ -40,8 +45,10 @@ using namespace std;
namespace {
-const std::string PRIMARY="primary";
+const std::string STANDALONE="standalone";
+const std::string CATCH_UP="catch-up";
const std::string BACKUP="backup";
+const std::string PRIMARY="primary";
} // namespace
@@ -49,7 +56,6 @@ const std::string BACKUP="backup";
HaBroker::HaBroker(broker::Broker& b, const Settings& s)
: broker(b),
settings(s),
- backup(new Backup(b, s)),
mgmtObject(0)
{
// Register a factory for replicating subscriptions.
@@ -62,15 +68,20 @@ HaBroker::HaBroker(broker::Broker& b, const Settings& s)
ManagementAgent* ma = broker.getManagementAgent();
if (!ma)
throw Exception("Cannot start HA: management is disabled");
- if (ma) {
- _qmf::Package packageInit(ma);
- mgmtObject = new _qmf::HaBroker(ma, this, "ha-broker");
- mgmtObject->set_status(BACKUP);
- ma->addObject(mgmtObject);
- }
+ _qmf::Package packageInit(ma);
+ mgmtObject = new _qmf::HaBroker(ma, this, "ha-broker");
+ mgmtObject->set_status(settings.cluster ? BACKUP : STANDALONE);
+ mgmtObject->set_replicateDefault(str(settings.replicateDefault));
+ ma->addObject(mgmtObject);
+
+ // NOTE: lock is not needed in a constructor but we created it just to pass
+ // to the set functions.
sys::Mutex::ScopedLock l(lock);
if (!settings.clientUrl.empty()) setClientUrl(Url(settings.clientUrl), l);
if (!settings.brokerUrl.empty()) setBrokerUrl(Url(settings.brokerUrl), l);
+
+ // If we are in a cluster, we start in backup mode.
+ if (settings.cluster) backup.reset(new Backup(*this, s));
}
HaBroker::~HaBroker() {}
@@ -80,26 +91,47 @@ Manageable::status_t HaBroker::ManagementMethod (uint32_t methodId, Args& args,
switch (methodId) {
case _qmf::HaBroker::METHOD_PROMOTE: {
if (backup.get()) { // I am a backup
- // FIXME aconway 2012-01-26: create primary state before resetting backup
- // as that allows client connections.
+ // NOTE: resetting backup allows client connections, so any
+ // primary state should be set up here before backup.reset()
backup.reset();
- QPID_LOG(notice, "HA: Primary promoted from backup");
+ QPID_LOG(notice, "HA: Promoted to primary");
mgmtObject->set_status(PRIMARY);
}
break;
}
- case _qmf::HaBroker::METHOD_SETCLIENTADDRESSES: {
- setClientUrl(
- Url(dynamic_cast<_qmf::ArgsHaBrokerSetClientAddresses&>(args).
- i_clientAddresses), l);
+ case _qmf::HaBroker::METHOD_SETBROKERS: {
+ setBrokerUrl(Url(dynamic_cast<_qmf::ArgsHaBrokerSetBrokers&>(args).i_url), l);
+ break;
+ }
+ case _qmf::HaBroker::METHOD_SETPUBLICBROKERS: {
+ setClientUrl(Url(dynamic_cast<_qmf::ArgsHaBrokerSetPublicBrokers&>(args).i_url), l);
break;
}
- case _qmf::HaBroker::METHOD_SETBROKERADDRESSES: {
- setBrokerUrl(
- Url(dynamic_cast<_qmf::ArgsHaBrokerSetBrokerAddresses&>(args)
- .i_brokerAddresses), l);
+ case _qmf::HaBroker::METHOD_SETEXPECTEDBACKUPS: {
+ setExpectedBackups(dynamic_cast<_qmf::ArgsHaBrokerSetExpectedBackups&>(args).i_expectedBackups, l);
+ break;
+ }
+ case _qmf::HaBroker::METHOD_REPLICATE: {
+ _qmf::ArgsHaBrokerReplicate& bq_args =
+ dynamic_cast<_qmf::ArgsHaBrokerReplicate&>(args);
+ QPID_LOG(debug, "HA replicating individual queue "<< bq_args.i_queue << " from " << bq_args.i_broker);
+
+ boost::shared_ptr<broker::Queue> queue = broker.getQueues().get(bq_args.i_queue);
+ Url url(bq_args.i_broker);
+ string protocol = url[0].protocol.empty() ? "tcp" : url[0].protocol;
+ std::pair<broker::Link::shared_ptr, bool> result = broker.getLinks().declare(
+ url[0].host, url[0].port, protocol,
+ false, // durable
+ settings.mechanism, settings.username, settings.password);
+ boost::shared_ptr<broker::Link> link = result.first;
+ link->setUrl(url);
+ // Create a queue replicator
+ boost::shared_ptr<QueueReplicator> qr(new QueueReplicator(queue, link));
+ qr->activate();
+ broker.getExchanges().registerExchange(qr);
break;
}
+
default:
return Manageable::STATUS_UNKNOWN_METHOD;
}
@@ -114,24 +146,35 @@ void HaBroker::setClientUrl(const Url& url, const sys::Mutex::ScopedLock& l) {
void HaBroker::updateClientUrl(const sys::Mutex::ScopedLock&) {
Url url = clientUrl.empty() ? brokerUrl : clientUrl;
- assert(!url.empty());
- mgmtObject->set_clientAddresses(url.str());
+ if (url.empty()) throw Url::Invalid("HA client URL is empty");
+ mgmtObject->set_publicBrokers(url.str());
knownBrokers.clear();
knownBrokers.push_back(url);
- QPID_LOG(debug, "HA: Setting client known-brokers to: " << url);
+ QPID_LOG(debug, "HA: Setting client URL to: " << url);
}
void HaBroker::setBrokerUrl(const Url& url, const sys::Mutex::ScopedLock& l) {
- if (url.empty()) throw Exception("Invalid empty URL for HA broker failover");
+ if (url.empty()) throw Url::Invalid("HA broker URL is empty");
+ QPID_LOG(debug, "HA: Setting broker URL to: " << url);
brokerUrl = url;
- mgmtObject->set_brokerAddresses(brokerUrl.str());
+ mgmtObject->set_brokers(brokerUrl.str());
if (backup.get()) backup->setBrokerUrl(brokerUrl);
// Updating broker URL also updates defaulted client URL:
if (clientUrl.empty()) updateClientUrl(l);
}
+void HaBroker::setExpectedBackups(size_t n, const sys::Mutex::ScopedLock&) {
+ expectedBackups = n;
+ mgmtObject->set_expectedBackups(n);
+}
+
std::vector<Url> HaBroker::getKnownBrokers() const {
return knownBrokers;
}
+void HaBroker::shutdown(const std::string& message) {
+ QPID_LOG(critical, "Shutting down: " << message);
+ broker.shutdown();
+}
+
}} // namespace qpid::ha
diff --git a/cpp/src/qpid/ha/HaBroker.h b/cpp/src/qpid/ha/HaBroker.h
index 835a47c749..99b30fd36b 100644
--- a/cpp/src/qpid/ha/HaBroker.h
+++ b/cpp/src/qpid/ha/HaBroker.h
@@ -52,9 +52,16 @@ class HaBroker : public management::Manageable
management::Manageable::status_t ManagementMethod (
uint32_t methodId, management::Args& args, std::string& text);
+ broker::Broker& getBroker() { return broker; }
+ const Settings& getSettings() const { return settings; }
+
+ // Log a critical error message and shut down the broker.
+ void shutdown(const std::string& message);
+
private:
void setClientUrl(const Url&, const sys::Mutex::ScopedLock&);
void setBrokerUrl(const Url&, const sys::Mutex::ScopedLock&);
+ void setExpectedBackups(size_t, const sys::Mutex::ScopedLock&);
void updateClientUrl(const sys::Mutex::ScopedLock&);
bool isPrimary(const sys::Mutex::ScopedLock&) { return !backup.get(); }
std::vector<Url> getKnownBrokers() const;
@@ -67,6 +74,7 @@ class HaBroker : public management::Manageable
qmf::org::apache::qpid::ha::HaBroker* mgmtObject;
Url clientUrl, brokerUrl;
std::vector<Url> knownBrokers;
+ size_t expectedBackups;
};
}} // namespace qpid::ha
diff --git a/cpp/src/qpid/ha/HaPlugin.cpp b/cpp/src/qpid/ha/HaPlugin.cpp
index fc9e48411d..4da3b0d7d2 100644
--- a/cpp/src/qpid/ha/HaPlugin.cpp
+++ b/cpp/src/qpid/ha/HaPlugin.cpp
@@ -31,12 +31,23 @@ struct Options : public qpid::Options {
Settings& settings;
Options(Settings& s) : qpid::Options("HA Options"), settings(s) {
addOptions()
- ("ha-enable", optValue(settings.enabled, "yes|no"), "Enable High Availability features")
- ("ha-client-url", optValue(settings.clientUrl,"URL"), "URL that clients use to connect and fail over.")
- ("ha-broker-url", optValue(settings.brokerUrl,"URL"), "URL that backup brokers use to connect and fail over.")
- ("ha-username", optValue(settings.username, "USER"), "Username for connections between brokers")
- ("ha-password", optValue(settings.password, "PASS"), "Password for connections between brokers")
- ("ha-mechanism", optValue(settings.mechanism, "MECH"), "Authentication mechanism for connections between brokers")
+ ("ha-cluster", optValue(settings.cluster, "yes|no"),
+ "Join a HA active/passive cluster.")
+ ("ha-brokers", optValue(settings.brokerUrl,"URL"),
+ "URL that backup brokers use to connect and fail over.")
+ ("ha-public-brokers", optValue(settings.clientUrl,"URL"),
+ "URL that clients use to connect and fail over, defaults to ha-brokers.")
+ ("ha-replicate",
+ optValue(settings.replicateDefault, "LEVEL"),
+ "Replication level for creating queues and exchanges if there is no qpid.replicate argument supplied. LEVEL is 'none', 'configuration' or 'all'")
+ ("ha-expected-backups", optValue(settings.expectedBackups, "N"),
+ "Number of backups expected to be active in the HA cluster.")
+ ("ha-username", optValue(settings.username, "USER"),
+ "Username for connections between HA brokers")
+ ("ha-password", optValue(settings.password, "PASS"),
+ "Password for connections between HA brokers")
+ ("ha-mechanism", optValue(settings.mechanism, "MECH"),
+ "Authentication mechanism for connections between HA brokers")
;
}
};
@@ -55,10 +66,7 @@ struct HaPlugin : public Plugin {
void initialize(Plugin::Target& target) {
broker::Broker* broker = dynamic_cast<broker::Broker*>(&target);
- if (broker && settings.enabled) {
- haBroker.reset(new ha::HaBroker(*broker, settings));
- } else
- QPID_LOG(notice, "HA: Disabled");
+ if (broker) haBroker.reset(new ha::HaBroker(*broker, settings));
}
};
diff --git a/cpp/src/qpid/ha/QueueReplicator.cpp b/cpp/src/qpid/ha/QueueReplicator.cpp
index 0017cc82cd..633619be13 100644
--- a/cpp/src/qpid/ha/QueueReplicator.cpp
+++ b/cpp/src/qpid/ha/QueueReplicator.cpp
@@ -30,8 +30,8 @@
#include "qpid/framing/SequenceSet.h"
#include "qpid/framing/FieldTable.h"
#include "qpid/log/Statement.h"
+#include "qpid/Msg.h"
#include <boost/shared_ptr.hpp>
-#include <sstream>
namespace {
const std::string QPID_REPLICATOR_("qpid.replicator-");
@@ -54,10 +54,8 @@ std::string QueueReplicator::replicatorName(const std::string& queueName) {
QueueReplicator::QueueReplicator(boost::shared_ptr<Queue> q, boost::shared_ptr<Link> l)
: Exchange(replicatorName(q->getName()), 0, q->getBroker()), queue(q), link(l)
{
- std::stringstream ss;
- ss << "HA: Backup " << queue->getName() << ": ";
- logPrefix = ss.str();
- QPID_LOG(info, logPrefix << "Created, settings: " << q->getSettings());
+ logPrefix = "HA: Backup of " + queue->getName() + ": ";
+ QPID_LOG(info, logPrefix << "Created");
}
// This must be separate from the constructor so we can call shared_from_this.
@@ -77,7 +75,7 @@ void QueueReplicator::activate() {
0, // sync?
// Include shared_ptr to self to ensure we are not deleted
// before initializeBridge is called.
- boost::bind(&QueueReplicator::initializeBridge, this, _1, _2, shared_from_this())
+ boost::bind(&QueueReplicator::initializeBridge, shared_from_this(), _1, _2)
);
}
@@ -91,9 +89,7 @@ void QueueReplicator::deactivate() {
}
// Called in a broker connection thread when the bridge is created.
-// shared_ptr to self ensures we are not deleted before initializeBridge is called.
-void QueueReplicator::initializeBridge(Bridge& bridge, SessionHandler& sessionHandler,
- boost::shared_ptr<QueueReplicator> /*self*/) {
+void QueueReplicator::initializeBridge(Bridge& bridge, SessionHandler& sessionHandler) {
sys::Mutex::ScopedLock l(lock);
bridgeName = bridge.getName();
framing::AMQP_ServerProxy peer(sessionHandler.out);
@@ -141,27 +137,35 @@ void QueueReplicator::dequeue(SequenceNumber n, const sys::Mutex::ScopedLock&)
}
// Called in connection thread of the queues bridge to primary.
-void QueueReplicator::route(Deliverable& msg, const std::string& key, const FieldTable*)
+void QueueReplicator::route(Deliverable& msg)
{
- sys::Mutex::ScopedLock l(lock);
- if (key == DEQUEUE_EVENT_KEY) {
- SequenceSet dequeues = decodeContent<SequenceSet>(msg.getMessage());
- QPID_LOG(trace, logPrefix << "Dequeue: " << dequeues);
- //TODO: should be able to optimise the following
- for (SequenceSet::iterator i = dequeues.begin(); i != dequeues.end(); i++)
- dequeue(*i, l);
- } else if (key == POSITION_EVENT_KEY) {
- SequenceNumber position = decodeContent<SequenceNumber>(msg.getMessage());
- QPID_LOG(trace, logPrefix << "Position moved from " << queue->getPosition()
- << " to " << position);
- assert(queue->getPosition() <= position);
- //TODO aconway 2011-12-14: Optimize this?
- for (SequenceNumber i = queue->getPosition(); i < position; ++i)
- dequeue(i,l);
- queue->setPosition(position);
- } else {
- msg.deliverTo(queue);
- QPID_LOG(trace, logPrefix << "Enqueued message " << queue->getPosition());
+ try {
+ const std::string& key = msg.getMessage().getRoutingKey();
+ sys::Mutex::ScopedLock l(lock);
+ if (key == DEQUEUE_EVENT_KEY) {
+ SequenceSet dequeues = decodeContent<SequenceSet>(msg.getMessage());
+ QPID_LOG(trace, logPrefix << "Dequeue: " << dequeues);
+ //TODO: should be able to optimise the following
+ for (SequenceSet::iterator i = dequeues.begin(); i != dequeues.end(); i++)
+ dequeue(*i, l);
+ } else if (key == POSITION_EVENT_KEY) {
+ SequenceNumber position = decodeContent<SequenceNumber>(msg.getMessage());
+ QPID_LOG(trace, logPrefix << "Position moved from " << queue->getPosition()
+ << " to " << position);
+ if (queue->getPosition() > position) {
+ throw Exception(
+ QPID_MSG(logPrefix << "Invalid position update from "
+ << queue->getPosition() << " to " << position));
+ }
+ queue->setPosition(position);
+ } else {
+ msg.deliverTo(queue);
+ QPID_LOG(trace, logPrefix << "Enqueued message " << queue->getPosition());
+ }
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(critical, logPrefix << "Replication failed: " << e.what());
+ throw;
}
}
diff --git a/cpp/src/qpid/ha/QueueReplicator.h b/cpp/src/qpid/ha/QueueReplicator.h
index 9de7dd480c..bcbac988fa 100644
--- a/cpp/src/qpid/ha/QueueReplicator.h
+++ b/cpp/src/qpid/ha/QueueReplicator.h
@@ -66,12 +66,11 @@ class QueueReplicator : public broker::Exchange,
bool bind(boost::shared_ptr<broker::Queue
>, const std::string&, const framing::FieldTable*);
bool unbind(boost::shared_ptr<broker::Queue>, const std::string&, const framing::FieldTable*);
- void route(broker::Deliverable&, const std::string&, const framing::FieldTable*);
+ void route(broker::Deliverable&);
bool isBound(boost::shared_ptr<broker::Queue>, const std::string* const, const framing::FieldTable* const);
private:
- void initializeBridge(broker::Bridge& bridge, broker::SessionHandler& sessionHandler,
- boost::shared_ptr<QueueReplicator> self);
+ void initializeBridge(broker::Bridge& bridge, broker::SessionHandler& sessionHandler);
void dequeue(framing::SequenceNumber, const sys::Mutex::ScopedLock&);
std::string logPrefix;
diff --git a/cpp/src/qpid/ha/ReplicateLevel.cpp b/cpp/src/qpid/ha/ReplicateLevel.cpp
new file mode 100644
index 0000000000..4981577225
--- /dev/null
+++ b/cpp/src/qpid/ha/ReplicateLevel.cpp
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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 "ReplicateLevel.h"
+#include "qpid/Exception.h"
+#include "qpid/Msg.h"
+#include <iostream>
+#include <assert.h>
+
+namespace qpid {
+namespace ha {
+
+using namespace std;
+
+// Note replicateLevel is called during plugin-initialization which
+// happens in the static construction phase so these constants need
+// to be POD, they can't be class objects
+//
+namespace {
+const char* S_NONE="none";
+const char* S_CONFIGURATION="configuration";
+const char* S_ALL="all";
+}
+
+bool replicateLevel(const string& level, ReplicateLevel& out) {
+ if (level == S_NONE) { out = RL_NONE; return true; }
+ if (level == S_CONFIGURATION) { out = RL_CONFIGURATION; return true; }
+ if (level == S_ALL) { out = RL_ALL; return true; }
+ return false;
+}
+
+ReplicateLevel replicateLevel(const string& level) {
+ ReplicateLevel rl;
+ if (!replicateLevel(level, rl))
+ throw Exception("Invalid value for replication level: "+level);
+ return rl;
+}
+
+string str(ReplicateLevel l) {
+ const char* names[] = { S_NONE, S_CONFIGURATION, S_ALL };
+ if (l > RL_ALL)
+ throw Exception(QPID_MSG("Invalid value for replication level: " << l));
+ return names[l];
+}
+
+ostream& operator<<(ostream& o, ReplicateLevel rl) { return o << str(rl); }
+
+istream& operator>>(istream& i, ReplicateLevel& rl) {
+ string str;
+ i >> str;
+ rl = replicateLevel(str);
+ return i;
+}
+
+}} // namespace qpid::ha
diff --git a/cpp/src/qpid/framing/BodyHandler.h b/cpp/src/qpid/ha/ReplicateLevel.h
index 9ded737195..c11e03f0ce 100644
--- a/cpp/src/qpid/framing/BodyHandler.h
+++ b/cpp/src/qpid/ha/ReplicateLevel.h
@@ -1,5 +1,5 @@
-#ifndef _BodyHandler_
-#define _BodyHandler_
+#ifndef QPID_HA_REPLICATELEVEL_H
+#define QPID_HA_REPLICATELEVEL_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
@@ -22,35 +22,31 @@
*
*/
-#include <boost/shared_ptr.hpp>
+#include <string>
+#include <iosfwd>
namespace qpid {
-namespace framing {
-class AMQBody;
-class AMQMethodBody;
-class AMQHeaderBody;
-class AMQContentBody;
-class AMQHeartbeatBody;
+namespace ha {
+
+enum ReplicateLevel { RL_NONE, RL_CONFIGURATION, RL_ALL };
-// TODO aconway 2007-08-10: rework using Visitor pattern?
+/**
+ * If str is a valid replicate level, set out and return true.
+ */
+bool replicateLevel(const std::string& str, ReplicateLevel& out);
/**
- * Interface to handle incoming frame bodies.
- * Derived classes provide logic for each frame type.
+ *@return enum corresponding to string level.
+ *@throw qpid::Exception if level is not a valid replication level.
*/
-class BodyHandler {
- public:
- virtual ~BodyHandler();
- virtual void handleBody(AMQBody* body);
+ReplicateLevel replicateLevel(const std::string& level);
- protected:
- virtual void handleMethod(AMQMethodBody*) = 0;
- virtual void handleHeader(AMQHeaderBody*) = 0;
- virtual void handleContent(AMQContentBody*) = 0;
- virtual void handleHeartbeat(AMQHeartbeatBody*) = 0;
-};
+/**@return string form of replicate level */
+std::string str(ReplicateLevel l);
-}}
+std::ostream& operator<<(std::ostream&, ReplicateLevel);
+std::istream& operator>>(std::istream&, ReplicateLevel&);
+}} // namespaces qpid::ha
-#endif
+#endif /*!QPID_HA_REPLICATELEVEL_H*/
diff --git a/cpp/src/qpid/ha/ReplicatingSubscription.cpp b/cpp/src/qpid/ha/ReplicatingSubscription.cpp
index af6180305d..91a4538bc4 100644
--- a/cpp/src/qpid/ha/ReplicatingSubscription.cpp
+++ b/cpp/src/qpid/ha/ReplicatingSubscription.cpp
@@ -87,10 +87,13 @@ ReplicatingSubscription::ReplicatingSubscription(
events(new Queue(mask(name))),
consumer(new DelegatingConsumer(*this))
{
+ // Separate the remote part from a "local-remote" address.
+ string address = parent->getSession().getConnection().getUrl();
+ size_t i = address.find('-');
+ if (i != string::npos) address = address.substr(i+1);
+ logPrefix = "HA: Primary ";
stringstream ss;
- ss << "HA: Primary: " << getQueue()->getName() << " at "
- << parent->getSession().getConnection().getUrl() << ": ";
- logPrefix = ss.str();
+ logSuffix = " (" + address + ")";
// FIXME aconway 2011-12-09: Failover optimization removed.
// There was code here to re-use messages already on the backup
@@ -99,7 +102,7 @@ ReplicatingSubscription::ReplicatingSubscription(
// can be re-introduced later. Last revision with the optimization:
// r1213258 | QPID-3603: Fix QueueReplicator subscription parameters.
- QPID_LOG(debug, logPrefix << "Created backup subscription " << getName());
+ QPID_LOG(debug, logPrefix << "created backup subscription " << getName() << logSuffix);
// FIXME aconway 2011-12-15: ConsumerImpl::position is left at 0
// so we will start consuming from the lowest numbered message.
@@ -109,23 +112,36 @@ ReplicatingSubscription::ReplicatingSubscription(
// Message is delivered in the subscription's connection thread.
bool ReplicatingSubscription::deliver(QueuedMessage& m) {
- // Add position events for the subscribed queue, not for the internal event queue.
- if (m.queue && m.queue == getQueue().get()) {
- sys::Mutex::ScopedLock l(lock);
- assert(position == m.position);
- // m.position is the position of the newly enqueued m on the local queue.
- // backupPosition is latest position on the backup queue (before enqueueing m.)
- assert(m.position > backupPosition);
- if (m.position - backupPosition > 1) {
- // Position has advanced because of messages dequeued ahead of us.
- SequenceNumber send(m.position);
- --send; // Send the position before m was enqueued.
- sendPositionEvent(send, l);
+ try {
+ // Add position events for the subscribed queue, not for the internal event queue.
+ if (m.queue && m.queue == getQueue().get()) {
+ sys::Mutex::ScopedLock l(lock);
+ if (position != m.position)
+ throw Exception(
+ QPID_MSG("Expected position " << position
+ << " but got " << m.position));
+ // m.position is the position of the newly enqueued m on the local queue.
+ // backupPosition is latest position on the backup queue (before enqueueing m.)
+ if (m.position <= backupPosition)
+ throw Exception(
+ QPID_MSG("Expected position > " << backupPosition
+ << " but got " << m.position));
+
+ if (m.position - backupPosition > 1) {
+ // Position has advanced because of messages dequeued ahead of us.
+ SequenceNumber send(m.position);
+ --send; // Send the position before m was enqueued.
+ sendPositionEvent(send, l);
+ }
+ backupPosition = m.position;
+ QPID_LOG(trace, logPrefix << "replicating " << m << logSuffix);
}
- backupPosition = m.position;
- QPID_LOG(trace, logPrefix << "Replicating message " << m.position);
+ return ConsumerImpl::deliver(m);
+ } catch (const std::exception& e) {
+ QPID_LOG(critical, logPrefix << "error replicating " << getQueue()->getName()
+ << logSuffix << ": " << e.what());
+ throw;
}
- return ConsumerImpl::deliver(m);
}
ReplicatingSubscription::~ReplicatingSubscription() {}
@@ -139,7 +155,7 @@ void ReplicatingSubscription::complete(
{
// Handle completions for the subscribed queue, not the internal event queue.
if (qm.queue && qm.queue == getQueue().get()) {
- QPID_LOG(trace, logPrefix << "Completed message " << qm.position);
+ QPID_LOG(trace, logPrefix << "completed " << qm << logSuffix);
Delayed::iterator i= delayed.find(qm.position);
// The same message can be completed twice, by acknowledged and
// dequeued, remove it from the set so it only gets completed
@@ -157,7 +173,7 @@ void ReplicatingSubscription::complete(
void ReplicatingSubscription::enqueued(const QueuedMessage& qm) {
sys::Mutex::ScopedLock l(lock);
// Delay completion
- QPID_LOG(trace, logPrefix << "Delaying completion of message " << qm.position);
+ QPID_LOG(trace, logPrefix << "delaying completion of " << qm << logSuffix);
qm.payload->getIngressCompletion().startCompleter();
assert(delayed.find(qm.position) == delayed.end());
delayed[qm.position] = qm;
@@ -168,7 +184,7 @@ void ReplicatingSubscription::enqueued(const QueuedMessage& qm) {
void ReplicatingSubscription::cancelComplete(
const Delayed::value_type& v, const sys::Mutex::ScopedLock&)
{
- QPID_LOG(trace, logPrefix << "Cancel completed message " << v.second.position);
+ QPID_LOG(trace, logPrefix << "cancel completed " << v.second << logSuffix);
v.second.payload->getIngressCompletion().finishCompleter();
}
@@ -179,7 +195,7 @@ void ReplicatingSubscription::cancel()
boost::dynamic_pointer_cast<QueueObserver>(shared_from_this()));
{
sys::Mutex::ScopedLock l(lock);
- QPID_LOG(debug, logPrefix <<"Cancelled backup subscription " << getName());
+ QPID_LOG(debug, logPrefix << "cancel backup subscription " << getName() << logSuffix);
for_each(delayed.begin(), delayed.end(),
boost::bind(&ReplicatingSubscription::cancelComplete, this, _1, boost::ref(l)));
delayed.clear();
@@ -201,7 +217,8 @@ bool ReplicatingSubscription::hideDeletedError() { return true; }
// Called with lock held. Called in subscription's connection thread.
void ReplicatingSubscription::sendDequeueEvent(const sys::Mutex::ScopedLock& l)
{
- QPID_LOG(trace, logPrefix << "Sending dequeues " << dequeues);
+ QPID_LOG(trace, logPrefix << "sending dequeues " << dequeues
+ << " from " << getQueue()->getName() << logSuffix);
string buf(dequeues.encodedSize(),'\0');
framing::Buffer buffer(&buf[0], buf.size());
dequeues.encode(buffer);
@@ -216,7 +233,7 @@ void ReplicatingSubscription::dequeued(const QueuedMessage& qm)
{
{
sys::Mutex::ScopedLock l(lock);
- QPID_LOG(trace, logPrefix << "Dequeued message " << qm.position);
+ QPID_LOG(trace, logPrefix << "dequeued " << qm << logSuffix);
dequeues.add(qm.position);
// If we have not yet sent this message to the backup, then
// complete it now as it will never be accepted.
@@ -229,8 +246,8 @@ void ReplicatingSubscription::dequeued(const QueuedMessage& qm)
void ReplicatingSubscription::sendPositionEvent(
SequenceNumber position, const sys::Mutex::ScopedLock&l )
{
- QPID_LOG(trace, logPrefix << "Sending position " << position
- << ", was " << backupPosition);
+ QPID_LOG(trace, logPrefix << "sending position " << position
+ << ", was " << backupPosition << logSuffix);
string buf(backupPosition.encodedSize(),'\0');
framing::Buffer buffer(&buf[0], buf.size());
position.encode(buffer);
diff --git a/cpp/src/qpid/ha/ReplicatingSubscription.h b/cpp/src/qpid/ha/ReplicatingSubscription.h
index e311f9505a..f9176915f6 100644
--- a/cpp/src/qpid/ha/ReplicatingSubscription.h
+++ b/cpp/src/qpid/ha/ReplicatingSubscription.h
@@ -33,7 +33,7 @@ namespace qpid {
namespace broker {
class Message;
class Queue;
-class QueuedMessage;
+struct QueuedMessage;
class OwnershipToken;
}
@@ -94,7 +94,7 @@ class ReplicatingSubscription : public broker::SemanticState::ConsumerImpl,
bool doDispatch();
private:
typedef std::map<framing::SequenceNumber, broker::QueuedMessage> Delayed;
- std::string logPrefix;
+ std::string logPrefix, logSuffix;
boost::shared_ptr<broker::Queue> events;
boost::shared_ptr<broker::Consumer> consumer;
Delayed delayed;
diff --git a/cpp/src/qpid/ha/Settings.h b/cpp/src/qpid/ha/Settings.h
index 049c873b9f..bf70c3f3f7 100644
--- a/cpp/src/qpid/ha/Settings.h
+++ b/cpp/src/qpid/ha/Settings.h
@@ -22,6 +22,7 @@
*
*/
+#include "ReplicateLevel.h"
#include <string>
namespace qpid {
@@ -33,10 +34,12 @@ namespace ha {
class Settings
{
public:
- Settings() : enabled(false) {}
- bool enabled;
+ Settings() : cluster(false), expectedBackups(0), replicateDefault(RL_NONE) {}
+ bool cluster; // True if we are a cluster member.
std::string clientUrl;
std::string brokerUrl;
+ size_t expectedBackups;
+ ReplicateLevel replicateDefault;
std::string username, password, mechanism;
private:
};
diff --git a/cpp/src/qpid/ha/management-schema.xml b/cpp/src/qpid/ha/management-schema.xml
index fe4a14d111..363dff61fb 100644
--- a/cpp/src/qpid/ha/management-schema.xml
+++ b/cpp/src/qpid/ha/management-schema.xml
@@ -22,16 +22,39 @@
<!-- Monitor and control HA status of a broker. -->
<class name="HaBroker">
<property name="name" type="sstr" access="RC" index="y" desc="Primary Key"/>
+
<property name="status" type="sstr" desc="HA status: primary or backup"/>
- <property name="clientAddresses" type="sstr" desc="List of addresses used by clients to connect to the HA cluster."/>
- <property name="brokerAddresses" type="sstr" desc="List of addresses used by HA brokers to connect to each other."/>
+
+ <property name="brokers" type="sstr"
+ desc="Multiple-address URL used by HA brokers to connect to each other."/>
+
+ <property name="publicBrokers" type="sstr"
+ desc="Multiple-address URL used by clients to connect to the HA brokers."/>
+
+ <property name="expectedBackups" type="uint16"
+ desc="Number of HA backup brokers expected."/>
+
+ <property
+ name="replicateDefault" type="sstr"
+ desc="Replicate value for queues/exchanges without a qpid.replicate argument"/>
<method name="promote" desc="Promote a backup broker to primary."/>
- <method name="setClientAddresses" desc="Set HA client addresses">
- <arg name="clientAddresses" type="sstr" dir="I"/>
+
+ <method name="setBrokers" desc="Set URL for HA brokers to connect to each other.">
+ <arg name="url" type="sstr" dir="I"/>
</method>
- <method name="setBrokerAddresses" desc="Set HA broker addresses">
- <arg name="brokerAddresses" type="sstr" dir="I"/>
+
+ <method name="setPublicBrokers" desc="Set URL for clients to connect to HA brokers">
+ <arg name="url" type="sstr" dir="I"/>
+ </method>
+
+ <method name="setExpectedBackups" desc="Set number of backups expected">
+ <arg name="expectedBackups" type="uint16" dir="I"/>
+ </method>
+
+ <method name="replicate" desc="Replicate individual queue from remote broker.">
+ <arg name="broker" type="sstr" dir="I"/>
+ <arg name="queue" type="sstr" dir="I"/>
</method>
</class>
diff --git a/cpp/src/qpid/log/Statement.cpp b/cpp/src/qpid/log/Statement.cpp
index 7dfdf08703..79f7a28100 100644
--- a/cpp/src/qpid/log/Statement.cpp
+++ b/cpp/src/qpid/log/Statement.cpp
@@ -55,6 +55,50 @@ void Statement::log(const std::string& message) {
}
Statement::Initializer::Initializer(Statement& s) : statement(s) {
+ // QPID-3891
+ // From the given BOOST_CURRENT_FUNCTION name extract only the
+ // namespace-qualified-functionName, skipping return and calling args.
+ // Given:
+ // <possible return value type> qpid::name::space::Function(args)
+ // Return:
+ // "qpid::name::space::Function".
+ if (s.function != NULL) {
+ bool foundOParen(false);
+ const char * opPtr;
+ for (opPtr = s.function; *opPtr != '\0'; opPtr++) {
+ if (*opPtr == '(') {
+ foundOParen = true;
+ break;
+ }
+ }
+
+ if (foundOParen) {
+ const char * bPtr = opPtr;
+ for (bPtr = opPtr; bPtr > s.function; bPtr--) {
+ if (bPtr[-1] == ' ') {
+ break;
+ }
+ }
+
+ size_t nStoreSize = opPtr - bPtr;
+ if (nStoreSize > 0) {
+ // Note: the struct into which this name is stored
+ // is static and is never deleted.
+ char * nStore = new char[nStoreSize + 1];
+ std::copy (bPtr, opPtr, nStore);
+ nStore[nStoreSize] = '\0';
+
+ s.function = nStore;
+ } else {
+ // Ignore zero length name
+ }
+ } else {
+ // No name found - do nothing
+ }
+ } else {
+ // no function-name pointer to process
+ }
+
Logger::instance().add(s);
}
diff --git a/cpp/src/qpid/log/posix/SinkOptions.cpp b/cpp/src/qpid/log/posix/SinkOptions.cpp
index ffa7633e3b..8459938e5c 100644
--- a/cpp/src/qpid/log/posix/SinkOptions.cpp
+++ b/cpp/src/qpid/log/posix/SinkOptions.cpp
@@ -30,6 +30,10 @@
using std::string;
using qpid::Exception;
+namespace qpid {
+namespace log {
+namespace posix {
+
namespace {
// SyslogFacilities maps from syslog values to the text equivalents.
@@ -110,10 +114,6 @@ std::string basename(const std::string path) {
} // namespace
-namespace qpid {
-namespace log {
-namespace posix {
-
std::ostream& operator<<(std::ostream& o, const SyslogFacility& f) {
return o << SyslogFacilities().name(f.value);
}
diff --git a/cpp/src/qpid/management/ManagementAgent.cpp b/cpp/src/qpid/management/ManagementAgent.cpp
index 741ef442b0..062a530706 100644
--- a/cpp/src/qpid/management/ManagementAgent.cpp
+++ b/cpp/src/qpid/management/ManagementAgent.cpp
@@ -30,6 +30,7 @@
#include "qpid/log/Statement.h"
#include <qpid/broker/Message.h>
#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/FieldValue.h"
#include "qpid/sys/Time.h"
#include "qpid/sys/Thread.h"
#include "qpid/broker/ConnectionState.h"
@@ -44,14 +45,15 @@
#include <sstream>
#include <typeinfo>
+namespace qpid {
+namespace management {
+
using boost::intrusive_ptr;
using qpid::framing::Uuid;
using qpid::types::Variant;
using qpid::amqp_0_10::MapCodec;
using qpid::amqp_0_10::ListCodec;
-using qpid::sys::Mutex;
using namespace qpid::framing;
-using namespace qpid::management;
using namespace qpid::broker;
using namespace qpid;
using namespace std;
@@ -117,7 +119,7 @@ ManagementAgent::RemoteAgent::~RemoteAgent ()
}
ManagementAgent::ManagementAgent (const bool qmfV1, const bool qmfV2) :
- threadPoolSize(1), interval(10), broker(0), timer(0),
+ threadPoolSize(1), publish(true), interval(10), broker(0), timer(0),
startTime(sys::now()),
suppressed(false), disallowAllV1Methods(false),
vendorNameKey(defaultVendorName), productNameKey(defaultProductName),
@@ -164,10 +166,11 @@ ManagementAgent::~ManagementAgent ()
}
}
-void ManagementAgent::configure(const string& _dataDir, uint16_t _interval,
+void ManagementAgent::configure(const string& _dataDir, bool _publish, uint16_t _interval,
qpid::broker::Broker* _broker, int _threads)
{
dataDir = _dataDir;
+ publish = _publish;
interval = _interval;
broker = _broker;
threadPoolSize = _threads;
@@ -428,16 +431,17 @@ void ManagementAgent::raiseEvent(const ManagementEvent& event, severity_t severi
}
ManagementAgent::Periodic::Periodic (ManagementAgent& _agent, uint32_t _seconds)
- : TimerTask (sys::Duration((_seconds ? _seconds : 1) * sys::TIME_SEC),
- "ManagementAgent::periodicProcessing"),
+ : TimerTask(sys::Duration((_seconds ? _seconds : 1) * sys::TIME_SEC),
+ "ManagementAgent::periodicProcessing"),
agent(_agent) {}
-ManagementAgent::Periodic::~Periodic () {}
+ManagementAgent::Periodic::~Periodic() {}
-void ManagementAgent::Periodic::fire ()
+void ManagementAgent::Periodic::fire()
{
- agent.timer->add (new Periodic (agent, agent.interval));
- agent.periodicProcessing ();
+ setupNextFire();
+ agent.timer->add(this);
+ agent.periodicProcessing();
}
void ManagementAgent::clientAdded (const string& routingKey)
@@ -562,7 +566,7 @@ void ManagementAgent::sendBufferLH(Buffer& buf,
DeliverableMessage deliverable (msg);
try {
- exchange->route(deliverable, routingKey, 0);
+ exchange->route(deliverable);
} catch(exception&) {}
}
buf.reset();
@@ -639,7 +643,7 @@ void ManagementAgent::sendBufferLH(const string& data,
DeliverableMessage deliverable (msg);
try {
- exchange->route(deliverable, routingKey, 0);
+ exchange->route(deliverable);
} catch(exception&) {}
}
}
@@ -719,11 +723,16 @@ void ManagementAgent::periodicProcessing (void)
string routingKey;
string sBuf;
- uint64_t uptime = sys::Duration(startTime, sys::now());
- static_cast<_qmf::Broker*>(broker->GetManagementObject())->set_uptime(uptime);
-
moveNewObjectsLH();
- qpid::sys::MemStat::loadMemInfo(memstat);
+
+ //
+ // If we're publishing updates, get the latest memory statistics and uptime now
+ //
+ if (publish) {
+ uint64_t uptime = sys::Duration(startTime, sys::now());
+ static_cast<_qmf::Broker*>(broker->GetManagementObject())->set_uptime(uptime);
+ qpid::sys::MemStat::loadMemInfo(memstat);
+ }
//
// Clear the been-here flag on all objects in the map.
@@ -747,6 +756,14 @@ void ManagementAgent::periodicProcessing (void)
// would incorrectly think the object was deleted. See QPID-2997
//
bool objectsDeleted = moveDeletedObjectsLH();
+
+ //
+ // If we are not publishing updates, just clear the pending deletes. There's no
+ // need to tell anybody.
+ //
+ if (!publish)
+ pendingDeletedObjs.clear();
+
if (!pendingDeletedObjs.empty()) {
// use a temporary copy of the pending deletes so dropping the lock when
// the buffer is sent is safe.
@@ -867,7 +884,9 @@ void ManagementAgent::periodicProcessing (void)
// sendBuffer(). This allows the managementObjects map to be altered during the
// sendBuffer() call, so always restart the search after a sendBuffer() call
//
- while (1) {
+ // If publish is disabled, don't send any updates.
+ //
+ while (publish) {
msgBuffer.reset();
Variant::List list_;
uint32_t pcount;
@@ -1023,10 +1042,9 @@ void ManagementAgent::periodicProcessing (void)
if (objectsDeleted) deleteOrphanedAgentsLH();
- // heartbeat generation
+ // heartbeat generation. Note that heartbeats need to be sent even if publish is disabled.
if (qmf1Support) {
-#define BUFSIZE 65536
uint32_t contentSize;
char msgChars[BUFSIZE];
Buffer msgBuffer(msgChars, BUFSIZE);
@@ -1087,7 +1105,7 @@ void ManagementAgent::deleteObjectNowLH(const ObjectId& oid)
Variant::List list_;
stringstream v1key, v2key;
- if (qmf1Support) {
+ if (publish && qmf1Support) {
string sBuf;
v1key << "console.obj.1.0." << object->getPackageName() << "." << object->getClassName();
@@ -1096,7 +1114,7 @@ void ManagementAgent::deleteObjectNowLH(const ObjectId& oid)
msgBuffer.putRawData(sBuf);
}
- if (qmf2Support) {
+ if (publish && qmf2Support) {
Variant::Map map_;
Variant::Map values;
@@ -1121,14 +1139,14 @@ void ManagementAgent::deleteObjectNowLH(const ObjectId& oid)
// object deleted, ok to drop lock now.
- if (qmf1Support) {
+ if (publish && qmf1Support) {
uint32_t contentSize = msgBuffer.getPosition();
msgBuffer.reset();
sendBufferLH(msgBuffer, contentSize, mExchange, v1key.str());
QPID_LOG(debug, "SEND Immediate(delete) ContentInd to=" << v1key.str());
}
- if (qmf2Support) {
+ if (publish && qmf2Support) {
Variant::Map headers;
headers["method"] = "indication";
headers["qmf.opcode"] = "_data_indication";
@@ -1841,6 +1859,12 @@ void ManagementAgent::handleGetQueryLH(Buffer& inBuffer, const string& replyToKe
if (className == "memory")
qpid::sys::MemStat::loadMemInfo(memstat);
+ if (className == "broker") {
+ uint64_t uptime = sys::Duration(startTime, sys::now());
+ static_cast<_qmf::Broker*>(broker->GetManagementObject())->set_uptime(uptime);
+ }
+
+
// build up a set of all objects to be dumped
for (ManagementObjectMap::iterator iter = managementObjects.begin();
iter != managementObjects.end();
@@ -1956,6 +1980,11 @@ void ManagementAgent::handleGetQueryLH(const string& body, const string& rte, co
if (className == "memory")
qpid::sys::MemStat::loadMemInfo(memstat);
+ if (className == "broker") {
+ uint64_t uptime = sys::Duration(startTime, sys::now());
+ static_cast<_qmf::Broker*>(broker->GetManagementObject())->set_uptime(uptime);
+ }
+
/*
* Unpack the _object_id element of the query if it is present. If it is present, find that one
* object and return it. If it is not present, send a class-based result.
@@ -2934,9 +2963,6 @@ bool ManagementAgent::moveDeletedObjectsLH() {
return !deleteList.empty();
}
-namespace qpid {
-namespace management {
-
namespace {
QPID_TSS const qpid::broker::ConnectionState* executionContext = 0;
}
@@ -2951,3 +2977,4 @@ const qpid::broker::ConnectionState* getManagementExecutionContext()
}
}}
+
diff --git a/cpp/src/qpid/management/ManagementAgent.h b/cpp/src/qpid/management/ManagementAgent.h
index f68bfe0577..c7e830dcf5 100644
--- a/cpp/src/qpid/management/ManagementAgent.h
+++ b/cpp/src/qpid/management/ManagementAgent.h
@@ -36,7 +36,6 @@
#include "qpid/sys/MemStat.h"
#include "qpid/types/Variant.h"
#include <qpid/framing/AMQFrame.h>
-#include <qpid/framing/FieldValue.h>
#include <qpid/framing/ResizableBuffer.h>
#include <memory>
#include <string>
@@ -72,7 +71,7 @@ public:
virtual ~ManagementAgent ();
/** Called before plugins are initialized */
- void configure (const std::string& dataDir, uint16_t interval,
+ void configure (const std::string& dataDir, bool publish, uint16_t interval,
qpid::broker::Broker* broker, int threadPoolSize);
/** Called after plugins are initialized. */
void pluginsInitialized();
@@ -300,6 +299,7 @@ private:
qpid::broker::Exchange::shared_ptr v2Topic;
qpid::broker::Exchange::shared_ptr v2Direct;
std::string dataDir;
+ bool publish;
uint16_t interval;
qpid::broker::Broker* broker;
qpid::sys::Timer* timer;
diff --git a/cpp/src/qpid/management/ManagementDirectExchange.cpp b/cpp/src/qpid/management/ManagementDirectExchange.cpp
index 1d5f8bbd6b..312eacf462 100644
--- a/cpp/src/qpid/management/ManagementDirectExchange.cpp
+++ b/cpp/src/qpid/management/ManagementDirectExchange.cpp
@@ -40,17 +40,17 @@ ManagementDirectExchange::ManagementDirectExchange(const std::string& _name,
DirectExchange(_name, _durable, _args, _parent, b),
managementAgent(0) {}
-void ManagementDirectExchange::route(Deliverable& msg,
- const string& routingKey,
- const FieldTable* args)
+void ManagementDirectExchange::route(Deliverable& msg)
{
bool routeIt = true;
+ const string& routingKey = msg.getMessage().getRoutingKey();
+ const FieldTable* args = msg.getMessage().getApplicationHeaders();
if (managementAgent)
routeIt = managementAgent->dispatchCommand(msg, routingKey, args, false, qmfVersion);
if (routeIt)
- DirectExchange::route(msg, routingKey, args);
+ DirectExchange::route(msg);
}
void ManagementDirectExchange::setManagmentAgent(ManagementAgent* agent, int qv)
diff --git a/cpp/src/qpid/management/ManagementDirectExchange.h b/cpp/src/qpid/management/ManagementDirectExchange.h
index 7507179c06..582354d723 100644
--- a/cpp/src/qpid/management/ManagementDirectExchange.h
+++ b/cpp/src/qpid/management/ManagementDirectExchange.h
@@ -43,9 +43,7 @@ class ManagementDirectExchange : public virtual DirectExchange
virtual std::string getType() const { return typeName; }
- virtual void route(Deliverable& msg,
- const std::string& routingKey,
- const qpid::framing::FieldTable* args);
+ virtual void route(Deliverable& msg);
void setManagmentAgent(management::ManagementAgent* agent, int qmfVersion);
diff --git a/cpp/src/qpid/management/ManagementTopicExchange.cpp b/cpp/src/qpid/management/ManagementTopicExchange.cpp
index ee8657646f..587cc660df 100644
--- a/cpp/src/qpid/management/ManagementTopicExchange.cpp
+++ b/cpp/src/qpid/management/ManagementTopicExchange.cpp
@@ -39,18 +39,18 @@ ManagementTopicExchange::ManagementTopicExchange(const std::string& _name,
TopicExchange(_name, _durable, _args, _parent, b),
managementAgent(0) {}
-void ManagementTopicExchange::route(Deliverable& msg,
- const string& routingKey,
- const FieldTable* args)
+void ManagementTopicExchange::route(Deliverable& msg)
{
bool routeIt = true;
+ const 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);
if (routeIt)
- TopicExchange::route(msg, routingKey, args);
+ TopicExchange::route(msg);
}
bool ManagementTopicExchange::bind(Queue::shared_ptr queue,
diff --git a/cpp/src/qpid/management/ManagementTopicExchange.h b/cpp/src/qpid/management/ManagementTopicExchange.h
index 232300265e..eff01a8552 100644
--- a/cpp/src/qpid/management/ManagementTopicExchange.h
+++ b/cpp/src/qpid/management/ManagementTopicExchange.h
@@ -43,9 +43,7 @@ class ManagementTopicExchange : public virtual TopicExchange
virtual std::string getType() const { return typeName; }
- virtual void route(Deliverable& msg,
- const std::string& routingKey,
- const qpid::framing::FieldTable* args);
+ virtual void route(Deliverable& msg);
virtual bool bind(Queue::shared_ptr queue,
const std::string& routingKey,
diff --git a/cpp/src/qpid/replication/ReplicatingEventListener.cpp b/cpp/src/qpid/replication/ReplicatingEventListener.cpp
index 0ced4d9161..9284bda388 100644
--- a/cpp/src/qpid/replication/ReplicatingEventListener.cpp
+++ b/cpp/src/qpid/replication/ReplicatingEventListener.cpp
@@ -80,7 +80,7 @@ void ReplicatingEventListener::route(boost::intrusive_ptr<qpid::broker::Message>
try {
if (exchange) {
DeliverableMessage deliverable(msg);
- exchange->route(deliverable, msg->getRoutingKey(), msg->getApplicationHeaders());
+ exchange->route(deliverable);
} else if (queue) {
queue->deliver(msg);
} else {
@@ -131,7 +131,7 @@ boost::intrusive_ptr<Message> ReplicatingEventListener::cloneMessage(Queue& queu
//cloned body:
AMQFrame header(*original->getFrames().getHeaders());
header.setBof(false);
- header.setEof(!original->getFrames().getContentSize());//if there is any content then the header is not the end of the frameset
+ 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);
diff --git a/cpp/src/qpid/replication/ReplicationExchange.cpp b/cpp/src/qpid/replication/ReplicationExchange.cpp
index 89a2bf516d..66f4f14d0c 100644
--- a/cpp/src/qpid/replication/ReplicationExchange.cpp
+++ b/cpp/src/qpid/replication/ReplicationExchange.cpp
@@ -50,8 +50,9 @@ ReplicationExchange::ReplicationExchange(const std::string& name, bool durable,
std::string ReplicationExchange::getType() const { return typeName; }
-void ReplicationExchange::route(Deliverable& msg, const std::string& /*routingKey*/, const FieldTable* args)
+void ReplicationExchange::route(Deliverable& msg)
{
+ const FieldTable* args = msg.getMessage().getApplicationHeaders();
if (mgmtExchange != 0) {
mgmtExchange->inc_msgReceives();
mgmtExchange->inc_byteReceives(msg.contentSize());
@@ -59,7 +60,13 @@ void ReplicationExchange::route(Deliverable& msg, const std::string& /*routingKe
if (args) {
int eventType = args->getAsInt(REPLICATION_EVENT_TYPE);
if (eventType) {
- if (isDuplicate(args)) return;
+ if (isDuplicate(args)) {
+ if (mgmtExchange != 0) {
+ mgmtExchange->inc_msgDrops();
+ mgmtExchange->inc_byteDrops(msg.contentSize());
+ }
+ return;
+ }
switch (eventType) {
case ENQUEUE:
handleEnqueueEvent(args, msg);
diff --git a/cpp/src/qpid/replication/ReplicationExchange.h b/cpp/src/qpid/replication/ReplicationExchange.h
index 4b34e0df13..ff0a98c48e 100644
--- a/cpp/src/qpid/replication/ReplicationExchange.h
+++ b/cpp/src/qpid/replication/ReplicationExchange.h
@@ -52,7 +52,7 @@ class ReplicationExchange : public qpid::broker::Exchange
std::string getType() const;
- void route(qpid::broker::Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ 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);
diff --git a/cpp/src/qpid/store/MessageStorePlugin.cpp b/cpp/src/qpid/store/MessageStorePlugin.cpp
index 2a8d971987..20231bf910 100644
--- a/cpp/src/qpid/store/MessageStorePlugin.cpp
+++ b/cpp/src/qpid/store/MessageStorePlugin.cpp
@@ -28,6 +28,9 @@
#include "qpid/DataDir.h"
#include "qpid/log/Statement.h"
+namespace qpid {
+namespace store {
+
/*
* The MessageStore pointer given to the Broker points to static storage.
* Thus, it cannot be deleted, especially by the broker. To prevent deletion,
@@ -42,9 +45,6 @@ namespace {
};
}
-namespace qpid {
-namespace store {
-
static MessageStorePlugin static_instance_registers_plugin;
diff --git a/cpp/src/qpid/store/ms-clfs/MessageLog.cpp b/cpp/src/qpid/store/ms-clfs/MessageLog.cpp
index 14d63a4cd4..849a0a44e8 100644
--- a/cpp/src/qpid/store/ms-clfs/MessageLog.cpp
+++ b/cpp/src/qpid/store/ms-clfs/MessageLog.cpp
@@ -32,6 +32,10 @@
#include "MessageLog.h"
#include "Lsn.h"
+namespace qpid {
+namespace store {
+namespace ms_clfs {
+
namespace {
// Structures that hold log records. Each has a type field at the start.
@@ -97,10 +101,6 @@ struct MessageDequeue {
} // namespace
-namespace qpid {
-namespace store {
-namespace ms_clfs {
-
void
MessageLog::initialize()
{
diff --git a/cpp/src/qpid/store/ms-clfs/Transaction.h b/cpp/src/qpid/store/ms-clfs/Transaction.h
index fd07f2fb2e..499b01d503 100644
--- a/cpp/src/qpid/store/ms-clfs/Transaction.h
+++ b/cpp/src/qpid/store/ms-clfs/Transaction.h
@@ -27,6 +27,7 @@
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
+#include <vector>
#include "TransactionLog.h"
diff --git a/cpp/src/qpid/store/ms-clfs/TransactionLog.cpp b/cpp/src/qpid/store/ms-clfs/TransactionLog.cpp
index 04780e83e8..0ef046d7c8 100644
--- a/cpp/src/qpid/store/ms-clfs/TransactionLog.cpp
+++ b/cpp/src/qpid/store/ms-clfs/TransactionLog.cpp
@@ -33,6 +33,10 @@
#include "Transaction.h"
#include "Lsn.h"
+namespace qpid {
+namespace store {
+namespace ms_clfs {
+
namespace {
// Structures that hold log records. Each has a type field at the start.
@@ -95,10 +99,6 @@ struct TransactionDelete {
} // namespace
-namespace qpid {
-namespace store {
-namespace ms_clfs {
-
void
TransactionLog::initialize()
{
diff --git a/cpp/src/qpid/sys/apr/APRPool.h b/cpp/src/qpid/sys/MemStat.h
index da7661fcfa..d855786cd5 100644
--- a/cpp/src/qpid/sys/apr/APRPool.h
+++ b/cpp/src/qpid/sys/MemStat.h
@@ -1,6 +1,3 @@
-#ifndef _APRPool_
-#define _APRPool_
-
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -10,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
@@ -21,30 +18,21 @@
* under the License.
*
*/
-#include <boost/noncopyable.hpp>
-#include <apr_pools.h>
+#ifndef sys_MemStat
+#define sys_MemStat
+
+#include "qpid/CommonImportExport.h"
+#include "qmf/org/apache/qpid/broker/Memory.h"
namespace qpid {
namespace sys {
-/**
- * Singleton APR memory pool.
- */
-class APRPool : private boost::noncopyable {
- public:
- APRPool();
- ~APRPool();
- /** Get singleton instance */
- static apr_pool_t* get();
-
- private:
- apr_pool_t* pool;
-};
+ class QPID_COMMON_CLASS_EXTERN MemStat {
+ public:
+ QPID_COMMON_EXTERN static void loadMemInfo(qmf::org::apache::qpid::broker::Memory* object);
+ };
}}
+#endif
-
-
-
-#endif /*!_APRPool_*/
diff --git a/cpp/src/qpid/sys/Probes.h b/cpp/src/qpid/sys/Probes.h
new file mode 100644
index 0000000000..d30181c357
--- /dev/null
+++ b/cpp/src/qpid/sys/Probes.h
@@ -0,0 +1,65 @@
+#ifndef _sys_Probes
+#define _sys_Probes
+/*
+ *
+ * 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"
+
+#ifdef HAVE_SYS_SDT_H
+#include <sys/sdt.h>
+#endif
+
+// Pragmatically it seems that Linux and Solaris versions of sdt.h which support
+// user static probes define up to DTRACE_PROBE8, but FreeBSD 8 which doesn't
+// support usdt only defines up to DTRACE_PROBE4 - FreeBSD 9 which does support usdt
+// defines up to DTRACE_PROBE5.
+
+#ifdef DTRACE_PROBE5
+// Versions for Linux Systemtap/Solaris/FreeBSD 9
+#define QPID_PROBE(probe) DTRACE_PROBE(qpid, probe)
+#define QPID_PROBE1(probe, p1) DTRACE_PROBE1(qpid, probe, p1)
+#define QPID_PROBE2(probe, p1, p2) DTRACE_PROBE2(qpid, probe, p1, p2)
+#define QPID_PROBE3(probe, p1, p2, p3) DTRACE_PROBE3(qpid, probe, p1, p2, p3)
+#define QPID_PROBE4(probe, p1, p2, p3, p4) DTRACE_PROBE4(qpid, probe, p1, p2, p3, p4)
+#define QPID_PROBE5(probe, p1, p2, p3, p4, p5) DTRACE_PROBE5(qpid, probe, p1, p2, p3, p4, p5)
+#else
+// FreeBSD 8
+#define QPID_PROBE(probe)
+#define QPID_PROBE1(probe, p1)
+#define QPID_PROBE2(probe, p1, p2)
+#define QPID_PROBE3(probe, p1, p2, p3)
+#define QPID_PROBE4(probe, p1, p2, p3, p4)
+#define QPID_PROBE5(probe, p1, p2, p3, p4, p5)
+#endif
+
+#ifdef DTRACE_PROBE8
+// Versions for Linux Systemtap
+#define QPID_PROBE6(probe, p1, p2, p3, p4, p5, p6) DTRACE_PROBE6(qpid, probe, p1, p2, p3, p4, p5, p6)
+#define QPID_PROBE7(probe, p1, p2, p3, p4, p5, p6, p7) DTRACE_PROBE7(qpid, probe, p1, p2, p3, p4, p5, p6, p7)
+#define QPID_PROBE8(probe, p1, p2, p3, p4, p5, p6, p7, p8) DTRACE_PROBE8(qpid, probe, p1, p2, p3, p4, p5, p6, p7, p8)
+#else
+// Versions for Solaris/FreeBSD
+#define QPID_PROBE6(probe, p1, p2, p3, p4, p5, p6)
+#define QPID_PROBE7(probe, p1, p2, p3, p4, p5, p6, p7)
+#define QPID_PROBE8(probe, p1, p2, p3, p4, p5, p6, p7, p8)
+#endif
+
+#endif // _sys_Probes
diff --git a/cpp/src/qpid/sys/apr/APRBase.cpp b/cpp/src/qpid/sys/apr/APRBase.cpp
deleted file mode 100644
index 8bdba66bdc..0000000000
--- a/cpp/src/qpid/sys/apr/APRBase.cpp
+++ /dev/null
@@ -1,89 +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 <iostream>
-#include "qpid/log/Statement.h"
-#include "qpid/sys/apr/APRBase.h"
-
-using namespace qpid::sys;
-
-APRBase* APRBase::instance = 0;
-
-APRBase* APRBase::getInstance(){
- if(instance == 0){
- instance = new APRBase();
- }
- return instance;
-}
-
-
-APRBase::APRBase() : count(0){
- apr_initialize();
- CHECK_APR_SUCCESS(apr_pool_create(&pool, 0));
- CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, pool));
-}
-
-APRBase::~APRBase(){
- CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
- apr_pool_destroy(pool);
- apr_terminate();
-}
-
-bool APRBase::_increment(){
- bool deleted(false);
- CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
- if(this == instance){
- count++;
- }else{
- deleted = true;
- }
- CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
- return !deleted;
-}
-
-void APRBase::_decrement(){
- APRBase* copy = 0;
- CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
- if(--count == 0){
- copy = instance;
- instance = 0;
- }
- CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
- if(copy != 0){
- delete copy;
- }
-}
-
-void APRBase::increment(){
- int count = 0;
- while(count++ < 2 && !getInstance()->_increment())
- QPID_LOG(warning, "APR initialization triggered concurrently with termination.");
-}
-
-void APRBase::decrement(){
- getInstance()->_decrement();
-}
-
-std::string qpid::sys::get_desc(apr_status_t status){
- const int size = 50;
- char tmp[size];
- return std::string(apr_strerror(status, tmp, size));
-}
-
diff --git a/cpp/src/qpid/sys/apr/APRBase.h b/cpp/src/qpid/sys/apr/APRBase.h
deleted file mode 100644
index 7b5644a129..0000000000
--- a/cpp/src/qpid/sys/apr/APRBase.h
+++ /dev/null
@@ -1,74 +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 _APRBase_
-#define _APRBase_
-
-#include <string>
-#include <apr_thread_mutex.h>
-#include <apr_errno.h>
-
-namespace qpid {
-namespace sys {
-
- /**
- * Use of APR libraries necessitates explicit init and terminate
- * calls. Any class using APR libs should obtain the reference to
- * this singleton and increment on construction, decrement on
- * destruction. This class can then correctly initialise apr
- * before the first use and terminate after the last use.
- */
- class APRBase{
- static APRBase* instance;
- apr_pool_t* pool;
- apr_thread_mutex_t* mutex;
- int count;
-
- APRBase();
- ~APRBase();
- static APRBase* getInstance();
- bool _increment();
- void _decrement();
- public:
- static void increment();
- static void decrement();
- };
-
- //this is also a convenient place for a helper function for error checking:
- void check(apr_status_t status, const char* file, const int line);
- std::string get_desc(apr_status_t status);
-
-#define CHECK_APR_SUCCESS(A) qpid::sys::check(A, __FILE__, __LINE__);
-
-}
-}
-
-// Inlined as it is called *a lot*
-void inline qpid::sys::check(apr_status_t status, const char* file, const int line){
- if (status != APR_SUCCESS){
- char tmp[256];
- throw Exception(QPID_MSG(apr_strerror(status, tmp, size)))
- }
-}
-
-
-
-
-#endif
diff --git a/cpp/src/qpid/sys/apr/APRPool.cpp b/cpp/src/qpid/sys/apr/APRPool.cpp
deleted file mode 100644
index e221bfc2f1..0000000000
--- a/cpp/src/qpid/sys/apr/APRPool.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/sys/apr/APRPool.h"
-#include "qpid/sys/apr/APRBase.h"
-#include <boost/pool/detail/singleton.hpp>
-
-using namespace qpid::sys;
-
-APRPool::APRPool(){
- APRBase::increment();
- CHECK_APR_SUCCESS(apr_pool_create(&pool, NULL));
-}
-
-APRPool::~APRPool(){
- apr_pool_destroy(pool);
- APRBase::decrement();
-}
-
-apr_pool_t* APRPool::get() {
- return boost::details::pool::singleton_default<APRPool>::instance().pool;
-}
-
diff --git a/cpp/src/qpid/sys/apr/Condition.h b/cpp/src/qpid/sys/apr/Condition.h
deleted file mode 100644
index 66d465ca75..0000000000
--- a/cpp/src/qpid/sys/apr/Condition.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef _sys_apr_Condition_h
-#define _sys_apr_Condition_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/apr/APRPool.h"
-#include "qpid/sys/Mutex.h"
-#include "qpid/sys/Time.h"
-
-#include <sys/errno.h>
-#include <boost/noncopyable.hpp>
-#include <apr_thread_cond.h>
-
-namespace qpid {
-namespace sys {
-
-/**
- * A condition variable for thread synchronization.
- */
-class Condition
-{
- public:
- inline Condition();
- inline ~Condition();
- inline void wait(Mutex&);
- inline bool wait(Mutex&, const AbsTime& absoluteTime);
- inline void notify();
- inline void notifyAll();
-
- private:
- apr_thread_cond_t* condition;
-};
-
-
-Condition::Condition() {
- CHECK_APR_SUCCESS(apr_thread_cond_create(&condition, APRPool::get()));
-}
-
-Condition::~Condition() {
- CHECK_APR_SUCCESS(apr_thread_cond_destroy(condition));
-}
-
-void Condition::wait(Mutex& mutex) {
- CHECK_APR_SUCCESS(apr_thread_cond_wait(condition, mutex.mutex));
-}
-
-bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){
- // APR uses microseconds.
- apr_status_t status =
- apr_thread_cond_timedwait(
- condition, mutex.mutex, Duration(now(), absoluteTime)/TIME_USEC);
- if(status != APR_TIMEUP) CHECK_APR_SUCCESS(status);
- return status == 0;
-}
-
-void Condition::notify(){
- CHECK_APR_SUCCESS(apr_thread_cond_signal(condition));
-}
-
-void Condition::notifyAll(){
- CHECK_APR_SUCCESS(apr_thread_cond_broadcast(condition));
-}
-
-}}
-#endif /*!_sys_apr_Condition_h*/
diff --git a/cpp/src/qpid/sys/apr/Mutex.h b/cpp/src/qpid/sys/apr/Mutex.h
deleted file mode 100644
index cb75f5b339..0000000000
--- a/cpp/src/qpid/sys/apr/Mutex.h
+++ /dev/null
@@ -1,124 +0,0 @@
-#ifndef _sys_apr_Mutex_h
-#define _sys_apr_Mutex_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/sys/apr/APRBase.h"
-#include "qpid/sys/apr/APRPool.h"
-
-#include <boost/noncopyable.hpp>
-#include <apr_thread_mutex.h>
-
-namespace qpid {
-namespace sys {
-
-class Condition;
-
-/**
- * Mutex lock.
- */
-class Mutex : private boost::noncopyable {
- public:
- typedef ScopedLock<Mutex> ScopedLock;
- typedef ScopedUnlock<Mutex> ScopedUnlock;
-
- inline Mutex();
- inline ~Mutex();
- inline void lock();
- inline void unlock();
- inline bool trylock();
-
- protected:
- apr_thread_mutex_t* mutex;
- friend class Condition;
-};
-
-Mutex::Mutex() {
- CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, APRPool::get()));
-}
-
-Mutex::~Mutex(){
- CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
-}
-
-void Mutex::lock() {
- CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
-}
-void Mutex::unlock() {
- CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
-}
-
-bool Mutex::trylock() {
- return apr_thread_mutex_trylock(mutex) == 0;
-}
-
-
-/**
- * RW lock.
- */
-class RWlock : private boost::noncopyable {
- friend class Condition;
-
-public:
- typedef ScopedRlock<RWlock> ScopedRlock;
- typedef ScopedWlock<RWlock> ScopedWlock;
-
- inline RWlock();
- inline ~RWlock();
- inline void wlock(); // will write-lock
- inline void rlock(); // will read-lock
- inline void unlock();
- inline bool trywlock(); // will write-try
- inline bool tryrlock(); // will read-try
-
- protected:
- apr_thread_mutex_t* mutex;
-};
-
-RWlock::RWlock() {
- CHECK_APR_SUCCESS(apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, APRPool::get()));
-}
-
-RWlock::~RWlock(){
- CHECK_APR_SUCCESS(apr_thread_mutex_destroy(mutex));
-}
-
-void RWlock::wlock() {
- CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
-}
-
-void RWlock::rlock() {
- CHECK_APR_SUCCESS(apr_thread_mutex_lock(mutex));
-}
-
-void RWlock::unlock() {
- CHECK_APR_SUCCESS(apr_thread_mutex_unlock(mutex));
-}
-
-bool RWlock::trywlock() {
- return apr_thread_mutex_trylock(mutex) == 0;
-}
-
-bool RWlock::tryrlock() {
- return apr_thread_mutex_trylock(mutex) == 0;
-}
-
-
-}}
-#endif /*!_sys_apr_Mutex_h*/
diff --git a/cpp/src/qpid/sys/apr/Shlib.cpp b/cpp/src/qpid/sys/apr/Shlib.cpp
deleted file mode 100644
index b7ee13a03b..0000000000
--- a/cpp/src/qpid/sys/apr/Shlib.cpp
+++ /dev/null
@@ -1,49 +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/sys/Shlib.h"
-#include "qpid/sys/apr/APRBase.h"
-#include "qpid/sys/apr/APRPool.h"
-#include <apr_dso.h>
-
-namespace qpid {
-namespace sys {
-
-void Shlib::load(const char* libname) {
- apr_dso_handle_t* aprHandle;
- CHECK_APR_SUCCESS(
- apr_dso_load(&aprHandle, libname, APRPool::get()));
- handle=aprHandle;
-}
-
-void Shlib::unload() {
- CHECK_APR_SUCCESS(
- apr_dso_unload(static_cast<apr_dso_handle_t*>(handle)));
-}
-
-void* Shlib::getSymbol(const char* name) {
- apr_dso_handle_sym_t symbol;
- CHECK_APR_SUCCESS(apr_dso_sym(&symbol,
- static_cast<apr_dso_handle_t*>(handle),
- name));
- return (void*) symbol;
-}
-
-}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/apr/Socket.cpp b/cpp/src/qpid/sys/apr/Socket.cpp
deleted file mode 100644
index d9024d11c1..0000000000
--- a/cpp/src/qpid/sys/apr/Socket.cpp
+++ /dev/null
@@ -1,114 +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/sys/Socket.h"
-
-#include "qpid/sys/apr/APRBase.h"
-#include "qpid/sys/apr/APRPool.h"
-
-#include <apr_network_io.h>
-
-namespace qpid {
-namespace sys {
-
-class SocketPrivate {
-public:
- SocketPrivate(apr_socket_t* s = 0) :
- socket(s)
- {}
-
- apr_socket_t* socket;
-};
-
-Socket::Socket() :
- impl(new SocketPrivate)
-{
- createTcp();
-}
-
-Socket::Socket(SocketPrivate* sp) :
- impl(sp)
-{}
-
-Socket::~Socket() {
- delete impl;
-}
-
-void Socket::createTcp() const {
- apr_socket_t*& socket = impl->socket;
- apr_socket_t* s;
- CHECK_APR_SUCCESS(
- apr_socket_create(
- &s, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
- APRPool::get()));
- socket = s;
-}
-
-void Socket::setTimeout(const Duration& interval) const {
- apr_socket_t*& socket = impl->socket;
- apr_socket_timeout_set(socket, interval/TIME_USEC);
-}
-
-void Socket::connect(const std::string& host, int port) const {
- apr_socket_t*& socket = impl->socket;
- apr_sockaddr_t* address;
- CHECK_APR_SUCCESS(
- apr_sockaddr_info_get(
- &address, host.c_str(), APR_UNSPEC, port, APR_IPV4_ADDR_OK,
- APRPool::get()));
- CHECK_APR_SUCCESS(apr_socket_connect(socket, address));
-}
-
-void Socket::close() const {
- apr_socket_t*& socket = impl->socket;
- if (socket == 0) return;
- CHECK_APR_SUCCESS(apr_socket_close(socket));
- socket = 0;
-}
-
-ssize_t Socket::send(const void* data, size_t size) const
-{
- apr_socket_t*& socket = impl->socket;
- apr_size_t sent = size;
- apr_status_t status =
- apr_socket_send(socket, reinterpret_cast<const char*>(data), &sent);
- if (APR_STATUS_IS_TIMEUP(status)) return SOCKET_TIMEOUT;
- if (APR_STATUS_IS_EOF(status)) return SOCKET_EOF;
- CHECK_APR_SUCCESS(status);
- return sent;
-}
-
-ssize_t Socket::recv(void* data, size_t size) const
-{
- apr_socket_t*& socket = impl->socket;
- apr_size_t received = size;
- apr_status_t status =
- apr_socket_recv(socket, reinterpret_cast<char*>(data), &received);
- if (APR_STATUS_IS_TIMEUP(status))
- return SOCKET_TIMEOUT;
- if (APR_STATUS_IS_EOF(status))
- return SOCKET_EOF;
- CHECK_APR_SUCCESS(status);
- return received;
-}
-
-}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/apr/Thread.cpp b/cpp/src/qpid/sys/apr/Thread.cpp
deleted file mode 100644
index b52d0e6ace..0000000000
--- a/cpp/src/qpid/sys/apr/Thread.cpp
+++ /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.
- *
- */
-
-#include "qpid/sys/apr/Thread.h"
-#include "qpid/sys/Runnable.h"
-
-using namespace qpid::sys;
-using qpid::sys::Runnable;
-
-void* APR_THREAD_FUNC Thread::runRunnable(apr_thread_t* thread, void *data) {
- reinterpret_cast<Runnable*>(data)->run();
- CHECK_APR_SUCCESS(apr_thread_exit(thread, APR_SUCCESS));
- return NULL;
-}
-
-
diff --git a/cpp/src/qpid/sys/apr/Thread.h b/cpp/src/qpid/sys/apr/Thread.h
deleted file mode 100644
index 6cc63db5c9..0000000000
--- a/cpp/src/qpid/sys/apr/Thread.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef _sys_apr_Thread_h
-#define _sys_apr_Thread_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/apr/APRPool.h"
-#include "qpid/sys/apr/APRBase.h"
-
-#include <apr_thread_proc.h>
-#include <apr_portable.h>
-
-namespace qpid {
-namespace sys {
-
-class Runnable;
-
-class Thread
-{
- public:
- inline static Thread current();
-
- /** ID of current thread for logging.
- * Workaround for broken Thread::current() in APR
- */
- inline static long logId();
-
- inline static void yield();
-
- inline Thread();
- inline explicit Thread(qpid::sys::Runnable*);
- inline explicit Thread(qpid::sys::Runnable&);
-
- inline void join();
-
- inline long id();
-
- private:
- static void* APR_THREAD_FUNC runRunnable(apr_thread_t* thread, void *data);
- inline Thread(apr_thread_t* t);
- apr_thread_t* thread;
-};
-
-Thread::Thread() : thread(0) {}
-
-Thread::Thread(Runnable* runnable) {
- CHECK_APR_SUCCESS(
- apr_thread_create(&thread, 0, runRunnable, runnable, APRPool::get()));
-}
-
-Thread::Thread(Runnable& runnable) {
- CHECK_APR_SUCCESS(
- apr_thread_create(&thread, 0, runRunnable, &runnable, APRPool::get()));
-}
-
-void Thread::join(){
- apr_status_t status;
- if (thread != 0)
- CHECK_APR_SUCCESS(apr_thread_join(&status, thread));
-}
-
-long Thread::id() {
- return long(thread);
-}
-
-/** ID of current thread for logging.
- * Workaround for broken Thread::current() in APR
- */
-long Thread::logId() {
- return static_cast<long>(apr_os_thread_current());
-}
-
-Thread::Thread(apr_thread_t* t) : thread(t) {}
-
-Thread Thread::current(){
- apr_thread_t* thr;
- apr_os_thread_t osthr = apr_os_thread_current();
- CHECK_APR_SUCCESS(apr_os_thread_put(&thr, &osthr, APRPool::get()));
- return Thread(thr);
-}
-
-void Thread::yield()
-{
- apr_thread_yield();
-}
-
-}}
-#endif /*!_sys_apr_Thread_h*/
diff --git a/cpp/src/qpid/sys/posix/AsynchIO.cpp b/cpp/src/qpid/sys/posix/AsynchIO.cpp
index a1c161b596..01ff8b6bfa 100644
--- a/cpp/src/qpid/sys/posix/AsynchIO.cpp
+++ b/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -23,6 +23,7 @@
#include "qpid/sys/Socket.h"
#include "qpid/sys/SocketAddress.h"
#include "qpid/sys/Poller.h"
+#include "qpid/sys/Probes.h"
#include "qpid/sys/DispatchHandle.h"
#include "qpid/sys/Time.h"
#include "qpid/log/Statement.h"
@@ -40,7 +41,9 @@
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
-using namespace qpid::sys;
+namespace qpid {
+namespace sys {
+namespace posix {
namespace {
@@ -70,10 +73,6 @@ __thread int64_t threadMaxIoTimeNs = 2 * 1000000; // start at 2ms
/*
* Asynch Acceptor
*/
-namespace qpid {
-namespace sys {
-namespace posix {
-
class AsynchAcceptor : public qpid::sys::AsynchAcceptor {
public:
AsynchAcceptor(const Socket& s, AsynchAcceptor::Callback callback);
@@ -423,9 +422,12 @@ AsynchIO::BufferBase* AsynchIO::getQueuedBuffer() {
void AsynchIO::readable(DispatchHandle& h) {
if (readingStopped) {
// We have been flow controlled.
+ QPID_PROBE1(asynchio_read_flowcontrolled, &h);
return;
}
AbsTime readStartTime = AbsTime::now();
+ size_t total = 0;
+ int readCalls = 0;
do {
// (Try to) get a buffer
if (!bufferQueue.empty()) {
@@ -436,23 +438,29 @@ void AsynchIO::readable(DispatchHandle& h) {
errno = 0;
int readCount = buff->byteCount-buff->dataCount;
int rc = socket.read(buff->bytes + buff->dataCount, readCount);
+ int64_t duration = Duration(readStartTime, AbsTime::now());
+ ++readCalls;
if (rc > 0) {
buff->dataCount += rc;
threadReadTotal += rc;
+ total += rc;
readCallback(*this, buff);
if (readingStopped) {
// We have been flow controlled.
+ QPID_PROBE4(asynchio_read_finished_flowcontrolled, &h, duration, total, readCalls);
break;
}
if (rc != readCount) {
// If we didn't fill the read buffer then time to stop reading
+ QPID_PROBE4(asynchio_read_finished_done, &h, duration, total, readCalls);
break;
}
// Stop reading if we've overrun our timeslot
- if (Duration(readStartTime, AbsTime::now()) > threadMaxIoTimeNs) {
+ if ( duration > threadMaxIoTimeNs) {
+ QPID_PROBE4(asynchio_read_finished_maxtime, &h, duration, total, readCalls);
break;
}
@@ -461,6 +469,7 @@ void AsynchIO::readable(DispatchHandle& h) {
bufferQueue.push_front(buff);
assert(buff);
+ QPID_PROBE5(asynchio_read_finished_error, &h, duration, total, readCalls, errno);
// Eof or other side has gone away
if (rc == 0 || errno == ECONNRESET) {
eofCallback(*this);
@@ -486,6 +495,7 @@ void AsynchIO::readable(DispatchHandle& h) {
// If we still have no buffers we can't do anything more
if (bufferQueue.empty()) {
h.unwatchRead();
+ QPID_PROBE4(asynchio_read_finished_nobuffers, &h, Duration(readStartTime, AbsTime::now()), total, readCalls);
break;
}
@@ -501,6 +511,8 @@ void AsynchIO::readable(DispatchHandle& h) {
*/
void AsynchIO::writeable(DispatchHandle& h) {
AbsTime writeStartTime = AbsTime::now();
+ size_t total = 0;
+ int writeCalls = 0;
do {
// See if we've got something to write
if (!writeQueue.empty()) {
@@ -510,14 +522,18 @@ void AsynchIO::writeable(DispatchHandle& h) {
errno = 0;
assert(buff->dataStart+buff->dataCount <= buff->byteCount);
int rc = socket.write(buff->bytes+buff->dataStart, buff->dataCount);
+ int64_t duration = Duration(writeStartTime, AbsTime::now());
+ ++writeCalls;
if (rc >= 0) {
threadWriteTotal += rc;
+ total += rc;
// If we didn't write full buffer put rest back
if (rc != buff->dataCount) {
buff->dataStart += rc;
buff->dataCount -= rc;
writeQueue.push_back(buff);
+ QPID_PROBE4(asynchio_write_finished_done, &h, duration, total, writeCalls);
break;
}
@@ -525,12 +541,15 @@ void AsynchIO::writeable(DispatchHandle& h) {
queueReadBuffer(buff);
// Stop writing if we've overrun our timeslot
- if (Duration(writeStartTime, AbsTime::now()) > threadMaxIoTimeNs) {
+ if (duration > threadMaxIoTimeNs) {
+ QPID_PROBE4(asynchio_write_finished_maxtime, &h, duration, total, writeCalls);
break;
}
} else {
// Put buffer back
writeQueue.push_back(buff);
+ QPID_PROBE5(asynchio_write_finished_error, &h, duration, total, writeCalls, errno);
+
if (errno == ECONNRESET || errno == EPIPE) {
// Just stop watching for write here - we'll get a
// disconnect callback soon enough
@@ -548,9 +567,13 @@ void AsynchIO::writeable(DispatchHandle& h) {
}
}
} else {
+ int64_t duration = Duration(writeStartTime, AbsTime::now());
+ (void) duration; // force duration to be used if no probes are compiled
+
// If we're waiting to close the socket then can do it now as there is nothing to write
if (queuedClose) {
close(h);
+ QPID_PROBE4(asynchio_write_finished_closed, &h, duration, total, writeCalls);
break;
}
// Fd is writable, but nothing to write
@@ -567,6 +590,7 @@ void AsynchIO::writeable(DispatchHandle& h) {
// desired rewatchWrite so we correct that here
if (writePending)
h.rewatchWrite();
+ QPID_PROBE4(asynchio_write_finished_nodata, &h, duration, total, writeCalls);
break;
}
}
diff --git a/cpp/src/qpid/sys/posix/PollableCondition.cpp b/cpp/src/qpid/sys/posix/PollableCondition.cpp
index b22a615a54..abff8a5be8 100644
--- a/cpp/src/qpid/sys/posix/PollableCondition.cpp
+++ b/cpp/src/qpid/sys/posix/PollableCondition.cpp
@@ -1,6 +1,3 @@
-#ifndef QPID_SYS_LINUX_POLLABLECONDITION_CPP
-#define QPID_SYS_LINUX_POLLABLECONDITION_CPP
-
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -120,5 +117,3 @@ void PollableCondition::set() { impl->set(); }
void PollableCondition::clear() { impl->clear(); }
}} // namespace qpid::sys
-
-#endif /*!QPID_SYS_LINUX_POLLABLECONDITION_CPP*/
diff --git a/cpp/src/qpid/sys/ssl/SslIo.cpp b/cpp/src/qpid/sys/ssl/SslIo.cpp
index 73f15617dc..2a7cf16923 100644
--- a/cpp/src/qpid/sys/ssl/SslIo.cpp
+++ b/cpp/src/qpid/sys/ssl/SslIo.cpp
@@ -37,8 +37,9 @@
#include <boost/bind.hpp>
-using namespace qpid::sys;
-using namespace qpid::sys::ssl;
+namespace qpid {
+namespace sys {
+namespace ssl {
namespace {
@@ -448,3 +449,5 @@ SecuritySettings SslIO::getSecuritySettings() {
settings.authid = socket.getClientAuthId();
return settings;
}
+
+}}}
diff --git a/cpp/src/qpid/sys/windows/AsynchIO.cpp b/cpp/src/qpid/sys/windows/AsynchIO.cpp
index 30378d4c5f..ae53414e52 100644
--- a/cpp/src/qpid/sys/windows/AsynchIO.cpp
+++ b/cpp/src/qpid/sys/windows/AsynchIO.cpp
@@ -291,6 +291,8 @@ private:
volatile LONG opsInProgress;
// Is there a write in progress?
volatile bool writeInProgress;
+ // Or a read?
+ volatile bool readInProgress;
// Deletion requested, but there are callbacks in progress.
volatile bool queuedDelete;
// Socket close requested, but there are operations in progress.
@@ -344,6 +346,11 @@ private:
* Called when there's a completion to process.
*/
void completion(AsynchIoResult *result);
+
+ /**
+ * Helper function to facilitate the close operation
+ */
+ void cancelRead();
};
// This is used to encapsulate pure callbacks into a handle
@@ -372,6 +379,7 @@ AsynchIO::AsynchIO(const Socket& s,
socket(s),
opsInProgress(0),
writeInProgress(false),
+ readInProgress(false),
queuedDelete(false),
queuedClose(false),
working(false) {
@@ -389,21 +397,24 @@ AsynchIO::~AsynchIO() {
}
void AsynchIO::queueForDeletion() {
- queuedDelete = true;
- if (opsInProgress > 0) {
- QPID_LOG(info, "Delete AsynchIO queued; ops in progress");
- // AsynchIOHandler calls this then deletes itself; don't do any more
- // callbacks.
- readCallback = 0;
- eofCallback = 0;
- disCallback = 0;
- closedCallback = 0;
- emptyCallback = 0;
- idleCallback = 0;
- }
- else {
- delete this;
+ {
+ ScopedLock<Mutex> l(completionLock);
+ assert(!queuedDelete);
+ queuedDelete = true;
+ if (working || opsInProgress > 0) {
+ QPID_LOG(info, "Delete AsynchIO queued; ops in progress");
+ // AsynchIOHandler calls this then deletes itself; don't do any more
+ // callbacks.
+ readCallback = 0;
+ eofCallback = 0;
+ disCallback = 0;
+ closedCallback = 0;
+ emptyCallback = 0;
+ idleCallback = 0;
+ return;
+ }
}
+ delete this;
}
void AsynchIO::start(Poller::shared_ptr poller0) {
@@ -451,9 +462,14 @@ void AsynchIO::notifyPendingWrite() {
}
void AsynchIO::queueWriteClose() {
- queuedClose = true;
- if (!writeInProgress)
- notifyPendingWrite();
+ {
+ ScopedLock<Mutex> l(completionLock);
+ queuedClose = true;
+ if (working || writeInProgress)
+ // no need to summon an IO thread
+ return;
+ }
+ notifyPendingWrite();
}
bool AsynchIO::writeQueueEmpty() {
@@ -466,7 +482,7 @@ bool AsynchIO::writeQueueEmpty() {
* called when the read is complete and data is available.
*/
void AsynchIO::startReading() {
- if (queuedDelete)
+ if (queuedDelete || queuedClose)
return;
// (Try to) get a buffer; look on the front since there may be an
@@ -489,6 +505,7 @@ void AsynchIO::startReading() {
readCount);
DWORD bytesReceived = 0, flags = 0;
InterlockedIncrement(&opsInProgress);
+ readInProgress = true;
int status = WSARecv(toSocketHandle(socket),
const_cast<LPWSABUF>(result->getWSABUF()), 1,
&bytesReceived,
@@ -616,17 +633,19 @@ void AsynchIO::close(void) {
void AsynchIO::readComplete(AsynchReadResult *result) {
int status = result->getStatus();
size_t bytes = result->getTransferred();
+ readInProgress = false;
if (status == 0 && bytes > 0) {
- bool restartRead = true; // May not if receiver doesn't want more
if (readCallback)
readCallback(*this, result->getBuff());
- if (restartRead)
- startReading();
+ startReading();
}
else {
// No data read, so put the buffer back. It may be partially filled,
// so "unread" it back to the front of the queue.
unread(result->getBuff());
+ if (queuedClose) {
+ return; // Expected from cancelRead()
+ }
notifyEof();
if (status != 0)
{
@@ -682,6 +701,8 @@ void AsynchIO::writeComplete(AsynchWriteResult *result) {
}
void AsynchIO::completion(AsynchIoResult *result) {
+ bool closing = false;
+ bool deleting = false;
{
ScopedLock<Mutex> l(completionLock);
if (working) {
@@ -713,6 +734,8 @@ void AsynchIO::completion(AsynchIoResult *result) {
delete result;
result = 0;
InterlockedDecrement(&opsInProgress);
+ if (queuedClose && opsInProgress == 1 && readInProgress)
+ cancelRead();
}
// Lock is held again.
if (completionQueue.empty())
@@ -721,17 +744,40 @@ void AsynchIO::completion(AsynchIoResult *result) {
completionQueue.pop();
}
working = false;
+ if (opsInProgress == 0) {
+ closing = queuedClose;
+ deleting = queuedDelete;
+ }
}
// Lock released; ok to close if ops are done and close requested.
// Layer above will call back to queueForDeletion() if it hasn't
// already been done. If it already has, go ahead and delete.
- if (opsInProgress == 0) {
- if (queuedClose)
- // close() may cause a delete; don't trust 'this' on return
- close();
- else if (queuedDelete)
- delete this;
+ if (deleting)
+ delete this;
+ else if (closing)
+ // close() may cause a delete; don't trust 'this' on return
+ close();
+}
+
+/*
+ * NOTE - this method must be called in the same context as other completions,
+ * so that the resulting readComplete, and final AsynchIO::close() is serialized
+ * after this method returns.
+ */
+void AsynchIO::cancelRead() {
+ if (queuedDelete)
+ return; // socket already deleted
+ else {
+ ScopedLock<Mutex> l(completionLock);;
+ if (!completionQueue.empty())
+ return; // process it; come back later if necessary
}
+ // Cancel outstanding read and force to completion. Otherwise, on a faulty
+ // physical link, the pending read can remain uncompleted indefinitely.
+ // Draining the pending read will result in the official close (and
+ // notifyClosed). CancelIoEX() is the natural choice, but not available in
+ // XP, so we make do with closesocket().
+ socket.close();
}
} // namespace windows
diff --git a/cpp/src/qpid/sys/windows/PollableCondition.cpp b/cpp/src/qpid/sys/windows/PollableCondition.cpp
index 6a1d9045b4..bb637be0a6 100644
--- a/cpp/src/qpid/sys/windows/PollableCondition.cpp
+++ b/cpp/src/qpid/sys/windows/PollableCondition.cpp
@@ -1,6 +1,3 @@
-#ifndef QPID_SYS_WINDOWS_POLLABLECONDITION_CPP
-#define QPID_SYS_WINDOWS_POLLABLECONDITION_CPP
-
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -110,5 +107,3 @@ void PollableCondition::clear() {
}
}} // namespace qpid::sys
-
-#endif /*!QPID_SYS_WINDOWS_POLLABLECONDITION_CPP*/
diff --git a/cpp/src/qpid/sys/windows/Socket.cpp b/cpp/src/qpid/sys/windows/Socket.cpp
index 1fa4768329..b085f67539 100644
--- a/cpp/src/qpid/sys/windows/Socket.cpp
+++ b/cpp/src/qpid/sys/windows/Socket.cpp
@@ -32,6 +32,9 @@
#include <winsock2.h>
+namespace qpid {
+namespace sys {
+
// Need to initialize WinSock. Ideally, this would be a singleton or embedded
// in some one-time initialization function. I tried boost singleton and could
// not get it to compile (and others located in google had the same problem).
@@ -76,13 +79,6 @@ protected:
static WinSockSetup setup;
-} /* namespace */
-
-namespace qpid {
-namespace sys {
-
-namespace {
-
std::string getName(SOCKET fd, bool local)
{
::sockaddr_storage name_s; // big enough for any socket address
diff --git a/cpp/src/qpid/sys/windows/SslAsynchIO.cpp b/cpp/src/qpid/sys/windows/SslAsynchIO.cpp
index 11a3389e45..25cc94b290 100644
--- a/cpp/src/qpid/sys/windows/SslAsynchIO.cpp
+++ b/cpp/src/qpid/sys/windows/SslAsynchIO.cpp
@@ -38,6 +38,10 @@
#include <queue>
#include <boost/bind.hpp>
+namespace qpid {
+namespace sys {
+namespace windows {
+
namespace {
/*
@@ -66,10 +70,6 @@ namespace {
};
}
-namespace qpid {
-namespace sys {
-namespace windows {
-
SslAsynchIO::SslAsynchIO(const qpid::sys::Socket& s,
CredHandle hCred,
ReadCallback rCb,
diff --git a/cpp/src/qpid/xml/XmlExchange.cpp b/cpp/src/qpid/xml/XmlExchange.cpp
index b7ff5d211d..01770e22a6 100644
--- a/cpp/src/qpid/xml/XmlExchange.cpp
+++ b/cpp/src/qpid/xml/XmlExchange.cpp
@@ -283,8 +283,10 @@ bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::F
// But for very large messages, if all these queries are on the first part of the data,
// it could still be a big win.
-void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* args)
+void XmlExchange::route(Deliverable& msg)
{
+ const string& routingKey = msg.getMessage().getRoutingKey();
+ const FieldTable* args = msg.getMessage().getApplicationHeaders();
PreRoute pr(msg, this);
try {
XmlBinding::vector::ConstPtr p;
diff --git a/cpp/src/qpid/xml/XmlExchange.h b/cpp/src/qpid/xml/XmlExchange.h
index 958bad4931..9ef389d9bf 100644
--- a/cpp/src/qpid/xml/XmlExchange.h
+++ b/cpp/src/qpid/xml/XmlExchange.h
@@ -82,7 +82,7 @@ class XmlExchange : public virtual Exchange {
virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args);
- virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args);
+ virtual void route(Deliverable& msg);
virtual bool isBound(Queue::shared_ptr queue, const std::string* const routingKey, const qpid::framing::FieldTable* const args);