diff options
Diffstat (limited to 'qpid/cpp/src/qpid')
226 files changed, 3672 insertions, 2180 deletions
diff --git a/qpid/cpp/src/qpid/Address.h b/qpid/cpp/src/qpid/Address.h index 9669985165..a5a4345ba3 100755 --- a/qpid/cpp/src/qpid/Address.h +++ b/qpid/cpp/src/qpid/Address.h @@ -20,7 +20,7 @@ */ #include "qpid/sys/IntegerTypes.h" - +#include "qpid/CommonImportExport.h" #include <boost/variant.hpp> #include <iosfwd> #include <string> @@ -31,12 +31,12 @@ namespace qpid { /** TCP address of a broker - host:port */ struct TcpAddress { static const uint16_t DEFAULT_PORT=5672; - explicit TcpAddress(const std::string& host_=std::string(),uint16_t port_=DEFAULT_PORT); + QPID_COMMON_EXTERN explicit TcpAddress(const std::string& host_=std::string(),uint16_t port_=DEFAULT_PORT); std::string host; uint16_t port; }; bool operator==(const TcpAddress& x, const TcpAddress& y); -std::ostream& operator<<(std::ostream& os, const TcpAddress& a); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const TcpAddress& a); /**@internal Not a real address type, this is a placeholder to * demonstrate and validate multi-protocol Urls for unit tests and diff --git a/qpid/cpp/src/qpid/CommonImportExport.h b/qpid/cpp/src/qpid/CommonImportExport.h new file mode 100644 index 0000000000..47872646d9 --- /dev/null +++ b/qpid/cpp/src/qpid/CommonImportExport.h @@ -0,0 +1,33 @@ +#ifndef QPID_COMMON_IMPORT_EXPORT_H +#define QPID_COMMON_IMPORT_EXPORT_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. + */ + +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) +#if defined(COMMON_EXPORT) +#define QPID_COMMON_EXTERN __declspec(dllexport) +#else +#define QPID_COMMON_EXTERN __declspec(dllimport) +#endif +#else +#define QPID_COMMON_EXTERN +#endif + +#endif diff --git a/qpid/cpp/src/qpid/DataDir.h b/qpid/cpp/src/qpid/DataDir.h index 6b45d8747b..dfdd498cbc 100644 --- a/qpid/cpp/src/qpid/DataDir.h +++ b/qpid/cpp/src/qpid/DataDir.h @@ -24,6 +24,7 @@ #include <string> #include <memory> #include "qpid/sys/LockFile.h" +#include "qpid/CommonImportExport.h" namespace qpid { @@ -38,8 +39,8 @@ class DataDir public: - DataDir (std::string path); - ~DataDir (); + QPID_COMMON_EXTERN DataDir (std::string path); + QPID_COMMON_EXTERN ~DataDir (); bool isEnabled() { return enabled; } const std::string& getPath() { return dirPath; } diff --git a/qpid/cpp/src/qpid/Exception.h b/qpid/cpp/src/qpid/Exception.h index 86bf8fbc4a..0b0bc33e93 100644 --- a/qpid/cpp/src/qpid/Exception.h +++ b/qpid/cpp/src/qpid/Exception.h @@ -27,7 +27,7 @@ #include "qpid/framing/enum.h" #include "qpid/sys/StrError.h" #include "qpid/Msg.h" - +#include "qpid/CommonImportExport.h" #include <memory> #include <string> #include <errno.h> @@ -41,11 +41,11 @@ namespace qpid class Exception : public std::exception { public: - explicit Exception(const std::string& message=std::string()) throw(); - virtual ~Exception() throw(); - virtual const char* what() const throw(); // prefix: message - virtual std::string getMessage() const; // Unprefixed message - virtual std::string getPrefix() const; // Prefix + QPID_COMMON_EXTERN explicit Exception(const std::string& message=std::string()) throw(); + QPID_COMMON_EXTERN virtual ~Exception() throw(); + QPID_COMMON_EXTERN virtual const char* what() const throw(); // prefix: message + QPID_COMMON_EXTERN virtual std::string getMessage() const; // Unprefixed message + QPID_COMMON_EXTERN virtual std::string getPrefix() const; // Prefix private: std::string message; @@ -77,8 +77,8 @@ struct ConnectionException : public Exception { }; struct ClosedException : public Exception { - ClosedException(const std::string& msg=std::string()); - std::string getPrefix() const; + QPID_COMMON_EXTERN ClosedException(const std::string& msg=std::string()); + QPID_COMMON_EXTERN std::string getPrefix() const; }; /** diff --git a/qpid/cpp/src/qpid/Modules.h b/qpid/cpp/src/qpid/Modules.h index 2a3b24f359..ce06dd0ef6 100644 --- a/qpid/cpp/src/qpid/Modules.h +++ b/qpid/cpp/src/qpid/Modules.h @@ -25,6 +25,7 @@ #include "Options.h" #include <string> #include <vector> +#include "qpid/CommonImportExport.h" namespace qpid { @@ -32,11 +33,11 @@ struct ModuleOptions : public qpid::Options { std::string loadDir; std::vector<std::string> load; bool noLoad; - ModuleOptions(const std::string& defaultModuleDir); + QPID_COMMON_EXTERN ModuleOptions(const std::string& defaultModuleDir); }; -void tryShlib(const char* libname, bool noThrow); -void loadModuleDir (std::string dirname, bool isDefault); +QPID_COMMON_EXTERN void tryShlib(const char* libname, bool noThrow); +QPID_COMMON_EXTERN void loadModuleDir (std::string dirname, bool isDefault); } // namespace qpid diff --git a/qpid/cpp/src/qpid/Options.h b/qpid/cpp/src/qpid/Options.h index cb86d27241..aeb7a79329 100644 --- a/qpid/cpp/src/qpid/Options.h +++ b/qpid/cpp/src/qpid/Options.h @@ -23,13 +23,25 @@ */ #include "qpid/Exception.h" + +// Disable warnings triggered by boost. +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4251 4275) +#endif + #include <boost/program_options.hpp> #include <boost/format.hpp> + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + #include <sstream> #include <iterator> #include <algorithm> #include <string> - +#include "qpid/CommonImportExport.h" namespace qpid { namespace po=boost::program_options; @@ -37,7 +49,7 @@ namespace po=boost::program_options; ///@internal -std::string prettyArg(const std::string&, const std::string&); +QPID_COMMON_EXTERN std::string prettyArg(const std::string&, const std::string&); /** @internal Normally only constructed by optValue() */ template <class T> @@ -192,24 +204,20 @@ options_description_less_easy_init #endif - - - - struct Options : public po::options_description { struct Exception : public qpid::Exception { Exception(const std::string& msg) : qpid::Exception(msg) {} }; - Options(const std::string& name=std::string()); + QPID_COMMON_EXTERN Options(const std::string& name=std::string()); /** * Parses options from argc/argv, environment variables and config file. * Note the filename argument can reference an options variable that * is updated by argc/argv or environment variable parsing. */ - void parse(int argc, char const* const* argv, + QPID_COMMON_EXTERN void parse(int argc, char const* const* argv, const std::string& configfile=std::string(), bool allowUnknown = false); @@ -242,7 +250,7 @@ struct Options : public po::options_description { * Standard options for configuration */ struct CommonOptions : public Options { - CommonOptions(const std::string& name=std::string(), + QPID_COMMON_EXTERN CommonOptions(const std::string& name=std::string(), const std::string& configfile=std::string()); bool help; bool version; diff --git a/qpid/cpp/src/qpid/Plugin.h b/qpid/cpp/src/qpid/Plugin.h index 50d8e01227..913152f9e1 100644 --- a/qpid/cpp/src/qpid/Plugin.h +++ b/qpid/cpp/src/qpid/Plugin.h @@ -24,6 +24,7 @@ #include <boost/noncopyable.hpp> #include <boost/function.hpp> #include <vector> +#include "qpid/CommonImportExport.h" /**@file Generic plug-in framework. */ @@ -46,10 +47,10 @@ class Plugin : private boost::noncopyable { { public: /** Calls finalize() if not already called. */ - virtual ~Target(); + QPID_COMMON_EXTERN virtual ~Target(); /** Run all the finalizers */ - void finalize(); + QPID_COMMON_EXTERN void finalize(); /** Add a function to run when finalize() is called */ void addFinalizer(const boost::function<void()>&); @@ -65,9 +66,9 @@ class Plugin : private boost::noncopyable { * member variable in a library so it is registered during * initialization when the library is loaded. */ - Plugin(); + QPID_COMMON_EXTERN Plugin(); - virtual ~Plugin(); + QPID_COMMON_EXTERN virtual ~Plugin(); /** * Configuration options for the plugin. @@ -76,7 +77,7 @@ class Plugin : private boost::noncopyable { * @return An options group or 0 for no options. Default returns 0. * Plugin retains ownership of return value. */ - virtual Options* getOptions(); + QPID_COMMON_EXTERN virtual Options* getOptions(); /** * Initialize Plugin functionality on a Target, called before @@ -101,16 +102,16 @@ class Plugin : private boost::noncopyable { /** List of registered Plugin objects. * Caller must not delete plugin pointers. */ - static const Plugins& getPlugins(); + QPID_COMMON_EXTERN static const Plugins& getPlugins(); /** Call earlyInitialize() on all registered plugins */ - static void earlyInitAll(Target&); + QPID_COMMON_EXTERN static void earlyInitAll(Target&); /** Call initialize() on all registered plugins */ - static void initializeAll(Target&); + QPID_COMMON_EXTERN static void initializeAll(Target&); /** For each registered plugin, add plugin.getOptions() to opts. */ - static void addOptions(Options& opts); + QPID_COMMON_EXTERN static void addOptions(Options& opts); }; } // namespace qpid diff --git a/qpid/cpp/src/qpid/SessionId.cpp b/qpid/cpp/src/qpid/SessionId.cpp index fce6619f5d..098998015f 100644 --- a/qpid/cpp/src/qpid/SessionId.cpp +++ b/qpid/cpp/src/qpid/SessionId.cpp @@ -35,7 +35,7 @@ bool SessionId::operator==(const SessionId& id) const { } std::ostream& operator<<(std::ostream& o, const SessionId& id) { - return o << id.getName() << "@" << id.getUserId(); + return o << id.getUserId() << "." << id.getName(); } std::string SessionId::str() const { diff --git a/qpid/cpp/src/qpid/SessionId.h b/qpid/cpp/src/qpid/SessionId.h index 291c42a2bb..bf52f9856b 100644 --- a/qpid/cpp/src/qpid/SessionId.h +++ b/qpid/cpp/src/qpid/SessionId.h @@ -24,6 +24,7 @@ #include <boost/operators.hpp> #include <string> +#include <qpid/CommonImportExport.h> namespace qpid { @@ -42,16 +43,16 @@ class SessionId : boost::totally_ordered1<SessionId> { std::string userId; std::string name; public: - SessionId(const std::string& userId=std::string(), const std::string& name=std::string()); + QPID_COMMON_EXTERN SessionId(const std::string& userId=std::string(), const std::string& name=std::string()); std::string getUserId() const { return userId; } std::string getName() const { return name; } - bool operator<(const SessionId&) const ; - bool operator==(const SessionId& id) const; + QPID_COMMON_EXTERN bool operator<(const SessionId&) const ; + QPID_COMMON_EXTERN bool operator==(const SessionId& id) const; // Convert to a string - std::string str() const; + QPID_COMMON_EXTERN std::string str() const; }; -std::ostream& operator<<(std::ostream&, const SessionId&); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SessionId&); } // namespace qpid diff --git a/qpid/cpp/src/qpid/SessionState.cpp b/qpid/cpp/src/qpid/SessionState.cpp index ac75b5c5ff..3e844fb24b 100644 --- a/qpid/cpp/src/qpid/SessionState.cpp +++ b/qpid/cpp/src/qpid/SessionState.cpp @@ -113,7 +113,8 @@ SessionState::ReplayRange SessionState::senderExpected(const SessionPoint& expec void SessionState::senderRecord(const AMQFrame& f) { if (isControl(f)) return; // Ignore control frames. - QPID_LOG_IF(debug, f.getMethod(), getId() << ": sent cmd " << sender.sendPoint.command << ": " << *f.getMethod()); + QPID_LOG(trace, getId() << ": sent cmd " << sender.sendPoint.command << ": " << *f.getBody()); + stateful = true; if (timeout) sender.replayList.push_back(f); sender.unflushedSize += f.encodedSize(); @@ -183,6 +184,7 @@ void SessionState::receiverSetCommandPoint(const SessionPoint& point) { } bool SessionState::receiverRecord(const AMQFrame& f) { + if (receiverTrackingDisabled) return true; //Very nasty hack for push bridges if (isControl(f)) return true; // Ignore control frames. stateful = true; receiver.expected.advance(f); @@ -192,12 +194,13 @@ bool SessionState::receiverRecord(const AMQFrame& f) { receiver.received = receiver.expected; receiver.incomplete += receiverGetCurrent(); } - QPID_LOG_IF(debug, f.getMethod(), getId() << ": recv cmd " << receiverGetCurrent() << ": " << *f.getMethod()); - QPID_LOG_IF(debug, !firstTime, "Ignoring duplicate frame: " << receiverGetCurrent() << ": " << f); + QPID_LOG(trace, getId() << ": recv cmd " << receiverGetCurrent() << ": " << *f.getBody()); + if (!firstTime) QPID_LOG(trace, "Ignoring duplicate frame."); return firstTime; } void SessionState::receiverCompleted(SequenceNumber command, bool cumulative) { + if (receiverTrackingDisabled) return; //Very nasty hack for push bridges assert(receiver.incomplete.contains(command)); // Internal error to complete command twice. SequenceNumber first =cumulative ? receiver.incomplete.front() : command; SequenceNumber last = command; @@ -237,7 +240,7 @@ SessionState::Configuration::Configuration(size_t flush, size_t hard) : replayFlushLimit(flush), replayHardLimit(hard) {} SessionState::SessionState(const SessionId& i, const Configuration& c) - : id(i), timeout(), config(c), stateful() + : id(i), timeout(), config(c), stateful(), receiverTrackingDisabled(false) { QPID_LOG(debug, "SessionState::SessionState " << id << ": " << this); } @@ -275,4 +278,7 @@ void SessionState::setState( receiver.bytesSinceKnownCompleted = 0; } +void SessionState::disableReceiverTracking() { receiverTrackingDisabled = true; } +void SessionState::enableReceiverTracking() { receiverTrackingDisabled = false; } + } // namespace qpid diff --git a/qpid/cpp/src/qpid/SessionState.h b/qpid/cpp/src/qpid/SessionState.h index bf4ff6d326..da28738546 100644 --- a/qpid/cpp/src/qpid/SessionState.h +++ b/qpid/cpp/src/qpid/SessionState.h @@ -31,6 +31,7 @@ #include <boost/range/iterator_range.hpp> #include <vector> #include <iosfwd> +#include <qpid/CommonImportExport.h> namespace qpid { using framing::SequenceNumber; @@ -38,19 +39,19 @@ using framing::SequenceSet; /** A point in the session. Points to command id + offset */ struct SessionPoint : boost::totally_ordered1<SessionPoint> { - SessionPoint(SequenceNumber command = 0, uint64_t offset = 0); + QPID_COMMON_EXTERN SessionPoint(SequenceNumber command = 0, uint64_t offset = 0); SequenceNumber command; uint64_t offset; /** Advance past frame f */ - void advance(const framing::AMQFrame& f); + QPID_COMMON_EXTERN void advance(const framing::AMQFrame& f); - bool operator<(const SessionPoint&) const; - bool operator==(const SessionPoint&) const; + QPID_COMMON_EXTERN bool operator<(const SessionPoint&) const; + QPID_COMMON_EXTERN bool operator==(const SessionPoint&) const; }; -std::ostream& operator<<(std::ostream&, const SessionPoint&); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SessionPoint&); /** * Support for session idempotence barrier and resume as defined in @@ -78,14 +79,14 @@ class SessionState { typedef boost::iterator_range<ReplayList::iterator> ReplayRange; struct Configuration { - Configuration(size_t flush=1024*1024, size_t hard=0); + QPID_COMMON_EXTERN Configuration(size_t flush=1024*1024, size_t hard=0); size_t replayFlushLimit; // Flush when the replay list >= N bytes. 0 disables. size_t replayHardLimit; // Kill session if replay list > N bytes. 0 disables. }; - SessionState(const SessionId& =SessionId(), const Configuration& =Configuration()); + QPID_COMMON_EXTERN SessionState(const SessionId& =SessionId(), const Configuration& =Configuration()); - virtual ~SessionState(); + QPID_COMMON_EXTERN virtual ~SessionState(); bool hasState() const; @@ -100,78 +101,78 @@ class SessionState { // ==== Functions for sender state. /** Record frame f for replay. Should not be called during replay. */ - virtual void senderRecord(const framing::AMQFrame& f); + QPID_COMMON_EXTERN virtual void senderRecord(const framing::AMQFrame& f); /** @return true if we should send flush for confirmed and completed commands. */ - virtual bool senderNeedFlush() const; + QPID_COMMON_EXTERN virtual bool senderNeedFlush() const; /** Called when flush for confirmed and completed commands is sent to peer. */ - virtual void senderRecordFlush(); + QPID_COMMON_EXTERN virtual void senderRecordFlush(); /** True if we should reply to the next incoming completed command */ - virtual bool senderNeedKnownCompleted() const; + QPID_COMMON_EXTERN virtual bool senderNeedKnownCompleted() const; /** Called when knownCompleted is sent to peer. */ - virtual void senderRecordKnownCompleted(); + QPID_COMMON_EXTERN virtual void senderRecordKnownCompleted(); /** Called when the peer confirms up to comfirmed. */ - virtual void senderConfirmed(const SessionPoint& confirmed); + QPID_COMMON_EXTERN virtual void senderConfirmed(const SessionPoint& confirmed); /** Called when the peer indicates commands completed */ - virtual void senderCompleted(const SequenceSet& commands); + QPID_COMMON_EXTERN virtual void senderCompleted(const SequenceSet& commands); /** Point from which the next new (not replayed) data will be sent. */ - virtual SessionPoint senderGetCommandPoint(); + QPID_COMMON_EXTERN virtual SessionPoint senderGetCommandPoint(); /** Set of outstanding incomplete commands */ - virtual SequenceSet senderGetIncomplete() const; + QPID_COMMON_EXTERN virtual SequenceSet senderGetIncomplete() const; /** Point from which we can replay. */ - virtual SessionPoint senderGetReplayPoint() const; + QPID_COMMON_EXTERN virtual SessionPoint senderGetReplayPoint() const; /** Peer expecting commands from this point. *@return Range of frames to be replayed. */ - virtual ReplayRange senderExpected(const SessionPoint& expected); + QPID_COMMON_EXTERN virtual ReplayRange senderExpected(const SessionPoint& expected); // ==== Functions for receiver state /** Set the command point. */ - virtual void receiverSetCommandPoint(const SessionPoint& point); + QPID_COMMON_EXTERN virtual void receiverSetCommandPoint(const SessionPoint& point); /** Returns true if frame should be be processed, false if it is a duplicate. */ - virtual bool receiverRecord(const framing::AMQFrame& f); + QPID_COMMON_EXTERN virtual bool receiverRecord(const framing::AMQFrame& f); /** Command completed locally */ - virtual void receiverCompleted(SequenceNumber command, bool cumulative=false); + QPID_COMMON_EXTERN virtual void receiverCompleted(SequenceNumber command, bool cumulative=false); /** Peer has indicated commands are known completed */ - virtual void receiverKnownCompleted(const SequenceSet& commands); + QPID_COMMON_EXTERN virtual void receiverKnownCompleted(const SequenceSet& commands); /** True if the next completed control should set the timely-reply argument * to request a knonw-completed response. */ - virtual bool receiverNeedKnownCompleted() const; + QPID_COMMON_EXTERN virtual bool receiverNeedKnownCompleted() const; /** Get the incoming command point */ - virtual const SessionPoint& receiverGetExpected() const; + QPID_COMMON_EXTERN virtual const SessionPoint& receiverGetExpected() const; /** Get the received high-water-mark, may be > getExpected() during replay */ - virtual const SessionPoint& receiverGetReceived() const; + QPID_COMMON_EXTERN virtual const SessionPoint& receiverGetReceived() const; /** Completed received commands that the peer may not know about. */ - virtual const SequenceSet& receiverGetUnknownComplete() const; + QPID_COMMON_EXTERN virtual const SequenceSet& receiverGetUnknownComplete() const; /** Incomplete received commands. */ - virtual const SequenceSet& receiverGetIncomplete() const; + QPID_COMMON_EXTERN virtual const SequenceSet& receiverGetIncomplete() const; /** ID of the command currently being handled. */ - virtual SequenceNumber receiverGetCurrent() const; + QPID_COMMON_EXTERN virtual SequenceNumber receiverGetCurrent() const; /** Set the state variables, used to create a session that will resume * from some previously established point. */ - virtual void setState( + QPID_COMMON_EXTERN virtual void setState( const SequenceNumber& replayStart, const SequenceNumber& sendCommandPoint, const SequenceSet& sentIncomplete, @@ -181,6 +182,20 @@ class SessionState { const SequenceSet& receivedIncomplete ); + /** + * So called 'push' bridges work by faking a subscribe request + * (and the accompanying flows etc) to the local broker to initiate + * the outflow of messages for the bridge. + * + * As the peer doesn't send these it cannot include them in its + * session state. To keep the session state on either side of the + * bridge in sync, this hack allows the tracking of state for + * received messages to be disabled for the faked commands and + * subsequently re-enabled. + */ + QPID_COMMON_EXTERN void disableReceiverTracking(); + QPID_COMMON_EXTERN void enableReceiverTracking(); + private: struct SendState { @@ -209,6 +224,7 @@ class SessionState { uint32_t timeout; Configuration config; bool stateful; + bool receiverTrackingDisabled;//very nasty hack for 'push' bridges }; inline bool operator==(const SessionId& id, const SessionState& s) { return s == id; } diff --git a/qpid/cpp/src/qpid/StringUtils.h b/qpid/cpp/src/qpid/StringUtils.h index 3120e43334..4130fae017 100644 --- a/qpid/cpp/src/qpid/StringUtils.h +++ b/qpid/cpp/src/qpid/StringUtils.h @@ -22,6 +22,8 @@ * */ +#include "qpid/CommonImportExport.h" + #include <string> #include <vector> @@ -31,12 +33,12 @@ namespace qpid { * Split 'in' into words using delimiters in 'delims' and put * resulting strings into 'out' vector. */ -void split(std::vector<std::string>& out, const std::string& in, const std::string& delims); +QPID_COMMON_EXTERN void split(std::vector<std::string>& out, const std::string& in, const std::string& delims); /** * Split 'in' into words using delimiters in 'delims' and return the * resulting strings in a vector. */ -std::vector<std::string> split(const std::string& in, const std::string& delims); +QPID_COMMON_EXTERN std::vector<std::string> split(const std::string& in, const std::string& delims); } // namespace qpid diff --git a/qpid/cpp/src/qpid/Url.h b/qpid/cpp/src/qpid/Url.h index 07ca46e70c..353eac28f3 100644 --- a/qpid/cpp/src/qpid/Url.h +++ b/qpid/cpp/src/qpid/Url.h @@ -25,10 +25,11 @@ #include <vector> #include <new> #include <ostream> +#include "qpid/CommonImportExport.h" namespace qpid { -std::ostream& operator<<(std::ostream& os, const TcpAddress& a); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const TcpAddress& a); /** An AMQP URL contains a list of addresses */ struct Url : public std::vector<Address> { @@ -38,12 +39,12 @@ struct Url : public std::vector<Address> { /** Url with local IP address(es), may be more than one address * on a multi-homed host. */ - static Url getIpAddressesUrl(uint16_t port); + QPID_COMMON_EXTERN static Url getIpAddressesUrl(uint16_t port); struct Invalid : public Exception { Invalid(const std::string& s); }; /** Convert to string form. */ - std::string str() const; + QPID_COMMON_EXTERN std::string str() const; /** Empty URL. */ Url() {} @@ -62,14 +63,14 @@ struct Url : public std::vector<Address> { Url& operator=(const std::string& s) { parse(s); return *this; } /** Throw Invalid if the URL does not contain any addresses. */ - void throwIfEmpty() const; + QPID_COMMON_EXTERN void throwIfEmpty() const; /** Replace contents with parsed URL as defined in * https://wiki.108.redhat.com/jira/browse/AMQP-95 *@exception Invalid if the url is invalid. */ - void parse(const char* url); - void parse(const std::string& url) { parse(url.c_str()); } + QPID_COMMON_EXTERN void parse(const char* url); + QPID_COMMON_EXTERN void parse(const std::string& url) { parse(url.c_str()); } /** Replace contesnts with parsed URL as defined in * https://wiki.108.redhat.com/jira/browse/AMQP-95 @@ -84,8 +85,8 @@ struct Url : public std::vector<Address> { inline bool operator==(const Url& a, const Url& b) { return a.str()==b.str(); } inline bool operator!=(const Url& a, const Url& b) { return a.str()!=b.str(); } -std::ostream& operator<<(std::ostream& os, const Url& url); -std::istream& operator>>(std::istream& is, Url& url); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& os, const Url& url); +QPID_COMMON_EXTERN std::istream& operator>>(std::istream& is, Url& url); } // namespace qpid diff --git a/qpid/cpp/src/qpid/Version.h b/qpid/cpp/src/qpid/Version.h index 9bd561b7a9..ab7957e000 100755 --- a/qpid/cpp/src/qpid/Version.h +++ b/qpid/cpp/src/qpid/Version.h @@ -36,7 +36,7 @@ namespace qpid { # endif #else const std::string product = "qpidc"; - const std::string version = "0.3"; + const std::string version = "0.5"; const std::string saslName = "qpid-broker"; #endif } diff --git a/qpid/cpp/src/qpid/acl/AclPlugin.cpp b/qpid/cpp/src/qpid/acl/AclPlugin.cpp index 7310139041..4c6efa19dd 100644 --- a/qpid/cpp/src/qpid/acl/AclPlugin.cpp +++ b/qpid/cpp/src/qpid/acl/AclPlugin.cpp @@ -62,15 +62,10 @@ struct AclPlugin : public Plugin { if (acl) throw Exception("ACL plugin cannot be initialized twice in one process."); - if (values.aclFile.at(0) == '/') - { - values.aclFile = values.aclFile; - } - else - { - std::ostringstream oss; - oss << b.getDataDir().getPath() << "/" << values.aclFile; - values.aclFile = oss.str(); + if (values.aclFile.at(0) != '/' && !b.getDataDir().getPath().empty()) { + std::ostringstream oss; + oss << b.getDataDir().getPath() << "/" << values.aclFile; + values.aclFile = oss.str(); } acl = new Acl(values, b); diff --git a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp index 1e2f4cdd78..7c70c12213 100644 --- a/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp +++ b/qpid/cpp/src/qpid/agent/ManagementAgentImpl.cpp @@ -151,7 +151,7 @@ void ManagementAgentImpl::init(const client::ConnectionSettings& settings, // TODO: Abstract the socket calls for portability if (extThread) { int pair[2]; - int result = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair); + int result = socketpair(PF_UNIX, SOCK_STREAM, 0, pair); if (result == -1) { return; } @@ -485,6 +485,9 @@ void ManagementAgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, st Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE); uint32_t outLen; + if (object->getConfigChanged() || object->getInstChanged()) + object->setUpdateTime(); + encodeHeader(outBuffer, 'g', sequence); object->writeProperties(outBuffer); object->writeStatistics(outBuffer, true); @@ -508,6 +511,9 @@ void ManagementAgentImpl::handleGetQuery(Buffer& inBuffer, uint32_t sequence, st Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); uint32_t outLen; + if (object->getConfigChanged() || object->getInstChanged()) + object->setUpdateTime(); + encodeHeader(outBuffer, 'g', sequence); object->writeProperties(outBuffer); object->writeStatistics(outBuffer, true); diff --git a/qpid/cpp/src/qpid/amqp_0_10/Connection.h b/qpid/cpp/src/qpid/amqp_0_10/Connection.h index 743a7de3aa..3e0a5d1ee8 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/Connection.h +++ b/qpid/cpp/src/qpid/amqp_0_10/Connection.h @@ -27,6 +27,7 @@ #include "qpid/sys/ConnectionInputHandler.h" #include "qpid/sys/ConnectionOutputHandler.h" #include "qpid/sys/Mutex.h" +#include "qpid/broker/BrokerImportExport.h" #include <boost/intrusive_ptr.hpp> #include <memory> #include <deque> @@ -56,8 +57,8 @@ class Connection : public sys::ConnectionCodec, size_t buffered; public: - Connection(sys::OutputControl&, const std::string& id, bool isClient); - void setInputHandler(std::auto_ptr<sys::ConnectionInputHandler> c); + QPID_BROKER_EXTERN Connection(sys::OutputControl&, const std::string& id, bool isClient); + QPID_BROKER_EXTERN void setInputHandler(std::auto_ptr<sys::ConnectionInputHandler> c); size_t decode(const char* buffer, size_t size); size_t encode(const char* buffer, size_t size); bool isClosed() const; diff --git a/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.cpp b/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.cpp index f58d59cbd7..db957051d8 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.cpp +++ b/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.cpp @@ -277,7 +277,6 @@ void SessionHandler::sendCompletion() { } void SessionHandler::sendAttach(bool force) { - CHECK_ATTACHED("session.send-attach"); QPID_LOG(debug, "SessionHandler::sendAttach attach id=" << getState()->getId()); peer.attach(getState()->getId().getName(), force); if (getState()->hasState()) diff --git a/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.h b/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.h index d7af7dd6c7..0b158ec2b4 100644 --- a/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.h +++ b/qpid/cpp/src/qpid/amqp_0_10/SessionHandler.h @@ -26,6 +26,7 @@ #include "qpid/framing/AMQP_AllProxy.h" #include "qpid/framing/AMQP_AllOperations.h" #include "qpid/SessionState.h" +#include "qpid/CommonImportExport.h" namespace qpid { @@ -43,8 +44,8 @@ class SessionHandler : public framing::AMQP_AllOperations::SessionHandler, public framing::FrameHandler::InOutHandler { public: - SessionHandler(framing::FrameHandler* out=0, uint16_t channel=0); - ~SessionHandler(); + QPID_COMMON_EXTERN SessionHandler(framing::FrameHandler* out=0, uint16_t channel=0); + QPID_COMMON_EXTERN ~SessionHandler(); void setChannel(uint16_t ch) { channel = ch; } uint16_t getChannel() const { return channel.get(); } @@ -55,35 +56,35 @@ class SessionHandler : public framing::AMQP_AllOperations::SessionHandler, virtual framing::FrameHandler* getInHandler() = 0; // Non-protocol methods, called locally to initiate some action. - void sendDetach(); - void sendCompletion(); - void sendAttach(bool force); - void sendTimeout(uint32_t t); - void sendFlush(); - void markReadyToSend();//TODO: only needed for inter-broker bridge; cleanup + QPID_COMMON_EXTERN void sendDetach(); + QPID_COMMON_EXTERN void sendCompletion(); + QPID_COMMON_EXTERN void sendAttach(bool force); + QPID_COMMON_EXTERN void sendTimeout(uint32_t t); + QPID_COMMON_EXTERN void sendFlush(); + QPID_COMMON_EXTERN void markReadyToSend();//TODO: only needed for inter-broker bridge; cleanup /** True if the handler is ready to send and receive */ bool ready() const; // Protocol methods - void attach(const std::string& name, bool force); - void attached(const std::string& name); - void detach(const std::string& name); - void detached(const std::string& name, uint8_t code); - - void requestTimeout(uint32_t t); - void timeout(uint32_t t); - - void commandPoint(const framing::SequenceNumber& id, uint64_t offset); - void expected(const framing::SequenceSet& commands, const framing::Array& fragments); - void confirmed(const framing::SequenceSet& commands,const framing::Array& fragments); - void completed(const framing::SequenceSet& commands, bool timelyReply); - void knownCompleted(const framing::SequenceSet& commands); - void flush(bool expected, bool confirmed, bool completed); - void gap(const framing::SequenceSet& commands); + QPID_COMMON_EXTERN void attach(const std::string& name, bool force); + QPID_COMMON_EXTERN void attached(const std::string& name); + QPID_COMMON_EXTERN void detach(const std::string& name); + QPID_COMMON_EXTERN void detached(const std::string& name, uint8_t code); + + QPID_COMMON_EXTERN void requestTimeout(uint32_t t); + QPID_COMMON_EXTERN void timeout(uint32_t t); + + QPID_COMMON_EXTERN void commandPoint(const framing::SequenceNumber& id, uint64_t offset); + QPID_COMMON_EXTERN void expected(const framing::SequenceSet& commands, const framing::Array& fragments); + QPID_COMMON_EXTERN void confirmed(const framing::SequenceSet& commands,const framing::Array& fragments); + QPID_COMMON_EXTERN void completed(const framing::SequenceSet& commands, bool timelyReply); + QPID_COMMON_EXTERN void knownCompleted(const framing::SequenceSet& commands); + QPID_COMMON_EXTERN void flush(bool expected, bool confirmed, bool completed); + QPID_COMMON_EXTERN void gap(const framing::SequenceSet& commands); protected: - virtual void invoke(const framing::AMQMethodBody& m); + QPID_COMMON_EXTERN virtual void invoke(const framing::AMQMethodBody& m); virtual void setState(const std::string& sessionName, bool force) = 0; virtual void channelException(framing::session::DetachCode code, const std::string& msg) = 0; @@ -94,9 +95,9 @@ class SessionHandler : public framing::AMQP_AllOperations::SessionHandler, virtual void readyToSend() {} virtual void readyToReceive() {} - virtual void handleDetach(); - virtual void handleIn(framing::AMQFrame&); - virtual void handleOut(framing::AMQFrame&); + QPID_COMMON_EXTERN virtual void handleDetach(); + QPID_COMMON_EXTERN virtual void handleIn(framing::AMQFrame&); + QPID_COMMON_EXTERN virtual void handleOut(framing::AMQFrame&); framing::ChannelHandler channel; framing::AMQP_AllProxy::Session peer; diff --git a/qpid/cpp/src/qpid/assert.cpp b/qpid/cpp/src/qpid/assert.cpp index 5d039da528..bf36d3be86 100644 --- a/qpid/cpp/src/qpid/assert.cpp +++ b/qpid/cpp/src/qpid/assert.cpp @@ -35,7 +35,7 @@ void assert_fail(char const * expr, char const * function, char const * file, lo #ifdef NDEBUG throw framing::InternalErrorException(msg.str()); #else - std::cerr << msg << std::endl; + std::cerr << msg.str() << std::endl; abort(); #endif } diff --git a/qpid/cpp/src/qpid/broker/Bridge.cpp b/qpid/cpp/src/qpid/broker/Bridge.cpp index 38a9b5d64c..4d275b958f 100644 --- a/qpid/cpp/src/qpid/broker/Bridge.cpp +++ b/qpid/cpp/src/qpid/broker/Bridge.cpp @@ -22,6 +22,7 @@ #include "ConnectionState.h" #include "Connection.h" #include "LinkRegistry.h" +#include "SessionState.h" #include "qpid/agent/ManagementAgent.h" #include "qpid/framing/FieldTable.h" @@ -80,31 +81,31 @@ Bridge::~Bridge() mgmtObject->resourceDestroy(); } -void Bridge::create(ConnectionState& c) +void Bridge::create(Connection& c) { + connState = &c; FieldTable options; if (args.i_sync) options.setInt("qpid.sync_frequency", args.i_sync); - connState = &c; + SessionHandler& sessionHandler = c.getChannel(id); if (args.i_srcIsLocal) { if (args.i_dynamic) throw Exception("Dynamic routing not supported for push routes"); // Point the bridging commands at the local connection handler - Connection* conn = dynamic_cast<Connection*>(&c); - if (conn == 0) - return; - pushHandler.reset(new PushHandler(conn)); + pushHandler.reset(new PushHandler(&c)); channelHandler.reset(new framing::ChannelHandler(id, pushHandler.get())); + + session.reset(new framing::AMQP_ServerProxy::Session(*channelHandler)); + peer.reset(new framing::AMQP_ServerProxy(*channelHandler)); + + session->attach(name, false); + session->commandPoint(0,0); } else { + sessionHandler.attachAs(name); // Point the bridging commands at the remote peer broker - channelHandler.reset(new framing::ChannelHandler(id, &(connState->getOutput()))); + peer.reset(new framing::AMQP_ServerProxy(sessionHandler.out)); } - session.reset(new framing::AMQP_ServerProxy::Session(*channelHandler)); - peer.reset(new framing::AMQP_ServerProxy(*channelHandler)); - - session->attach(name, false); - session->commandPoint(0,0); - + if (args.i_srcIsLocal) sessionHandler.getSession()->disableReceiverTracking(); if (args.i_srcIsQueue) { peer->getMessage().subscribe(args.i_src, args.i_dest, args.i_sync ? 0 : 1, 0, false, "", 0, options); peer->getMessage().flow(args.i_dest, 0, 0xFFFFFFFF); @@ -116,7 +117,7 @@ void Bridge::create(ConnectionState& c) if (args.i_tag.size()) { queueSettings.setString("qpid.trace.id", args.i_tag); } else { - const string& peerTag = connState->getFederationPeerTag(); + const string& peerTag = c.getFederationPeerTag(); if (peerTag.size()) queueSettings.setString("qpid.trace.id", peerTag); } @@ -129,7 +130,7 @@ void Bridge::create(ConnectionState& c) queueSettings.setString("qpid.trace.exclude", localTag); } - bool durable = false;//should this be an arg, or would be use srcIsQueue for durable queues? + bool durable = false;//should this be an arg, or would we use srcIsQueue for durable queues? bool autoDelete = !durable;//auto delete transient queues? peer->getQueue().declare(queueName, "", false, durable, true, autoDelete, queueSettings); if (!args.i_dynamic) @@ -148,12 +149,23 @@ void Bridge::create(ConnectionState& c) QPID_LOG(debug, "Activated static route from exchange " << args.i_src << " to " << args.i_dest); } } + if (args.i_srcIsLocal) sessionHandler.getSession()->enableReceiverTracking(); } -void Bridge::cancel() +void Bridge::cancel(Connection& c) { + if (args.i_srcIsLocal) { + //recreate peer to be sure that the session handler reference + //is valid (it could have been deleted due to a detach) + SessionHandler& sessionHandler = c.getChannel(id); + peer.reset(new framing::AMQP_ServerProxy(sessionHandler.out)); + } peer->getMessage().cancel(args.i_dest); peer->getSession().detach(name); +} + +void Bridge::closed() +{ if (args.i_dynamic) { Exchange::shared_ptr exchange = link->getBroker()->getExchanges().get(args.i_src); if (exchange.get() != 0) @@ -166,13 +178,13 @@ void Bridge::destroy() listener(this); } -void Bridge::setPersistenceId(uint64_t id) const +void Bridge::setPersistenceId(uint64_t pId) const { if (mgmtObject != 0 && persistenceId == 0) { ManagementAgent* agent = ManagementAgent::Singleton::getInstance(); - agent->addObject (mgmtObject, id); + agent->addObject (mgmtObject, pId); } - persistenceId = id; + persistenceId = pId; } const string& Bridge::getName() const diff --git a/qpid/cpp/src/qpid/broker/Bridge.h b/qpid/cpp/src/qpid/broker/Bridge.h index c530a5d696..dae28ddeaa 100644 --- a/qpid/cpp/src/qpid/broker/Bridge.h +++ b/qpid/cpp/src/qpid/broker/Bridge.h @@ -52,8 +52,9 @@ public: const qmf::org::apache::qpid::broker::ArgsLinkBridge& args); ~Bridge(); - void create(ConnectionState& c); - void cancel(); + void create(Connection& c); + void cancel(Connection& c); + void closed(); void destroy(); bool isDurable() { return args.i_durable; } diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp index 95f55bb596..3f9effc08f 100644 --- a/qpid/cpp/src/qpid/broker/Broker.cpp +++ b/qpid/cpp/src/qpid/broker/Broker.cpp @@ -199,6 +199,7 @@ Broker::Broker(const Broker::Options& conf) : } QueuePolicy::setDefaultMaxSize(conf.queueLimit); + queues.setQueueEvents(&queueEvents); // Early-Initialize plugins const Plugin::Plugins& plugins=Plugin::getPlugins(); @@ -383,9 +384,9 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId, _qmf::ArgsBrokerQueueMoveMessages& moveArgs= dynamic_cast<_qmf::ArgsBrokerQueueMoveMessages&>(args); if (queueMoveMessages(moveArgs.i_srcQueue, moveArgs.i_destQueue, moveArgs.i_qty)) - status = Manageable::STATUS_OK; + status = Manageable::STATUS_OK; else - return Manageable::STATUS_INVALID_PARAMETER; + return Manageable::STATUS_INVALID_PARAMETER; break; } default: diff --git a/qpid/cpp/src/qpid/broker/Broker.h b/qpid/cpp/src/qpid/broker/Broker.h index a52a0f67e0..5a1529a3ba 100644 --- a/qpid/cpp/src/qpid/broker/Broker.h +++ b/qpid/cpp/src/qpid/broker/Broker.h @@ -22,6 +22,7 @@ * */ +#include "BrokerImportExport.h" #include "ConnectionFactory.h" #include "ConnectionToken.h" #include "DirectExchange.h" @@ -80,15 +81,16 @@ struct NoSuchTransportException : qpid::Exception * A broker instance. */ class Broker : public sys::Runnable, public Plugin::Target, - public management::Manageable, public RefCounted + public management::Manageable, + public RefCounted { - public: +public: struct Options : public qpid::Options { static const std::string DEFAULT_DATA_DIR_LOCATION; static const std::string DEFAULT_DATA_DIR_NAME; - Options(const std::string& name="Broker Options"); + QPID_BROKER_EXTERN Options(const std::string& name="Broker Options"); bool noDataDir; std::string dataDir; @@ -148,9 +150,9 @@ class Broker : public sys::Runnable, public Plugin::Target, virtual ~Broker(); - Broker(const Options& configuration); - static boost::intrusive_ptr<Broker> create(const Options& configuration); - static boost::intrusive_ptr<Broker> create(int16_t port = DEFAULT_PORT); + QPID_BROKER_EXTERN Broker(const Options& configuration); + static QPID_BROKER_EXTERN boost::intrusive_ptr<Broker> create(const Options& configuration); + static QPID_BROKER_EXTERN boost::intrusive_ptr<Broker> create(int16_t port = DEFAULT_PORT); /** * Return listening port. If called before bind this is @@ -169,7 +171,7 @@ class Broker : public sys::Runnable, public Plugin::Target, /** Shut down the broker */ virtual void shutdown(); - void setStore (MessageStore*); + QPID_BROKER_EXTERN void setStore (MessageStore*); MessageStore& getStore() { return *store; } void setAcl (AclModule* _acl) {acl = _acl;} AclModule* getAcl() { return acl; } @@ -229,7 +231,7 @@ class Broker : public sys::Runnable, public Plugin::Target, boost::function<std::vector<Url> ()> getKnownBrokers; - static const std::string TCP_TRANSPORT; + static QPID_BROKER_EXTERN const std::string TCP_TRANSPORT; void setRecovery(bool set) { recovery = set; } bool getRecovery() const { return recovery; } diff --git a/qpid/cpp/src/qpid/broker/BrokerImportExport.h b/qpid/cpp/src/qpid/broker/BrokerImportExport.h new file mode 100644 index 0000000000..2edc90993e --- /dev/null +++ b/qpid/cpp/src/qpid/broker/BrokerImportExport.h @@ -0,0 +1,33 @@ +#ifndef QPID_BROKER_IMPORT_EXPORT_H +#define QPID_BROKER_IMPORT_EXPORT_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. + */ + +#if defined(WIN32) && !defined(QPID_BROKER_STATIC) +#if defined(BROKER_EXPORT) +#define QPID_BROKER_EXTERN __declspec(dllexport) +#else +#define QPID_BROKER_EXTERN __declspec(dllimport) +#endif +#else +#define QPID_BROKER_EXTERN +#endif + +#endif diff --git a/qpid/cpp/src/qpid/broker/BrokerSingleton.h b/qpid/cpp/src/qpid/broker/BrokerSingleton.h index 22b707506b..3a842ee05a 100644 --- a/qpid/cpp/src/qpid/broker/BrokerSingleton.h +++ b/qpid/cpp/src/qpid/broker/BrokerSingleton.h @@ -20,6 +20,7 @@ */ #include "Broker.h" +#include "BrokerImportExport.h" namespace qpid { namespace broker { @@ -36,7 +37,7 @@ namespace broker { * * THREAD UNSAFE. */ -class BrokerSingleton : public boost::intrusive_ptr<Broker> +class QPID_BROKER_EXTERN BrokerSingleton : public boost::intrusive_ptr<Broker> { public: BrokerSingleton(); diff --git a/qpid/cpp/src/qpid/broker/Connection.cpp b/qpid/cpp/src/qpid/broker/Connection.cpp index b7446a2220..b06e06d353 100644 --- a/qpid/cpp/src/qpid/broker/Connection.cpp +++ b/qpid/cpp/src/qpid/broker/Connection.cpp @@ -80,7 +80,8 @@ Connection::Connection(ConnectionOutputHandler* out_, Broker& broker_, const std void Connection::requestIOProcessing(boost::function0<void> callback) { - ioCallback = callback; + ScopedLock<Mutex> l(ioCallbackLock); + ioCallbacks.push(callback); out.activateOutput(); } @@ -221,10 +222,13 @@ bool Connection::hasOutput() { return outputTasks.hasOutput(); } bool Connection::doOutput() { try{ - if (ioCallback) - ioCallback(); // Lend the IO thread for management processing - ioCallback = 0; - + { + ScopedLock<Mutex> l(ioCallbackLock); + while (!ioCallbacks.empty()) { + ioCallbacks.front()(); // Lend the IO thread for management processing + ioCallbacks.pop(); + } + } if (mgmtClosing) close(connection::CLOSE_CODE_CONNECTION_FORCED, "Closed by Management Request"); else diff --git a/qpid/cpp/src/qpid/broker/Connection.h b/qpid/cpp/src/qpid/broker/Connection.h index 71e03d76d4..b659fe6468 100644 --- a/qpid/cpp/src/qpid/broker/Connection.h +++ b/qpid/cpp/src/qpid/broker/Connection.h @@ -25,6 +25,7 @@ #include <memory> #include <sstream> #include <vector> +#include <queue> #include <boost/ptr_container/ptr_map.hpp> @@ -47,6 +48,7 @@ #include "qpid/sys/ConnectionOutputHandler.h" #include "qpid/sys/Socket.h" #include "qpid/sys/TimeoutHandler.h" +#include "qpid/sys/Mutex.h" #include <boost/ptr_container/ptr_map.hpp> #include <boost/bind.hpp> @@ -119,12 +121,15 @@ class Connection : public sys::ConnectionInputHandler, const bool isLink; bool mgmtClosing; const std::string mgmtId; - boost::function0<void> ioCallback; + sys::Mutex ioCallbackLock; + std::queue<boost::function0<void> > ioCallbacks; qmf::org::apache::qpid::broker::Connection* mgmtObject; LinkRegistry& links; management::ManagementAgent* agent; Timer& timer; boost::intrusive_ptr<TimerTask> heartbeatTimer; + public: + qmf::org::apache::qpid::broker::Connection* getMgmtObject() { return mgmtObject; } }; }} diff --git a/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp b/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp index f136d61462..63212c7794 100644 --- a/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp +++ b/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp @@ -24,8 +24,7 @@ #include "Connection.h" #include "SecureConnection.h" #include "qpid/Url.h" -#include "qpid/framing/ClientInvoker.h" -#include "qpid/framing/ServerInvoker.h" +#include "qpid/framing/AllInvoker.h" #include "qpid/framing/enum.h" #include "qpid/log/Statement.h" #include "qpid/sys/SecurityLayer.h" @@ -46,37 +45,33 @@ const std::string en_US = "en_US"; const std::string QPID_FED_LINK = "qpid.fed_link"; const std::string QPID_FED_TAG = "qpid.federation_tag"; const std::string SESSION_FLOW_CONTROL("qpid.session_flow"); +const std::string CLIENT_PROCESS_NAME("qpid.client_process"); +const std::string CLIENT_PID("qpid.client_pid"); +const std::string CLIENT_PPID("qpid.client_ppid"); const int SESSION_FLOW_CONTROL_VER = 1; } void ConnectionHandler::close(connection::CloseCode code, const string& text) { - handler->client.close(code, text); + handler->proxy.close(code, text); } void ConnectionHandler::heartbeat() { - handler->client.heartbeat(); + handler->proxy.heartbeat(); } void ConnectionHandler::handle(framing::AMQFrame& frame) { AMQMethodBody* method=frame.getBody()->getMethod(); try{ - bool handled = false; - if (handler->serverMode) { - handled = invoke(static_cast<AMQP_ServerOperations::ConnectionHandler&>(*handler.get()), *method); - } else { - handled = invoke(static_cast<AMQP_ClientOperations::ConnectionHandler&>(*handler.get()), *method); - } - if (!handled) { + if (!invoke(static_cast<AMQP_AllOperations::ConnectionHandler&>(*handler.get()), *method)) { handler->connection.getChannel(frame.getChannel()).in(frame); } - }catch(ConnectionException& e){ - handler->client.close(e.code, e.what()); + handler->proxy.close(e.code, e.what()); }catch(std::exception& e){ - handler->client.close(541/*internal error*/, e.what()); + handler->proxy.close(541/*internal error*/, e.what()); } } @@ -88,7 +83,7 @@ void ConnectionHandler::setSecureConnection(SecureConnection* secured) ConnectionHandler::ConnectionHandler(Connection& connection, bool isClient) : handler(new Handler(connection, isClient)) {} ConnectionHandler::Handler::Handler(Connection& c, bool isClient) : - client(c.getOutput()), server(c.getOutput()), + proxy(c.getOutput()), connection(c), serverMode(!isClient), acl(0), secured(0) { if (serverMode) { @@ -106,7 +101,7 @@ ConnectionHandler::Handler::Handler(Connection& c, bool isClient) : Array locales(0x95); boost::shared_ptr<FieldValue> l(new Str16Value(en_US)); locales.add(l); - client.start(properties, mechanisms, locales); + proxy.start(properties, mechanisms, locales); } } @@ -136,14 +131,27 @@ void ConnectionHandler::Handler::startOk(const framing::FieldTable& clientProper connection.setFederationPeerTag(clientProperties.getAsString(QPID_FED_TAG)); if (connection.isFederationLink()) { if (acl && !acl->authorise(connection.getUserId(),acl::ACT_CREATE,acl::OBJ_LINK,"")){ - client.close(framing::connection::CLOSE_CODE_CONNECTION_FORCED,"ACL denied creating a federation link"); + proxy.close(framing::connection::CLOSE_CODE_CONNECTION_FORCED,"ACL denied creating a federation link"); return; } QPID_LOG(info, "Connection is a federation link"); } - if ( clientProperties.getAsInt(SESSION_FLOW_CONTROL) == SESSION_FLOW_CONTROL_VER ) { + if (clientProperties.getAsInt(SESSION_FLOW_CONTROL) == SESSION_FLOW_CONTROL_VER) { connection.setClientThrottling(); } + + if (connection.getMgmtObject() != 0) { + string procName = clientProperties.getAsString(CLIENT_PROCESS_NAME); + uint32_t pid = clientProperties.getAsInt(CLIENT_PID); + uint32_t ppid = clientProperties.getAsInt(CLIENT_PPID); + + if (!procName.empty()) + connection.getMgmtObject()->set_remoteProcessName(procName); + if (pid != 0) + connection.getMgmtObject()->set_remotePid(pid); + if (ppid != 0) + connection.getMgmtObject()->set_remoteParentPid(ppid); + } } void ConnectionHandler::Handler::secureOk(const string& response) @@ -177,7 +185,7 @@ void ConnectionHandler::Handler::open(const string& /*virtualHost*/, framing::Array array(0x95); // str16 array for (std::vector<Url>::iterator i = urls.begin(); i < urls.end(); ++i) array.add(boost::shared_ptr<Str16Value>(new Str16Value(i->str()))); - client.openOk(array); + proxy.openOk(array); //install security layer if one has been negotiated: if (secured) { @@ -196,7 +204,7 @@ void ConnectionHandler::Handler::close(uint16_t replyCode, const string& replyTe if (replyCode == framing::connection::CLOSE_CODE_CONNECTION_FORCED) connection.notifyConnectionForced(replyText); - client.closeOk(); + proxy.closeOk(); connection.getOutput().close(); } @@ -222,12 +230,12 @@ void ConnectionHandler::Handler::start(const FieldTable& serverProperties, FieldTable ft; ft.setInt(QPID_FED_LINK,1); ft.setString(QPID_FED_TAG, connection.getBroker().getFederationTag()); - server.startOk(ft, mechanism, response, en_US); + proxy.startOk(ft, mechanism, response, en_US); } void ConnectionHandler::Handler::secure(const string& /*challenge*/) { - server.secureOk(""); + proxy.secureOk(""); } void ConnectionHandler::Handler::tune(uint16_t channelMax, @@ -237,8 +245,8 @@ void ConnectionHandler::Handler::tune(uint16_t channelMax, { connection.setFrameMax(frameMax); connection.setHeartbeat(heartbeatMax); - server.tuneOk(channelMax, frameMax, heartbeatMax); - server.open("/", Array(), true); + proxy.tuneOk(channelMax, frameMax, heartbeatMax); + proxy.open("/", Array(), true); } void ConnectionHandler::Handler::openOk(const framing::Array& knownHosts) diff --git a/qpid/cpp/src/qpid/broker/ConnectionHandler.h b/qpid/cpp/src/qpid/broker/ConnectionHandler.h index b24c10e9e8..ac4816dafa 100644 --- a/qpid/cpp/src/qpid/broker/ConnectionHandler.h +++ b/qpid/cpp/src/qpid/broker/ConnectionHandler.h @@ -25,10 +25,8 @@ #include "SaslAuthenticator.h" #include "qpid/framing/amqp_types.h" #include "qpid/framing/AMQFrame.h" -#include "qpid/framing/AMQP_ClientOperations.h" -#include "qpid/framing/AMQP_ClientProxy.h" -#include "qpid/framing/AMQP_ServerOperations.h" -#include "qpid/framing/AMQP_ServerProxy.h" +#include "qpid/framing/AMQP_AllOperations.h" +#include "qpid/framing/AMQP_AllProxy.h" #include "qpid/framing/enum.h" #include "qpid/framing/FrameHandler.h" #include "qpid/framing/ProtocolInitiation.h" @@ -44,11 +42,9 @@ class SecureConnection; class ConnectionHandler : public framing::FrameHandler { - struct Handler : public framing::AMQP_ServerOperations::ConnectionHandler, - public framing::AMQP_ClientOperations::ConnectionHandler + struct Handler : public framing::AMQP_AllOperations::ConnectionHandler { - framing::AMQP_ClientProxy::Connection client; - framing::AMQP_ServerProxy::Connection server; + framing::AMQP_AllProxy::Connection proxy; Connection& connection; bool serverMode; std::auto_ptr<SaslAuthenticator> authenticator; diff --git a/qpid/cpp/src/qpid/broker/ConnectionState.h b/qpid/cpp/src/qpid/broker/ConnectionState.h index 0e9d211b56..b712af11f5 100644 --- a/qpid/cpp/src/qpid/broker/ConnectionState.h +++ b/qpid/cpp/src/qpid/broker/ConnectionState.h @@ -48,8 +48,9 @@ class ConnectionState : public ConnectionToken, public management::Manageable heartbeatmax(120), stagingThreshold(broker.getStagingThreshold()), federationLink(true), - clientSupportsThrottling(false) - {} + clientSupportsThrottling(false), + clusterOrderOut(0) + {} virtual ~ConnectionState () {} @@ -75,7 +76,7 @@ class ConnectionState : public ConnectionToken, public management::Manageable const string& getFederationPeerTag() const { return federationPeerTag; } std::vector<Url>& getKnownHosts() { return knownHosts; } - void setClientThrottling() { clientSupportsThrottling = true; } + void setClientThrottling(bool set=true) { clientSupportsThrottling = set; } bool getClientThrottling() const { return clientSupportsThrottling; } Broker& getBroker() { return broker; } @@ -86,11 +87,21 @@ class ConnectionState : public ConnectionToken, public management::Manageable //contained output tasks sys::AggregateOutput outputTasks; - sys::ConnectionOutputHandlerPtr& getOutput() { return out; } + sys::ConnectionOutputHandler& getOutput() { return out; } framing::ProtocolVersion getVersion() const { return version; } - void setOutputHandler(qpid::sys::ConnectionOutputHandler* o) { out.set(o); } + /** + * If the broker is part of a cluster, this is a handler provided + * by cluster code. It ensures consistent ordering of commands + * that are sent based on criteria that are not predictably + * ordered cluster-wide, e.g. a timer firing. + */ + framing::FrameHandler* getClusterOrderOutput() { return clusterOrderOut; } + void setClusterOrderOutput(framing::FrameHandler& fh) { clusterOrderOut = &fh; } + + virtual void requestIOProcessing (boost::function0<void>) = 0; + protected: framing::ProtocolVersion version; uint32_t framemax; @@ -103,6 +114,7 @@ class ConnectionState : public ConnectionToken, public management::Manageable string federationPeerTag; std::vector<Url> knownHosts; bool clientSupportsThrottling; + framing::FrameHandler* clusterOrderOut; }; }} diff --git a/qpid/cpp/src/qpid/broker/Daemon.h b/qpid/cpp/src/qpid/broker/Daemon.h index 98468debb7..a9cd98bce2 100644 --- a/qpid/cpp/src/qpid/broker/Daemon.h +++ b/qpid/cpp/src/qpid/broker/Daemon.h @@ -19,10 +19,12 @@ * */ -#include <string> +#include "qpid/sys/IntegerTypes.h" #include <boost/scoped_ptr.hpp> #include <boost/function.hpp> #include <boost/noncopyable.hpp> +#include <string> + namespace qpid { namespace broker { diff --git a/qpid/cpp/src/qpid/broker/DeliverableMessage.h b/qpid/cpp/src/qpid/broker/DeliverableMessage.h index f5db473c22..ad944c746b 100644 --- a/qpid/cpp/src/qpid/broker/DeliverableMessage.h +++ b/qpid/cpp/src/qpid/broker/DeliverableMessage.h @@ -21,6 +21,7 @@ #ifndef _DeliverableMessage_ #define _DeliverableMessage_ +#include "BrokerImportExport.h" #include "Deliverable.h" #include "Queue.h" #include "Message.h" @@ -32,10 +33,10 @@ namespace qpid { class DeliverableMessage : public Deliverable{ boost::intrusive_ptr<Message> msg; public: - DeliverableMessage(const boost::intrusive_ptr<Message>& msg); - virtual void deliverTo(const boost::shared_ptr<Queue>& queue); - Message& getMessage(); - uint64_t contentSize(); + QPID_BROKER_EXTERN DeliverableMessage(const boost::intrusive_ptr<Message>& msg); + QPID_BROKER_EXTERN virtual void deliverTo(const boost::shared_ptr<Queue>& queue); + QPID_BROKER_EXTERN Message& getMessage(); + QPID_BROKER_EXTERN uint64_t contentSize(); virtual ~DeliverableMessage(){} }; } diff --git a/qpid/cpp/src/qpid/broker/DeliveryRecord.h b/qpid/cpp/src/qpid/broker/DeliveryRecord.h index d7ccab0726..2b2d4d0515 100644 --- a/qpid/cpp/src/qpid/broker/DeliveryRecord.h +++ b/qpid/cpp/src/qpid/broker/DeliveryRecord.h @@ -26,6 +26,7 @@ #include <vector> #include <ostream> #include "qpid/framing/SequenceSet.h" +#include "BrokerImportExport.h" #include "Queue.h" #include "QueuedMessage.h" #include "DeliveryId.h" @@ -74,17 +75,16 @@ class DeliveryRecord const uint32_t credit; public: - DeliveryRecord( - const QueuedMessage& msg, - const Queue::shared_ptr& queue, - const std::string& tag, - bool acquired, - bool accepted, - bool windowing, - uint32_t credit=0 // Only used if msg is empty. + QPID_BROKER_EXTERN DeliveryRecord(const QueuedMessage& msg, + const Queue::shared_ptr& queue, + const std::string& tag, + bool acquired, + bool accepted, + bool windowing, + uint32_t credit=0 // Only used if msg is empty. ); - bool matches(DeliveryId tag) const; + QPID_BROKER_EXTERN bool matches(DeliveryId tag) const; bool matchOrAfter(DeliveryId tag) const; bool after(DeliveryId tag) const; bool coveredBy(const framing::SequenceSet* const range) const; @@ -119,7 +119,7 @@ class DeliveryRecord const QueuedMessage& getMessage() const { return msg; } framing::SequenceNumber getId() const { return id; } Queue::shared_ptr getQueue() const { return queue; } - friend bool operator<(const DeliveryRecord&, const DeliveryRecord&); + friend QPID_BROKER_EXTERN bool operator<(const DeliveryRecord&, const DeliveryRecord&); friend std::ostream& operator<<(std::ostream&, const DeliveryRecord&); }; diff --git a/qpid/cpp/src/qpid/broker/DirectExchange.h b/qpid/cpp/src/qpid/broker/DirectExchange.h index ba60469df8..27d101c4fe 100644 --- a/qpid/cpp/src/qpid/broker/DirectExchange.h +++ b/qpid/cpp/src/qpid/broker/DirectExchange.h @@ -23,6 +23,7 @@ #include <map> #include <vector> +#include "BrokerImportExport.h" #include "Exchange.h" #include "qpid/framing/FieldTable.h" #include "qpid/sys/CopyOnWriteArray.h" @@ -44,18 +45,27 @@ class DirectExchange : public virtual Exchange { public: static const std::string typeName; - DirectExchange(const std::string& name, management::Manageable* parent = 0); - DirectExchange(const string& _name, bool _durable, - const qpid::framing::FieldTable& _args, management::Manageable* parent = 0); + QPID_BROKER_EXTERN DirectExchange(const std::string& name, + management::Manageable* parent = 0); + QPID_BROKER_EXTERN DirectExchange(const string& _name, + bool _durable, + const qpid::framing::FieldTable& _args, + management::Manageable* parent = 0); virtual std::string getType() const { return typeName; } - virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args); + QPID_BROKER_EXTERN virtual bool bind(Queue::shared_ptr queue, + const std::string& routingKey, + const qpid::framing::FieldTable* args); 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 bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args); + QPID_BROKER_EXTERN virtual void route(Deliverable& msg, + const std::string& routingKey, + const qpid::framing::FieldTable* args); + QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue, + const string* const routingKey, + const qpid::framing::FieldTable* const args); - virtual ~DirectExchange(); + QPID_BROKER_EXTERN virtual ~DirectExchange(); virtual bool supportsDynamicBinding() { return true; } }; diff --git a/qpid/cpp/src/qpid/broker/DtxBuffer.h b/qpid/cpp/src/qpid/broker/DtxBuffer.h index b302632037..ce37d09b7a 100644 --- a/qpid/cpp/src/qpid/broker/DtxBuffer.h +++ b/qpid/cpp/src/qpid/broker/DtxBuffer.h @@ -21,6 +21,7 @@ #ifndef _DtxBuffer_ #define _DtxBuffer_ +#include "BrokerImportExport.h" #include "TxBuffer.h" #include "qpid/sys/Mutex.h" @@ -37,9 +38,9 @@ namespace qpid { public: typedef boost::shared_ptr<DtxBuffer> shared_ptr; - DtxBuffer(const std::string& xid = ""); - ~DtxBuffer(); - void markEnded(); + QPID_BROKER_EXTERN DtxBuffer(const std::string& xid = ""); + QPID_BROKER_EXTERN ~DtxBuffer(); + QPID_BROKER_EXTERN void markEnded(); bool isEnded(); void setSuspended(bool suspended); bool isSuspended(); diff --git a/qpid/cpp/src/qpid/broker/DtxWorkRecord.h b/qpid/cpp/src/qpid/broker/DtxWorkRecord.h index 6677784c32..21fc759d66 100644 --- a/qpid/cpp/src/qpid/broker/DtxWorkRecord.h +++ b/qpid/cpp/src/qpid/broker/DtxWorkRecord.h @@ -21,6 +21,7 @@ #ifndef _DtxWorkRecord_ #define _DtxWorkRecord_ +#include "BrokerImportExport.h" #include "DtxBuffer.h" #include "DtxTimeout.h" #include "TransactionalStore.h" @@ -61,12 +62,13 @@ class DtxWorkRecord void abort(); bool prepare(TransactionContext* txn); public: - DtxWorkRecord(const std::string& xid, TransactionalStore* const store); - ~DtxWorkRecord(); - bool prepare(); - bool commit(bool onePhase); - void rollback(); - void add(DtxBuffer::shared_ptr ops); + QPID_BROKER_EXTERN DtxWorkRecord(const std::string& xid, + TransactionalStore* const store); + QPID_BROKER_EXTERN ~DtxWorkRecord(); + QPID_BROKER_EXTERN bool prepare(); + QPID_BROKER_EXTERN bool commit(bool onePhase); + QPID_BROKER_EXTERN void rollback(); + QPID_BROKER_EXTERN void add(DtxBuffer::shared_ptr ops); void recover(std::auto_ptr<TPCTransactionContext> txn, DtxBuffer::shared_ptr ops); void timedout(); void setTimeout(boost::intrusive_ptr<DtxTimeout> t) { timeout = t; } diff --git a/qpid/cpp/src/qpid/broker/Exchange.cpp b/qpid/cpp/src/qpid/broker/Exchange.cpp index f8b9e4b183..dd1fe98b2c 100644 --- a/qpid/cpp/src/qpid/broker/Exchange.cpp +++ b/qpid/cpp/src/qpid/broker/Exchange.cpp @@ -102,8 +102,8 @@ static const std::string QPID_MANAGEMENT("qpid.management"); Exchange::Exchange(const string& _name, bool _durable, const qpid::framing::FieldTable& _args, Manageable* parent) - : name(_name), durable(_durable), args(_args), alternateUsers(0), persistenceId(0), - sequence(false), sequenceNo(0), ive(false), mgmtExchange(0) + : name(_name), durable(_durable), alternateUsers(0), persistenceId(0), + args(_args), sequence(false), sequenceNo(0), ive(false), mgmtExchange(0) { if (parent != 0) { @@ -275,3 +275,7 @@ bool Exchange::MatchQueue::operator()(Exchange::Binding::shared_ptr b) { return b->queue == queue; } + +void Exchange::setProperties(const boost::intrusive_ptr<Message>& msg) { + msg->getProperties<DeliveryProperties>()->setExchange(getName()); +} diff --git a/qpid/cpp/src/qpid/broker/Exchange.h b/qpid/cpp/src/qpid/broker/Exchange.h index 488549bbf6..9260222342 100644 --- a/qpid/cpp/src/qpid/broker/Exchange.h +++ b/qpid/cpp/src/qpid/broker/Exchange.h @@ -23,6 +23,7 @@ */ #include <boost/shared_ptr.hpp> +#include "BrokerImportExport.h" #include "Deliverable.h" #include "Queue.h" #include "MessageStore.h" @@ -58,12 +59,12 @@ public: private: const std::string name; const bool durable; - mutable qpid::framing::FieldTable args; boost::shared_ptr<Exchange> alternate; uint32_t alternateUsers; mutable uint64_t persistenceId; protected: + mutable qpid::framing::FieldTable args; bool sequence; mutable qpid::sys::Mutex sequenceLock; int64_t sequenceNo; @@ -123,7 +124,7 @@ public: explicit Exchange(const std::string& name, management::Manageable* parent = 0); Exchange(const std::string& _name, bool _durable, const qpid::framing::FieldTable& _args, management::Manageable* parent = 0); - virtual ~Exchange(); + QPID_BROKER_EXTERN virtual ~Exchange(); const std::string& getName() const { return name; } bool isDurable() { return durable; } @@ -139,15 +140,16 @@ public: virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0; virtual bool unbind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0; virtual bool isBound(Queue::shared_ptr queue, const std::string* const routingKey, const qpid::framing::FieldTable* const args) = 0; + virtual void setProperties(const boost::intrusive_ptr<Message>&); virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0; - + //PersistableExchange: void setPersistenceId(uint64_t id) const; uint64_t getPersistenceId() const { return persistenceId; } uint32_t encodedSize() const; - void encode(framing::Buffer& buffer) const; + QPID_BROKER_EXTERN virtual void encode(framing::Buffer& buffer) const; - static Exchange::shared_ptr decode(ExchangeRegistry& exchanges, framing::Buffer& buffer); + static QPID_BROKER_EXTERN Exchange::shared_ptr decode(ExchangeRegistry& exchanges, framing::Buffer& buffer); // Manageable entry points management::ManagementObject* GetManagementObject(void) const; diff --git a/qpid/cpp/src/qpid/broker/ExchangeRegistry.h b/qpid/cpp/src/qpid/broker/ExchangeRegistry.h index 787b7896f0..9ca432e41c 100644 --- a/qpid/cpp/src/qpid/broker/ExchangeRegistry.h +++ b/qpid/cpp/src/qpid/broker/ExchangeRegistry.h @@ -22,6 +22,7 @@ * */ +#include "BrokerImportExport.h" #include "Exchange.h" #include "MessageStore.h" #include "qpid/framing/FieldTable.h" @@ -45,13 +46,17 @@ class ExchangeRegistry{ bool, const qpid::framing::FieldTable&, qpid::management::Manageable*> FactoryFunction; ExchangeRegistry () : parent(0) {} - std::pair<Exchange::shared_ptr, bool> declare(const std::string& name, const std::string& type) + QPID_BROKER_EXTERN std::pair<Exchange::shared_ptr, bool> declare + (const std::string& name, const std::string& type) throw(UnknownExchangeTypeException); - std::pair<Exchange::shared_ptr, bool> declare(const std::string& name, const std::string& type, - bool durable, const qpid::framing::FieldTable& args = framing::FieldTable()) - throw(UnknownExchangeTypeException); - void destroy(const std::string& name); - Exchange::shared_ptr get(const std::string& name); + QPID_BROKER_EXTERN std::pair<Exchange::shared_ptr, bool> declare + (const std::string& name, + const std::string& type, + bool durable, + const qpid::framing::FieldTable& args = framing::FieldTable()) + throw(UnknownExchangeTypeException); + QPID_BROKER_EXTERN void destroy(const std::string& name); + QPID_BROKER_EXTERN Exchange::shared_ptr get(const std::string& name); Exchange::shared_ptr getDefault(); /** diff --git a/qpid/cpp/src/qpid/broker/ExpiryPolicy.h b/qpid/cpp/src/qpid/broker/ExpiryPolicy.h index 1b7316f6f9..cefe9b7552 100644 --- a/qpid/cpp/src/qpid/broker/ExpiryPolicy.h +++ b/qpid/cpp/src/qpid/broker/ExpiryPolicy.h @@ -23,6 +23,7 @@ */ #include "qpid/RefCounted.h" +#include "BrokerImportExport.h" namespace qpid { namespace broker { @@ -35,9 +36,9 @@ class Message; class ExpiryPolicy : public RefCounted { public: - virtual ~ExpiryPolicy(); - virtual void willExpire(Message&); - virtual bool hasExpired(Message&); + QPID_BROKER_EXTERN virtual ~ExpiryPolicy(); + QPID_BROKER_EXTERN virtual void willExpire(Message&); + QPID_BROKER_EXTERN virtual bool hasExpired(Message&); }; }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/FanOutExchange.h b/qpid/cpp/src/qpid/broker/FanOutExchange.h index 5884a19732..edfc4395f4 100644 --- a/qpid/cpp/src/qpid/broker/FanOutExchange.h +++ b/qpid/cpp/src/qpid/broker/FanOutExchange.h @@ -23,6 +23,7 @@ #include <map> #include <vector> +#include "BrokerImportExport.h" #include "Exchange.h" #include "qpid/framing/FieldTable.h" #include "qpid/sys/CopyOnWriteArray.h" @@ -38,22 +39,30 @@ class FanOutExchange : public virtual Exchange { public: static const std::string typeName; - FanOutExchange(const std::string& name, management::Manageable* parent = 0); - FanOutExchange(const string& _name, bool _durable, - const qpid::framing::FieldTable& _args, - management::Manageable* parent = 0); + QPID_BROKER_EXTERN FanOutExchange(const std::string& name, + management::Manageable* parent = 0); + QPID_BROKER_EXTERN FanOutExchange(const string& _name, + bool _durable, + const qpid::framing::FieldTable& _args, + management::Manageable* parent = 0); virtual std::string getType() const { return typeName; } - virtual bool bind(Queue::shared_ptr queue, const std::string& routingKey, const qpid::framing::FieldTable* args); + QPID_BROKER_EXTERN virtual bool bind(Queue::shared_ptr queue, + const std::string& routingKey, + const qpid::framing::FieldTable* args); 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); + QPID_BROKER_EXTERN virtual void route(Deliverable& msg, + const std::string& routingKey, + const qpid::framing::FieldTable* args); - virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args); + QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue, + const string* const routingKey, + const qpid::framing::FieldTable* const args); - virtual ~FanOutExchange(); + QPID_BROKER_EXTERN virtual ~FanOutExchange(); virtual bool supportsDynamicBinding() { return true; } }; diff --git a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp index 104b34da8b..09fb2d9bef 100644 --- a/qpid/cpp/src/qpid/broker/HeadersExchange.cpp +++ b/qpid/cpp/src/qpid/broker/HeadersExchange.cpp @@ -105,33 +105,42 @@ bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey, void HeadersExchange::route(Deliverable& msg, const string& /*routingKey*/, const FieldTable* args){ - if (!args) return;//can't match if there were no headers passed in + if (!args) { + //can't match if there were no headers passed in + if (mgmtExchange != 0) { + mgmtExchange->inc_msgReceives(); + mgmtExchange->inc_byteReceives(msg.contentSize()); + mgmtExchange->inc_msgDrops(); + mgmtExchange->inc_byteDrops(msg.contentSize()); + } + return; + } + PreRoute pr(msg, this); uint32_t count(0); Bindings::ConstPtr p = bindings.snapshot(); if (p.get()){ - for (std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i, count++) { - if (match((*i)->args, *args)) msg.deliverTo((*i)->queue); - if ((*i)->mgmtBinding != 0) - (*i)->mgmtBinding->inc_msgMatched (); + for (std::vector<Binding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); ++i) { + if (match((*i)->args, *args)) { + msg.deliverTo((*i)->queue); + count++; + if ((*i)->mgmtBinding != 0) + (*i)->mgmtBinding->inc_msgMatched(); + } } } - if (mgmtExchange != 0) - { - mgmtExchange->inc_msgReceives (); - mgmtExchange->inc_byteReceives (msg.contentSize ()); - if (count == 0) - { - mgmtExchange->inc_msgDrops (); - mgmtExchange->inc_byteDrops (msg.contentSize ()); - } - else - { - mgmtExchange->inc_msgRoutes (count); - mgmtExchange->inc_byteRoutes (count * msg.contentSize ()); + if (mgmtExchange != 0) { + mgmtExchange->inc_msgReceives(); + mgmtExchange->inc_byteReceives(msg.contentSize()); + if (count == 0) { + mgmtExchange->inc_msgDrops(); + mgmtExchange->inc_byteDrops(msg.contentSize()); + } else { + mgmtExchange->inc_msgRoutes(count); + mgmtExchange->inc_byteRoutes(count * msg.contentSize()); } } } diff --git a/qpid/cpp/src/qpid/broker/HeadersExchange.h b/qpid/cpp/src/qpid/broker/HeadersExchange.h index e10fab2250..2b01f9ecae 100644 --- a/qpid/cpp/src/qpid/broker/HeadersExchange.h +++ b/qpid/cpp/src/qpid/broker/HeadersExchange.h @@ -22,6 +22,7 @@ #define _HeadersExchange_ #include <vector> +#include "BrokerImportExport.h" #include "Exchange.h" #include "qpid/framing/FieldTable.h" #include "qpid/sys/CopyOnWriteArray.h" @@ -59,24 +60,32 @@ class HeadersExchange : public virtual Exchange { public: static const std::string typeName; - HeadersExchange(const string& name, management::Manageable* parent = 0); - HeadersExchange(const string& _name, bool _durable, - const qpid::framing::FieldTable& _args, - management::Manageable* parent = 0); + QPID_BROKER_EXTERN HeadersExchange(const string& name, + management::Manageable* parent = 0); + QPID_BROKER_EXTERN HeadersExchange(const string& _name, + bool _durable, + const qpid::framing::FieldTable& _args, + management::Manageable* parent = 0); virtual std::string getType() const { return typeName; } - virtual bool bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args); + QPID_BROKER_EXTERN virtual bool bind(Queue::shared_ptr queue, + const string& routingKey, + const qpid::framing::FieldTable* args); virtual bool unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args); - virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args); + QPID_BROKER_EXTERN virtual void route(Deliverable& msg, + const string& routingKey, + const qpid::framing::FieldTable* args); - virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args); + QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue, + const string* const routingKey, + const qpid::framing::FieldTable* const args); - virtual ~HeadersExchange(); + QPID_BROKER_EXTERN virtual ~HeadersExchange(); - static bool match(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs); + static QPID_BROKER_EXTERN bool match(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs); static bool equal(const qpid::framing::FieldTable& bindArgs, const qpid::framing::FieldTable& msgArgs); }; diff --git a/qpid/cpp/src/qpid/broker/IncompleteMessageList.h b/qpid/cpp/src/qpid/broker/IncompleteMessageList.h index f89c0023b0..449194d571 100644 --- a/qpid/cpp/src/qpid/broker/IncompleteMessageList.h +++ b/qpid/cpp/src/qpid/broker/IncompleteMessageList.h @@ -21,6 +21,7 @@ #ifndef _IncompleteMessageList_ #define _IncompleteMessageList_ +#include "BrokerImportExport.h" #include "qpid/sys/Monitor.h" #include "qpid/broker/Message.h" #include <boost/intrusive_ptr.hpp> @@ -43,11 +44,11 @@ class IncompleteMessageList public: typedef Message::MessageCallback CompletionListener; - IncompleteMessageList(); - ~IncompleteMessageList(); + QPID_BROKER_EXTERN IncompleteMessageList(); + QPID_BROKER_EXTERN ~IncompleteMessageList(); - void add(boost::intrusive_ptr<Message> msg); - void process(const CompletionListener& l, bool sync); + QPID_BROKER_EXTERN void add(boost::intrusive_ptr<Message> msg); + QPID_BROKER_EXTERN void process(const CompletionListener& l, bool sync); void each(const CompletionListener& l); }; diff --git a/qpid/cpp/src/qpid/broker/Link.cpp b/qpid/cpp/src/qpid/broker/Link.cpp index e36635831b..dd1a1fa0b4 100644 --- a/qpid/cpp/src/qpid/broker/Link.cpp +++ b/qpid/cpp/src/qpid/broker/Link.cpp @@ -158,7 +158,7 @@ void Link::closed (int, std::string text) } for (Bridges::iterator i = active.begin(); i != active.end(); i++) { - (*i)->cancel(); + (*i)->closed(); created.push_back(*i); } active.clear(); @@ -217,21 +217,27 @@ void Link::add(Bridge::shared_ptr bridge) void Link::cancel(Bridge::shared_ptr bridge) { - Mutex::ScopedLock mutex(lock); - - for (Bridges::iterator i = created.begin(); i != created.end(); i++) { - if ((*i).get() == bridge.get()) { - created.erase(i); - break; + { + Mutex::ScopedLock mutex(lock); + + for (Bridges::iterator i = created.begin(); i != created.end(); i++) { + if ((*i).get() == bridge.get()) { + created.erase(i); + break; + } } - } - for (Bridges::iterator i = active.begin(); i != active.end(); i++) { - if ((*i).get() == bridge.get()) { - bridge->cancel(); - active.erase(i); - break; + for (Bridges::iterator i = active.begin(); i != active.end(); i++) { + if ((*i).get() == bridge.get()) { + cancellations.push_back(bridge); + bridge->closed(); + active.erase(i); + break; + } } } + if (!cancellations.empty()) { + connection->requestIOProcessing (boost::bind(&Link::ioThreadProcessing, this)); + } } void Link::ioThreadProcessing() @@ -242,7 +248,7 @@ void Link::ioThreadProcessing() return; QPID_LOG(debug, "Link::ioThreadProcessing()"); - //process any pending creates + //process any pending creates and/or cancellations if (!created.empty()) { for (Bridges::iterator i = created.begin(); i != created.end(); ++i) { active.push_back(*i); @@ -250,6 +256,13 @@ void Link::ioThreadProcessing() } created.clear(); } + if (!cancellations.empty()) { + for (Bridges::iterator i = cancellations.begin(); i != cancellations.end(); ++i) { + active.push_back(*i); + (*i)->cancel(*connection); + } + cancellations.clear(); + } } void Link::setConnection(Connection* c) @@ -284,7 +297,7 @@ void Link::maintenanceVisit () } } } - else if (state == STATE_OPERATIONAL && !created.empty() && connection != 0) + else if (state == STATE_OPERATIONAL && (!created.empty() || !cancellations.empty()) && connection != 0) connection->requestIOProcessing (boost::bind(&Link::ioThreadProcessing, this)); } diff --git a/qpid/cpp/src/qpid/broker/Link.h b/qpid/cpp/src/qpid/broker/Link.h index 8e741c6eb7..39014b0ec0 100644 --- a/qpid/cpp/src/qpid/broker/Link.h +++ b/qpid/cpp/src/qpid/broker/Link.h @@ -67,6 +67,7 @@ namespace qpid { typedef std::vector<Bridge::shared_ptr> Bridges; Bridges created; // Bridges pending creation Bridges active; // Bridges active + Bridges cancellations; // Bridges pending cancellation uint channelCounter; Connection* connection; management::ManagementAgent* agent; diff --git a/qpid/cpp/src/qpid/broker/LinkRegistry.cpp b/qpid/cpp/src/qpid/broker/LinkRegistry.cpp index 97b1c32d64..7d4ab7548e 100644 --- a/qpid/cpp/src/qpid/broker/LinkRegistry.cpp +++ b/qpid/cpp/src/qpid/broker/LinkRegistry.cpp @@ -19,19 +19,24 @@ * */ #include "LinkRegistry.h" +#include "Connection.h" #include "qpid/log/Statement.h" #include <iostream> +#include <boost/format.hpp> using namespace qpid::broker; using namespace qpid::sys; using std::pair; using std::stringstream; using boost::intrusive_ptr; +using boost::format; +using boost::str; namespace _qmf = qmf::org::apache::qpid::broker; #define LINK_MAINT_INTERVAL 2 -LinkRegistry::LinkRegistry (Broker* _broker) : broker(_broker), parent(0), store(0), passive(false), passiveChanged(false) +LinkRegistry::LinkRegistry (Broker* _broker) : broker(_broker), parent(0), store(0), passive(false), passiveChanged(false), + realm(broker ? broker->getOptions().realm : "") { timer.add (intrusive_ptr<TimerTask> (new Periodic(*this))); } @@ -233,66 +238,70 @@ MessageStore* LinkRegistry::getStore() const { return store; } -void LinkRegistry::notifyConnection(const std::string& key, Connection* c) +Link::shared_ptr LinkRegistry::findLink(const std::string& key) { Mutex::ScopedLock locker(lock); LinkMap::iterator l = links.find(key); - if (l != links.end()) - { - l->second->established(); - l->second->setConnection(c); + if (l != links.end()) return l->second; + else return Link::shared_ptr(); +} + +void LinkRegistry::notifyConnection(const std::string& key, Connection* c) +{ + Link::shared_ptr link = findLink(key); + if (link) { + link->established(); + link->setConnection(c); + c->setUserId(str(format("%1%@%2%") % link->getUsername() % realm)); } } void LinkRegistry::notifyClosed(const std::string& key) { - Mutex::ScopedLock locker(lock); - LinkMap::iterator l = links.find(key); - if (l != links.end()) - l->second->closed(0, "Closed by peer"); + Link::shared_ptr link = findLink(key); + if (link) { + link->closed(0, "Closed by peer"); + } } void LinkRegistry::notifyConnectionForced(const std::string& key, const std::string& text) { - Mutex::ScopedLock locker(lock); - LinkMap::iterator l = links.find(key); - if (l != links.end()) - l->second->notifyConnectionForced(text); + Link::shared_ptr link = findLink(key); + if (link) { + link->notifyConnectionForced(text); + } } std::string LinkRegistry::getAuthMechanism(const std::string& key) { - Mutex::ScopedLock locker(lock); - LinkMap::iterator l = links.find(key); - if (l != links.end()) - return l->second->getAuthMechanism(); + Link::shared_ptr link = findLink(key); + if (link) + return link->getAuthMechanism(); return string("ANONYMOUS"); } std::string LinkRegistry::getAuthCredentials(const std::string& key) { - Mutex::ScopedLock locker(lock); - LinkMap::iterator l = links.find(key); - if (l == links.end()) + Link::shared_ptr link = findLink(key); + if (!link) return string(); string result; result += '\0'; - result += l->second->getUsername(); + result += link->getUsername(); result += '\0'; - result += l->second->getPassword(); + result += link->getPassword(); return result; } std::string LinkRegistry::getAuthIdentity(const std::string& key) { - Mutex::ScopedLock locker(lock); - LinkMap::iterator l = links.find(key); - if (l == links.end()) + Link::shared_ptr link = findLink(key); + if (!link) return string(); - return l->second->getUsername(); + return link->getUsername(); } diff --git a/qpid/cpp/src/qpid/broker/LinkRegistry.h b/qpid/cpp/src/qpid/broker/LinkRegistry.h index 884228bd63..2397dbc6f3 100644 --- a/qpid/cpp/src/qpid/broker/LinkRegistry.h +++ b/qpid/cpp/src/qpid/broker/LinkRegistry.h @@ -66,9 +66,11 @@ namespace broker { MessageStore* store; bool passive; bool passiveChanged; + std::string realm; void periodicMaintenance (); bool updateAddress(const std::string& oldKey, const TcpAddress& newAddress); + Link::shared_ptr findLink(const std::string& key); static std::string createKey(const TcpAddress& address); public: diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp index 133e2b5ad1..40b5515829 100644 --- a/qpid/cpp/src/qpid/broker/Message.cpp +++ b/qpid/cpp/src/qpid/broker/Message.cpp @@ -160,6 +160,7 @@ void Message::decodeContent(framing::Buffer& buffer) //body on a frame then add that frame to the frameset AMQFrame frame((AMQContentBody())); frame.castBody<AMQContentBody>()->decode(buffer, buffer.available()); + frame.setFirstSegment(false); frames.append(frame); } else { //adjust header flags @@ -382,4 +383,9 @@ void Message::resetEnqueueCompleteCallback() { enqueueCallback = 0; } void Message::setDequeueCompleteCallback(MessageCallback& cb) { dequeueCallback = &cb; } void Message::resetDequeueCompleteCallback() { dequeueCallback = 0; } +framing::FieldTable& Message::getOrInsertHeaders() +{ + return getProperties<MessageProperties>()->getApplicationHeaders(); +} + }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h index 96fcf61dfc..458c6c7d1a 100644 --- a/qpid/cpp/src/qpid/broker/Message.h +++ b/qpid/cpp/src/qpid/broker/Message.h @@ -22,6 +22,7 @@ * */ +#include "BrokerImportExport.h" #include "PersistableMessage.h" #include "MessageAdapter.h" #include "qpid/framing/amqp_types.h" @@ -51,8 +52,8 @@ class Message : public PersistableMessage { public: typedef boost::function<void (const boost::intrusive_ptr<Message>&)> MessageCallback; - Message(const framing::SequenceNumber& id = framing::SequenceNumber()); - ~Message(); + QPID_BROKER_EXTERN Message(const framing::SequenceNumber& id = framing::SequenceNumber()); + QPID_BROKER_EXTERN ~Message(); uint64_t getPersistenceId() const { return persistenceId; } void setPersistenceId(uint64_t _persistenceId) const { persistenceId = _persistenceId; } @@ -65,17 +66,18 @@ public: const framing::SequenceNumber& getCommandId() { return frames.getId(); } - uint64_t contentSize() const; + QPID_BROKER_EXTERN uint64_t contentSize() const; - std::string getRoutingKey() const; + QPID_BROKER_EXTERN std::string getRoutingKey() const; const boost::shared_ptr<Exchange> getExchange(ExchangeRegistry&) const; - std::string getExchangeName() const; + QPID_BROKER_EXTERN std::string getExchangeName() const; bool isImmediate() const; - const framing::FieldTable* getApplicationHeaders() const; - bool isPersistent(); + QPID_BROKER_EXTERN const framing::FieldTable* getApplicationHeaders() const; + framing::FieldTable& getOrInsertHeaders(); + QPID_BROKER_EXTERN bool isPersistent(); bool requiresAccept(); - void setTimestamp(const boost::intrusive_ptr<ExpiryPolicy>& e); + QPID_BROKER_EXTERN void setTimestamp(const boost::intrusive_ptr<ExpiryPolicy>& e); void setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e); bool hasExpired(); sys::AbsTime getExpiration() const { return expiration; } @@ -124,8 +126,8 @@ public: uint32_t encodedHeaderSize() const; uint32_t encodedContentSize() const; - void decodeHeader(framing::Buffer& buffer); - void decodeContent(framing::Buffer& buffer); + QPID_BROKER_EXTERN void decodeHeader(framing::Buffer& buffer); + QPID_BROKER_EXTERN void decodeContent(framing::Buffer& buffer); /** * Releases the in-memory content data held by this @@ -139,7 +141,7 @@ public: void sendContent(const Queue& queue, framing::FrameHandler& out, uint16_t maxFrameSize) const; void sendHeader(framing::FrameHandler& out, uint16_t maxFrameSize) const; - bool isContentLoaded() const; + QPID_BROKER_EXTERN bool isContentLoaded() const; bool isExcluded(const std::vector<std::string>& excludes) const; void addTraceId(const std::string& id); diff --git a/qpid/cpp/src/qpid/broker/MessageBuilder.h b/qpid/cpp/src/qpid/broker/MessageBuilder.h index 395de024ab..1f5a2a8b84 100644 --- a/qpid/cpp/src/qpid/broker/MessageBuilder.h +++ b/qpid/cpp/src/qpid/broker/MessageBuilder.h @@ -21,6 +21,7 @@ #ifndef _MessageBuilder_ #define _MessageBuilder_ +#include "BrokerImportExport.h" #include "qpid/framing/FrameHandler.h" #include "qpid/framing/SequenceNumber.h" #include "qpid/RefCounted.h" @@ -34,10 +35,11 @@ namespace qpid { class MessageBuilder : public framing::FrameHandler{ public: - MessageBuilder(MessageStore* const store, uint64_t stagingThreshold); - void handle(framing::AMQFrame& frame); + QPID_BROKER_EXTERN MessageBuilder(MessageStore* const store, + uint64_t stagingThreshold); + QPID_BROKER_EXTERN void handle(framing::AMQFrame& frame); boost::intrusive_ptr<Message> getMessage() { return message; } - void start(const framing::SequenceNumber& id); + QPID_BROKER_EXTERN void start(const framing::SequenceNumber& id); void end(); private: enum State {DORMANT, METHOD, HEADER, CONTENT}; diff --git a/qpid/cpp/src/qpid/broker/NullMessageStore.h b/qpid/cpp/src/qpid/broker/NullMessageStore.h index d99c751d26..a44f8d2804 100644 --- a/qpid/cpp/src/qpid/broker/NullMessageStore.h +++ b/qpid/cpp/src/qpid/broker/NullMessageStore.h @@ -22,6 +22,7 @@ #define _NullMessageStore_ #include <set> +#include "BrokerImportExport.h" #include "MessageStore.h" #include "Queue.h" @@ -38,46 +39,54 @@ class NullMessageStore : public MessageStore std::set<std::string> prepared; uint64_t nextPersistenceId; public: - NullMessageStore(); + QPID_BROKER_EXTERN NullMessageStore(); - virtual bool init(const Options* options); - virtual std::auto_ptr<TransactionContext> begin(); - virtual std::auto_ptr<TPCTransactionContext> begin(const std::string& xid); - virtual void prepare(TPCTransactionContext& txn); - virtual void commit(TransactionContext& txn); - virtual void abort(TransactionContext& txn); - virtual void collectPreparedXids(std::set<std::string>& xids); + QPID_BROKER_EXTERN virtual bool init(const Options* options); + QPID_BROKER_EXTERN virtual std::auto_ptr<TransactionContext> begin(); + QPID_BROKER_EXTERN virtual std::auto_ptr<TPCTransactionContext> begin(const std::string& xid); + QPID_BROKER_EXTERN virtual void prepare(TPCTransactionContext& txn); + QPID_BROKER_EXTERN virtual void commit(TransactionContext& txn); + QPID_BROKER_EXTERN virtual void abort(TransactionContext& txn); + QPID_BROKER_EXTERN virtual void collectPreparedXids(std::set<std::string>& xids); - virtual void create(PersistableQueue& queue, const framing::FieldTable& args); - virtual void destroy(PersistableQueue& queue); - virtual void create(const PersistableExchange& exchange, const framing::FieldTable& args); - virtual void destroy(const PersistableExchange& exchange); + QPID_BROKER_EXTERN virtual void create(PersistableQueue& queue, + const framing::FieldTable& args); + QPID_BROKER_EXTERN virtual void destroy(PersistableQueue& queue); + QPID_BROKER_EXTERN virtual void create(const PersistableExchange& exchange, + const framing::FieldTable& args); + QPID_BROKER_EXTERN virtual void destroy(const PersistableExchange& exchange); - virtual void bind(const PersistableExchange& exchange, const PersistableQueue& queue, - const std::string& key, const framing::FieldTable& args); - virtual void unbind(const PersistableExchange& exchange, const PersistableQueue& queue, - const std::string& key, const framing::FieldTable& args); - virtual void create(const PersistableConfig& config); - virtual void destroy(const PersistableConfig& config); - virtual void recover(RecoveryManager& queues); - virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg); - virtual void destroy(PersistableMessage& msg); - virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg, - const std::string& data); - virtual void loadContent(const qpid::broker::PersistableQueue& queue, - const boost::intrusive_ptr<const PersistableMessage>& msg, std::string& data, - uint64_t offset, uint32_t length); - virtual void enqueue(TransactionContext* ctxt, - const boost::intrusive_ptr<PersistableMessage>& msg, - const PersistableQueue& queue); - virtual void dequeue(TransactionContext* ctxt, - const boost::intrusive_ptr<PersistableMessage>& msg, - const PersistableQueue& queue); - virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue); - virtual void flush(const qpid::broker::PersistableQueue& queue); + QPID_BROKER_EXTERN virtual void bind(const PersistableExchange& exchange, + const PersistableQueue& queue, + const std::string& key, + const framing::FieldTable& args); + QPID_BROKER_EXTERN virtual void unbind(const PersistableExchange& exchange, + const PersistableQueue& queue, + const std::string& key, + const framing::FieldTable& args); + QPID_BROKER_EXTERN virtual void create(const PersistableConfig& config); + QPID_BROKER_EXTERN virtual void destroy(const PersistableConfig& config); + QPID_BROKER_EXTERN virtual void recover(RecoveryManager& queues); + QPID_BROKER_EXTERN virtual void stage(const boost::intrusive_ptr<PersistableMessage>& msg); + QPID_BROKER_EXTERN virtual void destroy(PersistableMessage& msg); + QPID_BROKER_EXTERN virtual void appendContent(const boost::intrusive_ptr<const PersistableMessage>& msg, + const std::string& data); + QPID_BROKER_EXTERN virtual void loadContent(const qpid::broker::PersistableQueue& queue, + const boost::intrusive_ptr<const PersistableMessage>& msg, + std::string& data, + uint64_t offset, + uint32_t length); + QPID_BROKER_EXTERN virtual void enqueue(TransactionContext* ctxt, + const boost::intrusive_ptr<PersistableMessage>& msg, + const PersistableQueue& queue); + QPID_BROKER_EXTERN virtual void dequeue(TransactionContext* ctxt, + const boost::intrusive_ptr<PersistableMessage>& msg, + const PersistableQueue& queue); + QPID_BROKER_EXTERN virtual uint32_t outstandingQueueAIO(const PersistableQueue& queue); + QPID_BROKER_EXTERN virtual void flush(const qpid::broker::PersistableQueue& queue); ~NullMessageStore(){} - virtual bool isNull() const; + QPID_BROKER_EXTERN virtual bool isNull() const; static bool isNullStore(const MessageStore*); }; diff --git a/qpid/cpp/src/qpid/broker/PersistableMessage.h b/qpid/cpp/src/qpid/broker/PersistableMessage.h index 4f2e3abafa..92f89ba578 100644 --- a/qpid/cpp/src/qpid/broker/PersistableMessage.h +++ b/qpid/cpp/src/qpid/broker/PersistableMessage.h @@ -26,6 +26,7 @@ #include <list> #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> +#include "BrokerImportExport.h" #include "Persistable.h" #include "qpid/framing/amqp_types.h" #include "qpid/sys/Mutex.h" @@ -93,21 +94,23 @@ class PersistableMessage : public Persistable bool isContentReleased() const; - bool isEnqueueComplete(); + QPID_BROKER_EXTERN bool isEnqueueComplete(); - void enqueueComplete(); + QPID_BROKER_EXTERN void enqueueComplete(); - void enqueueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store); + QPID_BROKER_EXTERN void enqueueAsync(PersistableQueue::shared_ptr queue, + MessageStore* _store); - void enqueueAsync(); + QPID_BROKER_EXTERN void enqueueAsync(); - bool isDequeueComplete(); + QPID_BROKER_EXTERN bool isDequeueComplete(); - void dequeueComplete(); + QPID_BROKER_EXTERN void dequeueComplete(); - void dequeueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store); + QPID_BROKER_EXTERN void dequeueAsync(PersistableQueue::shared_ptr queue, + MessageStore* _store); - void dequeueAsync(); + QPID_BROKER_EXTERN void dequeueAsync(); }; }} diff --git a/qpid/cpp/src/qpid/broker/Queue.cpp b/qpid/cpp/src/qpid/broker/Queue.cpp index 3ae53c8ea9..aa0cd8ca31 100644 --- a/qpid/cpp/src/qpid/broker/Queue.cpp +++ b/qpid/cpp/src/qpid/broker/Queue.cpp @@ -32,6 +32,7 @@ #include "qpid/log/Statement.h" #include "qpid/management/ManagementBroker.h" #include "qpid/framing/reply_exceptions.h" +#include "qpid/framing/FieldTable.h" #include "qpid/sys/Monitor.h" #include "qpid/sys/Time.h" #include "qmf/org/apache/qpid/broker/ArgsQueuePurge.h" @@ -68,6 +69,9 @@ const std::string qpidLastValueQueueNoBrowse("qpid.last_value_queue_no_browse"); const std::string qpidPersistLastNode("qpid.persist_last_node"); const std::string qpidVQMatchProperty("qpid.LVQ_key"); const std::string qpidQueueEventGeneration("qpid.queue_event_generation"); +//following feature is not ready for general use as it doesn't handle +//the case where a message is enqueued on more than one queue well enough: +const std::string qpidInsertSequenceNumbers("qpid.insert_sequence_numbers"); const int ENQUEUE_ONLY=1; const int ENQUEUE_AND_DEQUEUE=2; @@ -93,7 +97,8 @@ Queue::Queue(const string& _name, bool _autodelete, policyExceeded(false), mgmtObject(0), eventMode(0), - eventMgr(0) + eventMgr(0), + insertSeqNo(0) { if (parent != 0) { @@ -176,7 +181,7 @@ void Queue::deliver(boost::intrusive_ptr<Message>& msg){ void Queue::recover(boost::intrusive_ptr<Message>& msg){ - push(msg); + push(msg, true); msg->enqueueComplete(); // mark the message as enqueued mgntEnqStats(msg); @@ -545,12 +550,13 @@ void Queue::popMsg(QueuedMessage& qmsg) ++dequeueTracker; } -void Queue::push(boost::intrusive_ptr<Message>& msg){ +void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){ QueueListeners::NotificationSet copy; { Mutex::ScopedLock locker(messageLock); QueuedMessage qm(this, msg, ++sequence); if (policy.get()) policy->tryEnqueue(qm); + if (insertSeqNo) msg->getOrInsertHeaders().setInt64(seqNoKey, sequence); LVQ::iterator i; const framing::FieldTable* ft = msg->getApplicationHeaders(); @@ -566,14 +572,21 @@ void Queue::push(boost::intrusive_ptr<Message>& msg){ boost::intrusive_ptr<Message> old = i->second->getReplacementMessage(this); if (!old) old = i->second; i->second->setReplacementMessage(msg,this); - dequeued(QueuedMessage(qm.queue, old, qm.position)); + if (isRecovery) { + //can't issue new requests for the store until + //recovery is complete + pendingDequeues.push_back(QueuedMessage(qm.queue, old, qm.position)); + } else { + dequeue(0, QueuedMessage(qm.queue, old, qm.position)); + } } }else { messages.push_back(qm); listeners.populate(copy); } - if (eventMode && eventMgr) { - eventMgr->enqueued(qm); + if (eventMode) { + if (eventMgr) eventMgr->enqueued(qm); + else QPID_LOG(warning, "Enqueue manager not set, events not generated for " << getName()); } } copy.notify(); @@ -664,7 +677,7 @@ bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg) msg->addTraceId(traceId); } - if (msg->isPersistent() && store && !lastValueQueue) { + if (msg->isPersistent() && store) { msg->enqueueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg); store->enqueue(ctxt, pmsg, *this); @@ -676,14 +689,14 @@ bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg) // return true if store exists, bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg) { - if (policy.get() && !policy->isEnqueued(msg)) return false; { Mutex::ScopedLock locker(messageLock); + if (policy.get() && !policy->isEnqueued(msg)) return false; if (!ctxt) { dequeued(msg); } } - if (msg.payload->isPersistent() && store && !lastValueQueue) { + if (msg.payload->isPersistent() && store) { msg.payload->dequeueAsync(shared_from_this(), store); //increment to async counter -- for message sent to more than one queue boost::intrusive_ptr<PersistableMessage> pmsg = boost::static_pointer_cast<PersistableMessage>(msg.payload); store->dequeue(ctxt, pmsg, *this); @@ -765,6 +778,9 @@ void Queue::configure(const FieldTable& _settings, bool recovering) eventMode = _settings.getAsInt(qpidQueueEventGeneration); + FieldTable::ValuePtr p =_settings.get(qpidInsertSequenceNumbers); + if (p && p->convertsTo<std::string>()) insertSequenceNumbers(p->get<std::string>()); + if (mgmtObject != 0) mgmtObject->set_arguments (_settings); @@ -976,3 +992,17 @@ void Queue::setQueueEventManager(QueueEvents& mgr) { eventMgr = &mgr; } + +void Queue::recoveryComplete() +{ + //process any pending dequeues + for_each(pendingDequeues.begin(), pendingDequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1)); + pendingDequeues.clear(); +} + +void Queue::insertSequenceNumbers(const std::string& key) +{ + seqNoKey = key; + insertSeqNo = !seqNoKey.empty(); + QPID_LOG(debug, "Inserting sequence numbers as " << key); +} diff --git a/qpid/cpp/src/qpid/broker/Queue.h b/qpid/cpp/src/qpid/broker/Queue.h index 14849b3c8e..d1f71581d6 100644 --- a/qpid/cpp/src/qpid/broker/Queue.h +++ b/qpid/cpp/src/qpid/broker/Queue.h @@ -21,6 +21,8 @@ * under the License. * */ + +#include "BrokerImportExport.h" #include "OwnershipToken.h" #include "Consumer.h" #include "Message.h" @@ -85,6 +87,7 @@ namespace qpid { std::vector<std::string> traceExclude; QueueListeners listeners; Messages messages; + Messages pendingDequeues;//used to avoid dequeuing during recovery LVQ lvq; mutable qpid::sys::Mutex consumerLock; mutable qpid::sys::Mutex messageLock; @@ -100,8 +103,10 @@ namespace qpid { RateTracker dequeueTracker; int eventMode; QueueEvents* eventMgr; + bool insertSeqNo; + std::string seqNoKey; - void push(boost::intrusive_ptr<Message>& msg); + void push(boost::intrusive_ptr<Message>& msg, bool isRecovery=false); void setPolicy(std::auto_ptr<QueuePolicy> policy); bool seek(QueuedMessage& msg, Consumer::shared_ptr position); bool getNextMessage(QueuedMessage& msg, Consumer::shared_ptr c); @@ -149,13 +154,14 @@ namespace qpid { typedef std::vector<shared_ptr> vector; - Queue(const string& name, bool autodelete = false, - MessageStore* const store = 0, - const OwnershipToken* const owner = 0, - management::Manageable* parent = 0); - ~Queue(); + QPID_BROKER_EXTERN Queue(const string& name, + bool autodelete = false, + MessageStore* const store = 0, + const OwnershipToken* const owner = 0, + management::Manageable* parent = 0); + QPID_BROKER_EXTERN ~Queue(); - bool dispatch(Consumer::shared_ptr); + QPID_BROKER_EXTERN bool dispatch(Consumer::shared_ptr); /** * Check whether there would be a message available for * dispatch to this consumer. If not, the consumer will be @@ -167,24 +173,28 @@ namespace qpid { void create(const qpid::framing::FieldTable& settings); // "recovering" means we are doing a MessageStore recovery. - void configure(const qpid::framing::FieldTable& settings, bool recovering = false); + QPID_BROKER_EXTERN void configure(const qpid::framing::FieldTable& settings, + bool recovering = false); void destroy(); - void bound(const string& exchange, const string& key, const qpid::framing::FieldTable& args); - void unbind(ExchangeRegistry& exchanges, Queue::shared_ptr shared_ref); + QPID_BROKER_EXTERN void bound(const string& exchange, + const string& key, + const qpid::framing::FieldTable& args); + QPID_BROKER_EXTERN void unbind(ExchangeRegistry& exchanges, + Queue::shared_ptr shared_ref); - bool acquire(const QueuedMessage& msg); + QPID_BROKER_EXTERN bool acquire(const QueuedMessage& msg); bool acquireMessageAt(const qpid::framing::SequenceNumber& position, QueuedMessage& message); /** * Delivers a message to the queue. Will record it as * enqueued if persistent then process it. */ - void deliver(boost::intrusive_ptr<Message>& msg); + QPID_BROKER_EXTERN void deliver(boost::intrusive_ptr<Message>& msg); /** * Dispatches the messages immediately to a consumer if * one is available or stores it for later if not. */ - void process(boost::intrusive_ptr<Message>& msg); + QPID_BROKER_EXTERN void process(boost::intrusive_ptr<Message>& msg); /** * Returns a message to the in-memory queue (due to lack * of acknowledegement from a receiver). If a consumer is @@ -197,17 +207,18 @@ namespace qpid { */ void recover(boost::intrusive_ptr<Message>& msg); - void consume(Consumer::shared_ptr c, bool exclusive = false); - void cancel(Consumer::shared_ptr c); + QPID_BROKER_EXTERN void consume(Consumer::shared_ptr c, + 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 - void purgeExpired(); + QPID_BROKER_EXTERN void purgeExpired(); //move qty # of messages to destination Queue destq uint32_t move(const Queue::shared_ptr destq, uint32_t qty); - uint32_t getMessageCount() const; - uint32_t getConsumerCount() const; + QPID_BROKER_EXTERN uint32_t getMessageCount() const; + QPID_BROKER_EXTERN uint32_t getConsumerCount() const; inline const string& getName() const { return name; } bool isExclusiveOwner(const OwnershipToken* const o) const; void releaseExclusiveOwnership(); @@ -223,8 +234,8 @@ namespace qpid { /** * used to take messages from in memory and flush down to disk. */ - void setLastNodeFailure(); - void clearLastNodeFailure(); + QPID_BROKER_EXTERN void setLastNodeFailure(); + QPID_BROKER_EXTERN void clearLastNodeFailure(); bool enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message> msg); /** @@ -240,7 +251,7 @@ namespace qpid { /** * Gets the next available message */ - QueuedMessage get(); + QPID_BROKER_EXTERN QueuedMessage get(); /** Get the message at position pos */ QueuedMessage find(framing::SequenceNumber pos) const; @@ -290,6 +301,11 @@ namespace qpid { void setPosition(framing::SequenceNumber pos); int getEventMode(); void setQueueEventManager(QueueEvents&); + void insertSequenceNumbers(const std::string& key); + /** + * Notify queue that recovery has completed. + */ + void recoveryComplete(); }; } } diff --git a/qpid/cpp/src/qpid/broker/QueueCleaner.h b/qpid/cpp/src/qpid/broker/QueueCleaner.h index 7903266f5f..007826f33e 100644 --- a/qpid/cpp/src/qpid/broker/QueueCleaner.h +++ b/qpid/cpp/src/qpid/broker/QueueCleaner.h @@ -22,6 +22,7 @@ * */ +#include "BrokerImportExport.h" #include "Timer.h" namespace qpid { @@ -34,8 +35,8 @@ class QueueRegistry; class QueueCleaner { public: - QueueCleaner(QueueRegistry& queues, Timer& timer); - void start(qpid::sys::Duration period); + QPID_BROKER_EXTERN QueueCleaner(QueueRegistry& queues, Timer& timer); + QPID_BROKER_EXTERN void start(qpid::sys::Duration period); private: class Task : public TimerTask { diff --git a/qpid/cpp/src/qpid/broker/QueueEvents.cpp b/qpid/cpp/src/qpid/broker/QueueEvents.cpp index a6517e1bfe..7525e4cb76 100644 --- a/qpid/cpp/src/qpid/broker/QueueEvents.cpp +++ b/qpid/cpp/src/qpid/broker/QueueEvents.cpp @@ -20,12 +20,13 @@ */ #include "QueueEvents.h" #include "qpid/Exception.h" +#include "qpid/log/Statement.h" namespace qpid { namespace broker { QueueEvents::QueueEvents(const boost::shared_ptr<sys::Poller>& poller) : - eventQueue(boost::bind(&QueueEvents::handle, this, _1), poller) + eventQueue(boost::bind(&QueueEvents::handle, this, _1), poller), enabled(true) { eventQueue.start(); } @@ -37,12 +38,12 @@ QueueEvents::~QueueEvents() void QueueEvents::enqueued(const QueuedMessage& m) { - eventQueue.push(Event(ENQUEUE, m)); + if (enabled) eventQueue.push(Event(ENQUEUE, m)); } void QueueEvents::dequeued(const QueuedMessage& m) { - eventQueue.push(Event(DEQUEUE, m)); + if (enabled) eventQueue.push(Event(DEQUEUE, m)); } void QueueEvents::registerListener(const std::string& id, const EventListener& listener) @@ -81,6 +82,18 @@ void QueueEvents::shutdown() if (!eventQueue.empty() && !listeners.empty()) eventQueue.shutdown(); } +void QueueEvents::enable() +{ + enabled = true; + QPID_LOG(debug, "Queue events enabled"); +} + +void QueueEvents::disable() +{ + enabled = false; + QPID_LOG(debug, "Queue events disabled"); +} + QueueEvents::Event::Event(EventType t, const QueuedMessage& m) : type(t), msg(m) {} diff --git a/qpid/cpp/src/qpid/broker/QueueEvents.h b/qpid/cpp/src/qpid/broker/QueueEvents.h index 2ba69e33e6..82abd3d20a 100644 --- a/qpid/cpp/src/qpid/broker/QueueEvents.h +++ b/qpid/cpp/src/qpid/broker/QueueEvents.h @@ -22,6 +22,7 @@ * */ +#include "BrokerImportExport.h" #include "QueuedMessage.h" #include "qpid/sys/Mutex.h" #include "qpid/sys/PollableQueue.h" @@ -48,25 +49,29 @@ class QueueEvents EventType type; QueuedMessage msg; - Event(EventType, const QueuedMessage&); + QPID_BROKER_EXTERN Event(EventType, const QueuedMessage&); }; typedef boost::function<void (Event)> EventListener; - QueueEvents(const boost::shared_ptr<sys::Poller>& poller); - ~QueueEvents(); - void enqueued(const QueuedMessage&); - void dequeued(const QueuedMessage&); - void registerListener(const std::string& id, const EventListener&); - void unregisterListener(const std::string& id); + QPID_BROKER_EXTERN QueueEvents(const boost::shared_ptr<sys::Poller>& poller); + QPID_BROKER_EXTERN ~QueueEvents(); + QPID_BROKER_EXTERN void enqueued(const QueuedMessage&); + QPID_BROKER_EXTERN void dequeued(const QueuedMessage&); + QPID_BROKER_EXTERN void registerListener(const std::string& id, + const EventListener&); + QPID_BROKER_EXTERN void unregisterListener(const std::string& id); + void enable(); + void disable(); //process all outstanding events - void shutdown(); + QPID_BROKER_EXTERN void shutdown(); private: typedef qpid::sys::PollableQueue<Event> EventQueue; typedef std::map<std::string, EventListener> Listeners; EventQueue eventQueue; Listeners listeners; + volatile bool enabled; qpid::sys::Mutex lock;//protect listeners from concurrent access void handle(EventQueue::Queue& e); diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp index 41a6709d27..c59736969f 100644 --- a/qpid/cpp/src/qpid/broker/QueuePolicy.cpp +++ b/qpid/cpp/src/qpid/broker/QueuePolicy.cpp @@ -126,7 +126,7 @@ std::string QueuePolicy::getType(const FieldTable& settings) FieldTable::ValuePtr v = settings.get(typeKey); if (v && v->convertsTo<std::string>()) { std::string t = v->get<std::string>(); - transform(t.begin(), t.end(), t.begin(), tolower); + std::transform(t.begin(), t.end(), t.begin(), tolower); if (t == REJECT || t == FLOW_TO_DISK || t == RING || t == RING_STRICT) return t; } return FLOW_TO_DISK; @@ -197,11 +197,12 @@ void RingQueuePolicy::enqueued(const QueuedMessage& m) void RingQueuePolicy::dequeued(const QueuedMessage& m) { qpid::sys::Mutex::ScopedLock l(lock); - QueuePolicy::dequeued(m); //find and remove m from queue - for (Messages::iterator i = queue.begin(); i != queue.end() && m.position <= i->position; i++) { - if (i->position == m.position) { + for (Messages::iterator i = queue.begin(); i != queue.end(); i++) { + if (i->payload == m.payload) { queue.erase(i); + //now update count and size + QueuePolicy::dequeued(m); break; } } @@ -210,9 +211,11 @@ void RingQueuePolicy::dequeued(const QueuedMessage& m) bool RingQueuePolicy::isEnqueued(const QueuedMessage& m) { qpid::sys::Mutex::ScopedLock l(lock); - //for non-strict ring policy, a message can be dequeued before acked; need to detect this - for (Messages::iterator i = queue.begin(); i != queue.end() && m.position <= i->position; i++) { - if (i->position == m.position) { + //for non-strict ring policy, a message can be replaced (and + //therefore dequeued) before it is accepted or released by + //subscriber; need to detect this + for (Messages::const_iterator i = queue.begin(); i != queue.end(); i++) { + if (i->payload == m.payload) { return true; } } @@ -236,13 +239,10 @@ bool RingQueuePolicy::checkLimit(const QueuedMessage& m) oldest = queue.front(); } if (oldest.queue->acquire(oldest) || !strict) { - qpid::sys::Mutex::ScopedLock l(lock); - if (oldest.position == queue.front().position) { - queue.pop_front(); - QPID_LOG(debug, "Ring policy triggered in queue " - << (m.queue ? m.queue->getName() : std::string("unknown queue")) - << ": removed message " << oldest.position << " to make way for " << m.position); - } + oldest.queue->dequeue(0, oldest); + QPID_LOG(debug, "Ring policy triggered in queue " + << (m.queue ? m.queue->getName() : std::string("unknown queue")) + << ": removed message " << oldest.position << " to make way for " << m.position); return true; } else { QPID_LOG(debug, "Ring policy could not be triggered in queue " diff --git a/qpid/cpp/src/qpid/broker/QueuePolicy.h b/qpid/cpp/src/qpid/broker/QueuePolicy.h index 0e8c15aa0e..45992f87ac 100644 --- a/qpid/cpp/src/qpid/broker/QueuePolicy.h +++ b/qpid/cpp/src/qpid/broker/QueuePolicy.h @@ -24,6 +24,7 @@ #include <deque> #include <iostream> #include <memory> +#include "BrokerImportExport.h" #include "QueuedMessage.h" #include "qpid/framing/FieldTable.h" #include "qpid/sys/AtomicValue.h" @@ -47,20 +48,20 @@ class QueuePolicy static std::string getType(const qpid::framing::FieldTable& settings); public: - static const std::string maxCountKey; - static const std::string maxSizeKey; - static const std::string typeKey; - static const std::string REJECT; - static const std::string FLOW_TO_DISK; - static const std::string RING; - static const std::string RING_STRICT; + static QPID_BROKER_EXTERN const std::string maxCountKey; + static QPID_BROKER_EXTERN const std::string maxSizeKey; + static QPID_BROKER_EXTERN const std::string typeKey; + static QPID_BROKER_EXTERN const std::string REJECT; + static QPID_BROKER_EXTERN const std::string FLOW_TO_DISK; + static QPID_BROKER_EXTERN const std::string RING; + static QPID_BROKER_EXTERN const std::string RING_STRICT; virtual ~QueuePolicy() {} - void tryEnqueue(const QueuedMessage&); + QPID_BROKER_EXTERN void tryEnqueue(const QueuedMessage&); virtual void dequeued(const QueuedMessage&); virtual bool isEnqueued(const QueuedMessage&); virtual bool checkLimit(const QueuedMessage&); - void update(qpid::framing::FieldTable& settings); + QPID_BROKER_EXTERN void update(qpid::framing::FieldTable& settings); uint32_t getMaxCount() const { return maxCount; } uint64_t getMaxSize() const { return maxSize; } void encode(framing::Buffer& buffer) const; @@ -68,10 +69,11 @@ class QueuePolicy uint32_t encodedSize() const; - static std::auto_ptr<QueuePolicy> createQueuePolicy(const qpid::framing::FieldTable& settings); - static std::auto_ptr<QueuePolicy> createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT); + static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(const qpid::framing::FieldTable& settings); + static QPID_BROKER_EXTERN std::auto_ptr<QueuePolicy> createQueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT); static void setDefaultMaxSize(uint64_t); - friend std::ostream& operator<<(std::ostream&, const QueuePolicy&); + friend QPID_BROKER_EXTERN std::ostream& operator<<(std::ostream&, + const QueuePolicy&); protected: QueuePolicy(uint32_t maxCount, uint64_t maxSize, const std::string& type = REJECT); diff --git a/qpid/cpp/src/qpid/broker/QueueRegistry.cpp b/qpid/cpp/src/qpid/broker/QueueRegistry.cpp index 2cb801bf83..d079e543c4 100644 --- a/qpid/cpp/src/qpid/broker/QueueRegistry.cpp +++ b/qpid/cpp/src/qpid/broker/QueueRegistry.cpp @@ -19,6 +19,7 @@ * */ #include "QueueRegistry.h" +#include "QueueEvents.h" #include "qpid/log/Statement.h" #include <sstream> #include <assert.h> @@ -27,7 +28,7 @@ using namespace qpid::broker; using namespace qpid::sys; QueueRegistry::QueueRegistry() : - counter(1), store(0), parent(0), lastNode(false) {} + counter(1), store(0), events(0), parent(0), lastNode(false) {} QueueRegistry::~QueueRegistry(){} @@ -43,7 +44,8 @@ QueueRegistry::declare(const string& declareName, bool durable, if (i == queues.end()) { Queue::shared_ptr queue(new Queue(name, autoDelete, durable ? store : 0, owner, parent)); queues[name] = queue; - if (lastNode) queue->setLastNodeFailure(); + if (lastNode) queue->setLastNodeFailure(); + if (events) queue->setQueueEventManager(*events); return std::pair<Queue::shared_ptr, bool>(queue, true); } else { @@ -105,3 +107,7 @@ void QueueRegistry::updateQueueClusterState(bool _lastNode) lastNode = _lastNode; } +void QueueRegistry::setQueueEvents(QueueEvents* e) +{ + events = e; +} diff --git a/qpid/cpp/src/qpid/broker/QueueRegistry.h b/qpid/cpp/src/qpid/broker/QueueRegistry.h index c53ba668cc..3c02afedc4 100644 --- a/qpid/cpp/src/qpid/broker/QueueRegistry.h +++ b/qpid/cpp/src/qpid/broker/QueueRegistry.h @@ -21,6 +21,7 @@ #ifndef _QueueRegistry_ #define _QueueRegistry_ +#include "BrokerImportExport.h" #include "Queue.h" #include "qpid/sys/Mutex.h" #include "qpid/management/Manageable.h" @@ -31,6 +32,8 @@ namespace qpid { namespace broker { +class QueueEvents; + /** * A registry of queues indexed by queue name. * @@ -38,10 +41,10 @@ namespace broker { * are deleted when and only when they are no longer in use. * */ -class QueueRegistry{ +class QueueRegistry { public: - QueueRegistry(); - ~QueueRegistry(); + QPID_BROKER_EXTERN QueueRegistry(); + QPID_BROKER_EXTERN ~QueueRegistry(); /** * Declare a queue. @@ -49,8 +52,11 @@ class QueueRegistry{ * @return The queue and a boolean flag which is true if the queue * was created by this declare call false if it already existed. */ - std::pair<Queue::shared_ptr, bool> declare(const string& name, bool durable = false, bool autodelete = false, - const OwnershipToken* owner = 0); + QPID_BROKER_EXTERN std::pair<Queue::shared_ptr, bool> declare + (const string& name, + bool durable = false, + bool autodelete = false, + const OwnershipToken* owner = 0); /** * Destroy the named queue. @@ -64,7 +70,7 @@ class QueueRegistry{ * subsequent calls to find or declare with the same name. * */ - void destroy (const string& name); + QPID_BROKER_EXTERN void destroy(const string& name); template <class Test> bool destroyIf(const string& name, Test test) { qpid::sys::RWlock::ScopedWlock locker(lock); @@ -79,13 +85,15 @@ class QueueRegistry{ /** * Find the named queue. Return 0 if not found. */ - Queue::shared_ptr find(const string& name); + QPID_BROKER_EXTERN Queue::shared_ptr find(const string& name); /** * Generate unique queue name. */ string generateName(); + void setQueueEvents(QueueEvents*); + /** * Set the store to use. May only be called once. */ @@ -120,6 +128,7 @@ private: mutable qpid::sys::RWlock lock; int counter; MessageStore* store; + QueueEvents* events; management::Manageable* parent; bool lastNode; //used to set mode on queue declare diff --git a/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp index 8030cf7d0e..5f8b57fa0b 100644 --- a/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp +++ b/qpid/cpp/src/qpid/broker/RecoveryManagerImpl.cpp @@ -149,7 +149,8 @@ RecoverableConfig::shared_ptr RecoveryManagerImpl::recoverConfig(framing::Buffer void RecoveryManagerImpl::recoveryComplete() { - //TODO (finalise binding setup etc) + //notify all queues + queues.eachQueue(boost::bind(&Queue::recoveryComplete, _1)); } bool RecoverableMessageImpl::loadContent(uint64_t available) diff --git a/qpid/cpp/src/qpid/broker/RetryList.h b/qpid/cpp/src/qpid/broker/RetryList.h index 013233ef00..3cdba72ecf 100644 --- a/qpid/cpp/src/qpid/broker/RetryList.h +++ b/qpid/cpp/src/qpid/broker/RetryList.h @@ -22,6 +22,7 @@ * */ +#include "BrokerImportExport.h" #include "qpid/Address.h" #include "qpid/Url.h" @@ -35,9 +36,9 @@ namespace broker { class RetryList { public: - RetryList(); - void reset(const std::vector<Url>& urls); - bool next(TcpAddress& address); + QPID_BROKER_EXTERN RetryList(); + QPID_BROKER_EXTERN void reset(const std::vector<Url>& urls); + QPID_BROKER_EXTERN bool next(TcpAddress& address); private: std::vector<Url> urls; size_t urlIndex; diff --git a/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp b/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp index 736b051945..edc66444ec 100644 --- a/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp +++ b/qpid/cpp/src/qpid/broker/SaslAuthenticator.cpp @@ -141,21 +141,31 @@ NullAuthenticator::~NullAuthenticator() {} void NullAuthenticator::getMechanisms(Array& mechanisms) { mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("ANONYMOUS"))); + mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("PLAIN")));//useful for testing } void NullAuthenticator::start(const string& mechanism, const string& response) { if (mechanism == "PLAIN") { // Old behavior - if (response.size() > 0 && response[0] == (char) 0) { - string temp = response.substr(1); - string::size_type i = temp.find((char)0); - string uid = temp.substr(0, i); - string pwd = temp.substr(i + 1); - i = uid.find_last_of(realm); - if (i == string::npos || i != (uid.size() - 1)) { - uid = str(format("%1%@%2%") % uid % realm); + if (response.size() > 0) { + string uid; + string::size_type i = response.find((char)0); + if (i == 0 && response.size() > 1) { + //no authorization id; use authentication id + i = response.find((char)0, 1); + if (i != string::npos) uid = response.substr(1, i-1); + } else if (i != string::npos) { + //authorization id is first null delimited field + uid = response.substr(0, i); + }//else not a valid SASL PLAIN response, throw error? + if (!uid.empty()) { + //append realm if it has not already been added + i = uid.find(realm); + if (i == string::npos || realm.size() + i < uid.size()) { + uid = str(format("%1%@%2%") % uid % realm); + } + connection.setUserId(uid); } - connection.setUserId(uid); } } else { connection.setUserId("anonymous"); diff --git a/qpid/cpp/src/qpid/broker/SemanticState.cpp b/qpid/cpp/src/qpid/broker/SemanticState.cpp index 4f751e43b7..3c7c6d9afa 100644 --- a/qpid/cpp/src/qpid/broker/SemanticState.cpp +++ b/qpid/cpp/src/qpid/broker/SemanticState.cpp @@ -355,20 +355,12 @@ const std::string nullstring; } void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) { + msg->setTimestamp(getSession().getBroker().getExpiryPolicy()); + std::string exchangeName = msg->getExchangeName(); - //TODO: the following should be hidden behind message (using MessageAdapter or similar) - - if (msg->isA<MessageTransferBody>()) { - // Do not replace the delivery-properties.exchange if it is is already set. - // This is used internally (by the cluster) to force the exchange name on a message. - // The client library ensures this is always empty for messages from normal clients. - if (!msg->hasProperties<DeliveryProperties>() || msg->getProperties<DeliveryProperties>()->getExchange().empty()) - msg->getProperties<DeliveryProperties>()->setExchange(exchangeName); - msg->setTimestamp(getSession().getBroker().getExpiryPolicy()); - } - if (!cacheExchange || cacheExchange->getName() != exchangeName){ + if (!cacheExchange || cacheExchange->getName() != exchangeName) cacheExchange = session.getBroker().getExchanges().get(exchangeName); - } + cacheExchange->setProperties(msg); /* verify the userid if specified: */ std::string id = @@ -516,14 +508,16 @@ void SemanticState::ConsumerImpl::setCreditMode() void SemanticState::ConsumerImpl::addByteCredit(uint32_t value) { if (byteCredit != 0xFFFFFFFF) { - byteCredit += value; + if (value == 0xFFFFFFFF) byteCredit = value; + else byteCredit += value; } } void SemanticState::ConsumerImpl::addMessageCredit(uint32_t value) { if (msgCredit != 0xFFFFFFFF) { - msgCredit += value; + if (value == 0xFFFFFFFF) msgCredit = value; + else msgCredit += value; } } diff --git a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp index ae160fabc7..96c47085f0 100644 --- a/qpid/cpp/src/qpid/broker/SessionAdapter.cpp +++ b/qpid/cpp/src/qpid/broker/SessionAdapter.cpp @@ -362,10 +362,6 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string& getBroker().getExchanges().getDefault()->bind(queue, name, 0); queue->bound(getBroker().getExchanges().getDefault()->getName(), name, arguments); - //if event generation is turned on, pass in a pointer to - //the QueueEvents instance to use - if (queue->getEventMode()) queue->setQueueEventManager(getBroker().getQueueEvents()); - //handle automatic cleanup: if (exclusive) { exclusiveQueues.push_back(queue); diff --git a/qpid/cpp/src/qpid/broker/SessionHandler.cpp b/qpid/cpp/src/qpid/broker/SessionHandler.cpp index 2c4de478f6..442c3eb34b 100644 --- a/qpid/cpp/src/qpid/broker/SessionHandler.cpp +++ b/qpid/cpp/src/qpid/broker/SessionHandler.cpp @@ -34,7 +34,8 @@ using namespace qpid::sys; SessionHandler::SessionHandler(Connection& c, ChannelId ch) : amqp_0_10::SessionHandler(&c.getOutput(), ch), connection(c), - proxy(out) + proxy(out), + clusterOrderProxy(c.getClusterOrderOutput() ? new SetChannelProxy(ch, c.getClusterOrderOutput()) : 0) {} SessionHandler::~SessionHandler() {} @@ -84,11 +85,23 @@ void SessionHandler::readyToSend() { if (session.get()) session->readyToSend(); } -// TODO aconway 2008-05-12: hacky - handle attached for bridge clients. -// We need to integrate the client code so we can run a real client -// in the bridge. -// -void SessionHandler::attached(const std::string& name) { +/** + * Used by inter-broker bridges to set up session id and attach + */ +void SessionHandler::attachAs(const std::string& name) +{ + SessionId id(connection.getUserId(), name); + SessionState::Configuration config = connection.broker.getSessionManager().getSessionConfig(); + session.reset(new SessionState(connection.getBroker(), *this, id, config)); + sendAttach(false); +} + +/** + * TODO: this is a little ugly, fix it; its currently still relied on + * for 'push' bridges + */ +void SessionHandler::attached(const std::string& name) +{ if (session.get()) { amqp_0_10::SessionHandler::attached(name); } else { diff --git a/qpid/cpp/src/qpid/broker/SessionHandler.h b/qpid/cpp/src/qpid/broker/SessionHandler.h index 7449db1560..ffc032f64c 100644 --- a/qpid/cpp/src/qpid/broker/SessionHandler.h +++ b/qpid/cpp/src/qpid/broker/SessionHandler.h @@ -54,10 +54,20 @@ class SessionHandler : public amqp_0_10::SessionHandler { framing::AMQP_ClientProxy& getProxy() { return proxy; } const framing::AMQP_ClientProxy& getProxy() const { return proxy; } + /** + * If commands are sent based on the local time (e.g. in timers), they don't have + * a well-defined ordering across cluster nodes. + * 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; + } + virtual void handleDetach(); - - // Overrides - void attached(const std::string& name); + void attached(const std::string& name);//used by 'pushing' inter-broker bridges + void attachAs(const std::string& name);//used by 'pulling' inter-broker bridges protected: virtual void setState(const std::string& sessionName, bool force); @@ -69,9 +79,16 @@ class SessionHandler : public amqp_0_10::SessionHandler { virtual void readyToSend(); private: + struct SetChannelProxy : public framing::AMQP_ClientProxy { // Proxy that sets the channel. + framing::ChannelHandler setChannel; + SetChannelProxy(uint16_t ch, framing::FrameHandler* out) + : framing::AMQP_ClientProxy(setChannel), setChannel(ch, out) {} + }; + Connection& connection; framing::AMQP_ClientProxy proxy; std::auto_ptr<SessionState> session; + std::auto_ptr<SetChannelProxy> clusterOrderProxy; }; }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/SessionState.cpp b/qpid/cpp/src/qpid/broker/SessionState.cpp index 82ffede3f9..7e5f605753 100644 --- a/qpid/cpp/src/qpid/broker/SessionState.cpp +++ b/qpid/cpp/src/qpid/broker/SessionState.cpp @@ -66,7 +66,7 @@ SessionState::SessionState( uint32_t maxRate = broker.getOptions().maxSessionRate; if (maxRate) { if (handler->getConnection().getClientThrottling()) { - rateFlowcontrol = new RateFlowcontrol(maxRate); + rateFlowcontrol.reset(new RateFlowcontrol(maxRate)); } else { QPID_LOG(warning, getId() << ": Unable to flow control client - client doesn't support"); } @@ -212,11 +212,15 @@ struct ScheduledCreditTask : public TimerTask { void fire() { // This is the best we can currently do to avoid a destruction/fire race if (!isCancelled()) { - if ( !sessionState.processSendCredit(0) ) { - QPID_LOG(warning, sessionState.getId() << ": Reschedule sending credit"); - reset(); - timer.add(this); - } + sessionState.getConnection().requestIOProcessing(boost::bind(&ScheduledCreditTask::sendCredit, this)); + } + } + + void sendCredit() { + if ( !sessionState.processSendCredit(0) ) { + QPID_LOG(warning, sessionState.getId() << ": Reschedule sending credit"); + reset(); + timer.add(this); } } }; @@ -274,7 +278,8 @@ bool SessionState::processSendCredit(uint32_t msgs) if ( msgs > 0 && rateFlowcontrol->flowStopped() ) { QPID_LOG(warning, getId() << ": producer throttling violation"); // TODO: Probably do message.stop("") first time then disconnect - getProxy().getMessage().stop(""); + // See comment on getClusterOrderProxy() in .h file + getClusterOrderProxy().getMessage().stop(""); return true; } AbsTime now = AbsTime::now(); @@ -282,7 +287,7 @@ bool SessionState::processSendCredit(uint32_t msgs) if (mgmtObject) mgmtObject->dec_clientCredit(msgs); if ( sendCredit>0 ) { QPID_LOG(debug, getId() << ": send producer credit " << sendCredit); - getProxy().getMessage().flow("", 0, sendCredit); + getClusterOrderProxy().getMessage().flow("", 0, sendCredit); rateFlowcontrol->sentCredit(now, sendCredit); if (mgmtObject) mgmtObject->inc_clientCredit(sendCredit); return true; @@ -363,8 +368,9 @@ void SessionState::readyToSend() { // Issue initial credit - use a heuristic here issue min of 300 messages or 1 secs worth uint32_t credit = std::min(rateFlowcontrol->getRate(), 300U); QPID_LOG(debug, getId() << ": Issuing producer message credit " << credit); - getProxy().getMessage().setFlowMode("", 0); - getProxy().getMessage().flow("", 0, credit); + // See comment on getClusterOrderProxy() in .h file + getClusterOrderProxy().getMessage().setFlowMode("", 0); + getClusterOrderProxy().getMessage().flow("", 0, credit); rateFlowcontrol->sentCredit(AbsTime::now(), credit); if (mgmtObject) mgmtObject->inc_clientCredit(credit); } @@ -372,4 +378,8 @@ void SessionState::readyToSend() { Broker& SessionState::getBroker() { return broker; } +framing::AMQP_ClientProxy& SessionState::getClusterOrderProxy() { + return handler->getClusterOrderProxy(); +} + }} // namespace qpid::broker diff --git a/qpid/cpp/src/qpid/broker/SessionState.h b/qpid/cpp/src/qpid/broker/SessionState.h index c435a741f8..bdfed87905 100644 --- a/qpid/cpp/src/qpid/broker/SessionState.h +++ b/qpid/cpp/src/qpid/broker/SessionState.h @@ -56,7 +56,7 @@ class Message; class SessionHandler; class SessionManager; class RateFlowcontrol; -class TimerTask; +struct TimerTask; /** * Broker-side session state includes session's handler chains, which @@ -125,6 +125,15 @@ class SessionState : public qpid::SessionState, void sendAcceptAndCompletion(); + /** + * If commands are sent based on the local time (e.g. in timers), they don't have + * a well-defined ordering across cluster nodes. + * 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(); + Broker& broker; SessionHandler* handler; sys::AbsTime expiry; // Used by SessionManager. @@ -138,7 +147,7 @@ class SessionState : public qpid::SessionState, // State used for producer flow control (rate limited) qpid::sys::Mutex rateLock; - RateFlowcontrol* rateFlowcontrol; + boost::scoped_ptr<RateFlowcontrol> rateFlowcontrol; boost::intrusive_ptr<TimerTask> flowControlTimer; friend class SessionManager; diff --git a/qpid/cpp/src/qpid/broker/Timer.h b/qpid/cpp/src/qpid/broker/Timer.h index be4ac9d056..564fec5804 100644 --- a/qpid/cpp/src/qpid/broker/Timer.h +++ b/qpid/cpp/src/qpid/broker/Timer.h @@ -21,6 +21,7 @@ #ifndef _Timer_ #define _Timer_ +#include "BrokerImportExport.h" #include "qpid/sys/Monitor.h" #include "qpid/sys/Thread.h" #include "qpid/sys/Runnable.h" @@ -43,9 +44,9 @@ struct TimerTask : public RefCounted { qpid::sys::AbsTime time; volatile bool cancelled; - TimerTask(qpid::sys::Duration timeout); + QPID_BROKER_EXTERN TimerTask(qpid::sys::Duration timeout); TimerTask(qpid::sys::AbsTime time); - virtual ~TimerTask(); + QPID_BROKER_EXTERN virtual ~TimerTask(); void reset(); void cancel(); bool isCancelled() const; @@ -69,10 +70,10 @@ class Timer : private qpid::sys::Runnable { virtual void run(); public: - Timer(); - virtual ~Timer(); + QPID_BROKER_EXTERN Timer(); + QPID_BROKER_EXTERN virtual ~Timer(); - void add(boost::intrusive_ptr<TimerTask> task); + QPID_BROKER_EXTERN void add(boost::intrusive_ptr<TimerTask> task); void start(); void stop(); diff --git a/qpid/cpp/src/qpid/broker/TopicExchange.h b/qpid/cpp/src/qpid/broker/TopicExchange.h index f3a2e221f7..24bf5f7bca 100644 --- a/qpid/cpp/src/qpid/broker/TopicExchange.h +++ b/qpid/cpp/src/qpid/broker/TopicExchange.h @@ -23,6 +23,7 @@ #include <map> #include <vector> +#include "BrokerImportExport.h" #include "Exchange.h" #include "qpid/framing/FieldTable.h" #include "qpid/sys/Monitor.h" @@ -40,7 +41,7 @@ class Tokens : public std::vector<std::string> { /** Tokenize s, provides automatic conversion of string to Tokens */ Tokens(const std::string& s) { operator=(s); } /** Tokenizing assignment operator s */ - Tokens & operator=(const std::string& s); + QPID_BROKER_EXTERN Tokens & operator=(const std::string& s); void key(std::string& key) const; private: @@ -60,12 +61,12 @@ class TopicPattern : public Tokens // Default copy, assign, dtor are sufficient. TopicPattern(const Tokens& tokens) { operator=(tokens); } TopicPattern(const std::string& str) { operator=(str); } - TopicPattern& operator=(const Tokens&); + QPID_BROKER_EXTERN TopicPattern& operator=(const Tokens&); TopicPattern& operator=(const std::string& str) { return operator=(Tokens(str)); } /** Match a topic */ bool match(const std::string& topic) { return match(Tokens(topic)); } - bool match(const Tokens& topic) const; + QPID_BROKER_EXTERN bool match(const Tokens& topic) const; private: void normalize(); @@ -84,21 +85,30 @@ class TopicExchange : public virtual Exchange { public: static const std::string typeName; - TopicExchange(const string& name, management::Manageable* parent = 0); - TopicExchange(const string& _name, bool _durable, - const qpid::framing::FieldTable& _args, management::Manageable* parent = 0); + QPID_BROKER_EXTERN TopicExchange(const string& name, + management::Manageable* parent = 0); + QPID_BROKER_EXTERN TopicExchange(const string& _name, + bool _durable, + const qpid::framing::FieldTable& _args, + management::Manageable* parent = 0); virtual std::string getType() const { return typeName; } - virtual bool bind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args); + QPID_BROKER_EXTERN virtual bool bind(Queue::shared_ptr queue, + const string& routingKey, + const qpid::framing::FieldTable* args); virtual bool unbind(Queue::shared_ptr queue, const string& routingKey, const qpid::framing::FieldTable* args); - virtual void route(Deliverable& msg, const string& routingKey, const qpid::framing::FieldTable* args); + QPID_BROKER_EXTERN virtual void route(Deliverable& msg, + const string& routingKey, + const qpid::framing::FieldTable* args); - virtual bool isBound(Queue::shared_ptr queue, const string* const routingKey, const qpid::framing::FieldTable* const args); + QPID_BROKER_EXTERN virtual bool isBound(Queue::shared_ptr queue, + const string* const routingKey, + const qpid::framing::FieldTable* const args); - virtual ~TopicExchange(); + QPID_BROKER_EXTERN virtual ~TopicExchange(); virtual bool supportsDynamicBinding() { return true; } }; diff --git a/qpid/cpp/src/qpid/broker/TxAccept.cpp b/qpid/cpp/src/qpid/broker/TxAccept.cpp index c7001e5526..73f365d509 100644 --- a/qpid/cpp/src/qpid/broker/TxAccept.cpp +++ b/qpid/cpp/src/qpid/broker/TxAccept.cpp @@ -50,12 +50,12 @@ void TxAccept::RangeOps::operator()(SequenceNumber start, SequenceNumber end) void TxAccept::RangeOps::prepare(TransactionContext* ctxt) { - for_each(ranges.begin(), ranges.end(), bind(&RangeOp::prepare, _1, ctxt)); + std::for_each(ranges.begin(), ranges.end(), bind(&RangeOp::prepare, _1, ctxt)); } void TxAccept::RangeOps::commit() { - for_each(ranges.begin(), ranges.end(), bind(&RangeOp::commit, _1)); + std::for_each(ranges.begin(), ranges.end(), bind(&RangeOp::commit, _1)); //now remove if isRedundant(): if (!ranges.empty()) { ack_iterator i = ranges.front().range.start; diff --git a/qpid/cpp/src/qpid/broker/TxBuffer.h b/qpid/cpp/src/qpid/broker/TxBuffer.h index aabb5ea0b1..f63a65f115 100644 --- a/qpid/cpp/src/qpid/broker/TxBuffer.h +++ b/qpid/cpp/src/qpid/broker/TxBuffer.h @@ -24,6 +24,7 @@ #include <algorithm> #include <functional> #include <vector> +#include "BrokerImportExport.h" #include "TransactionalStore.h" #include "TxOp.h" @@ -68,7 +69,7 @@ namespace qpid { /** * Adds an operation to the transaction. */ - void enlist(TxOp::shared_ptr op); + QPID_BROKER_EXTERN void enlist(TxOp::shared_ptr op); /** * Requests that all ops are prepared. This should @@ -81,7 +82,7 @@ namespace qpid { * @returns true if all the operations prepared * successfully, false if not. */ - bool prepare(TransactionContext* const ctxt); + QPID_BROKER_EXTERN bool prepare(TransactionContext* const ctxt); /** * Signals that the ops all prepared successfully and can @@ -91,7 +92,7 @@ namespace qpid { * Should only be called after a call to prepare() returns * true. */ - void commit(); + QPID_BROKER_EXTERN void commit(); /** * Signals that all ops can be rolled back. @@ -100,13 +101,13 @@ namespace qpid { * returns true (2pc) or instead of a prepare call * ('server-local') */ - void rollback(); + QPID_BROKER_EXTERN void rollback(); /** * Helper method for managing the process of server local * commit */ - bool commitLocal(TransactionalStore* const store); + QPID_BROKER_EXTERN bool commitLocal(TransactionalStore* const store); // Used by cluster to replicate transaction status. void accept(TxOpConstVisitor& v) const; diff --git a/qpid/cpp/src/qpid/broker/TxPublish.h b/qpid/cpp/src/qpid/broker/TxPublish.h index 1f73cb8767..ebe3b51f3d 100644 --- a/qpid/cpp/src/qpid/broker/TxPublish.h +++ b/qpid/cpp/src/qpid/broker/TxPublish.h @@ -21,6 +21,7 @@ #ifndef _TxPublish_ #define _TxPublish_ +#include "BrokerImportExport.h" #include "Queue.h" #include "Deliverable.h" #include "Message.h" @@ -65,19 +66,19 @@ namespace qpid { std::list<Queue::shared_ptr> queues; public: - TxPublish(boost::intrusive_ptr<Message> msg); - virtual bool prepare(TransactionContext* ctxt) throw(); - virtual void commit() throw(); - virtual void rollback() throw(); + QPID_BROKER_EXTERN TxPublish(boost::intrusive_ptr<Message> msg); + QPID_BROKER_EXTERN virtual bool prepare(TransactionContext* ctxt) throw(); + QPID_BROKER_EXTERN virtual void commit() throw(); + QPID_BROKER_EXTERN virtual void rollback() throw(); virtual Message& getMessage() { return *msg; }; - virtual void deliverTo(const boost::shared_ptr<Queue>& queue); + QPID_BROKER_EXTERN virtual void deliverTo(const boost::shared_ptr<Queue>& queue); virtual ~TxPublish(){} virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); } - uint64_t contentSize(); + QPID_BROKER_EXTERN uint64_t contentSize(); boost::intrusive_ptr<Message> getMessage() const { return msg; } const std::list<Queue::shared_ptr> getQueues() const { return queues; } diff --git a/qpid/cpp/src/qpid/client/ClientImportExport.h b/qpid/cpp/src/qpid/client/ClientImportExport.h new file mode 100644 index 0000000000..0e6e5660d6 --- /dev/null +++ b/qpid/cpp/src/qpid/client/ClientImportExport.h @@ -0,0 +1,33 @@ +#ifndef QPID_CLIENT_IMPORT_EXPORT_H +#define QPID_CLIENT_IMPORT_EXPORT_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. + */ + +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) +#if defined(CLIENT_EXPORT) +#define QPID_CLIENT_EXTERN __declspec(dllexport) +#else +#define QPID_CLIENT_EXTERN __declspec(dllimport) +#endif +#else +#define QPID_CLIENT_EXTERN +#endif + +#endif diff --git a/qpid/cpp/src/qpid/client/Connection.h b/qpid/cpp/src/qpid/client/Connection.h index 03631ef56f..846ac33790 100644 --- a/qpid/cpp/src/qpid/client/Connection.h +++ b/qpid/cpp/src/qpid/client/Connection.h @@ -24,6 +24,7 @@ #include <map> #include <string> #include "qpid/client/Session.h" +#include "qpid/client/ClientImportExport.h" namespace qpid { @@ -58,9 +59,9 @@ class Connection * Creates a connection object, but does not open the connection. * @see open() */ - Connection(); + QPID_CLIENT_EXTERN Connection(); - ~Connection(); + QPID_CLIENT_EXTERN ~Connection(); /** * Opens a connection to a broker. @@ -79,7 +80,7 @@ class Connection * hosts, where implemented(!), provide namespace partitioning * within a single broker). */ - void open(const std::string& host, int port = 5672, + QPID_CLIENT_EXTERN void open(const std::string& host, int port = 5672, const std::string& uid = "guest", const std::string& pwd = "guest", const std::string& virtualhost = "/", uint16_t maxFrameSize=65535); @@ -101,7 +102,7 @@ class Connection * hosts, where implemented(!), provide namespace partitioning * within a single broker). */ - void open(const Url& url, + QPID_CLIENT_EXTERN void open(const Url& url, const std::string& uid = "guest", const std::string& pwd = "guest", const std::string& virtualhost = "/", uint16_t maxFrameSize=65535); @@ -116,14 +117,14 @@ class Connection * @param settings used for any settings not provided by the URL. * Settings provided by the url (e.g. host, port) are ignored. */ - void open(const Url& url, const ConnectionSettings& settings); + QPID_CLIENT_EXTERN void open(const Url& url, const ConnectionSettings& settings); /** * Opens a connection to a broker. * * @param the settings to use (host, port etc). @see ConnectionSettings. */ - void open(const ConnectionSettings& settings); + QPID_CLIENT_EXTERN void open(const ConnectionSettings& settings); /** * Close the connection. @@ -131,7 +132,7 @@ class Connection * Any further use of this connection (without reopening it) will * not succeed. */ - void close(); + QPID_CLIENT_EXTERN void close(); /** * Create a new session on this connection. Sessions allow @@ -174,23 +175,23 @@ class Connection * If the name is empty (the default) then a unique name will be * chosen using a Universally-unique identifier (UUID) algorithm. */ - Session newSession(const std::string& name=std::string(), uint32_t timeoutSeconds = 0); + QPID_CLIENT_EXTERN Session newSession(const std::string& name=std::string(), uint32_t timeoutSeconds = 0); /** * Resume a suspended session. A session may be resumed * on a different connection to the one that created it. */ - void resume(Session& session); + QPID_CLIENT_EXTERN void resume(Session& session); - bool isOpen() const; + QPID_CLIENT_EXTERN bool isOpen() const; - std::vector<Url> getKnownBrokers(); - void registerFailureCallback ( boost::function<void ()> fn ); + QPID_CLIENT_EXTERN std::vector<Url> getKnownBrokers(); + QPID_CLIENT_EXTERN void registerFailureCallback ( boost::function<void ()> fn ); /** * Return the set of client negotiated settings */ - const ConnectionSettings& getNegotiatedSettings(); + QPID_CLIENT_EXTERN const ConnectionSettings& getNegotiatedSettings(); friend class ConnectionAccess; ///<@internal friend class SessionBase_0_10; ///<@internal diff --git a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp index 377b84c019..6efdb91e96 100644 --- a/qpid/cpp/src/qpid/client/ConnectionHandler.cpp +++ b/qpid/cpp/src/qpid/client/ConnectionHandler.cpp @@ -28,6 +28,7 @@ #include "qpid/framing/reply_exceptions.h" #include "qpid/log/Helpers.h" #include "qpid/log/Statement.h" +#include "qpid/sys/SystemInfo.h" using namespace qpid::client; using namespace qpid::framing; @@ -52,6 +53,9 @@ const std::string INVALID_STATE_OPEN_OK("open-ok received in invalid state"); const std::string INVALID_STATE_CLOSE_OK("close-ok received in invalid state"); const std::string SESSION_FLOW_CONTROL("qpid.session_flow"); +const std::string CLIENT_PROCESS_NAME("qpid.client_process"); +const std::string CLIENT_PID("qpid.client_pid"); +const std::string CLIENT_PPID("qpid.client_ppid"); const int SESSION_FLOW_CONTROL_VER = 1; } @@ -80,6 +84,9 @@ ConnectionHandler::ConnectionHandler(const ConnectionSettings& s, ProtocolVersio FINISHED.insert(CLOSED); properties.setInt(SESSION_FLOW_CONTROL, SESSION_FLOW_CONTROL_VER); + properties.setString(CLIENT_PROCESS_NAME, sys::SystemInfo::getProcessName()); + properties.setInt(CLIENT_PID, sys::SystemInfo::getProcessId()); + properties.setInt(CLIENT_PPID, sys::SystemInfo::getParentProcessId()); } void ConnectionHandler::incoming(AMQFrame& frame) diff --git a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp index 8e27d78479..745bdb63b5 100644 --- a/qpid/cpp/src/qpid/client/ConnectionImpl.cpp +++ b/qpid/cpp/src/qpid/client/ConnectionImpl.cpp @@ -180,6 +180,9 @@ void ConnectionImpl::close() template <class F> void ConnectionImpl::closeInternal(const F& f) { + if (heartbeatTask) { + heartbeatTask->cancel(); + } { Mutex::ScopedUnlock u(lock); connector->close(); diff --git a/qpid/cpp/src/qpid/client/ConnectionSettings.h b/qpid/cpp/src/qpid/client/ConnectionSettings.h index f60b11a4ab..71fef219b4 100644 --- a/qpid/cpp/src/qpid/client/ConnectionSettings.h +++ b/qpid/cpp/src/qpid/client/ConnectionSettings.h @@ -25,6 +25,7 @@ #include "qpid/Options.h" #include "qpid/log/Options.h" #include "qpid/Url.h" +#include "qpid/client/ClientImportExport.h" #include <iostream> #include <exception> @@ -42,14 +43,14 @@ namespace client { */ struct ConnectionSettings { - ConnectionSettings(); - virtual ~ConnectionSettings(); + QPID_CLIENT_EXTERN ConnectionSettings(); + QPID_CLIENT_EXTERN virtual ~ConnectionSettings(); /** * Allows socket to be configured; default only sets tcp-nodelay * based on the flag set. Can be overridden. */ - virtual void configureSocket(qpid::sys::Socket&) const; + QPID_CLIENT_EXTERN virtual void configureSocket(qpid::sys::Socket&) const; /** * The protocol used for the connection (defaults to 'tcp') diff --git a/qpid/cpp/src/qpid/client/Connector.cpp b/qpid/cpp/src/qpid/client/Connector.cpp index e6355601df..c251233082 100644 --- a/qpid/cpp/src/qpid/client/Connector.cpp +++ b/qpid/cpp/src/qpid/client/Connector.cpp @@ -92,8 +92,6 @@ class TCPConnector : public Connector, public sys::Codec, private sys::Runnable framing::ProtocolVersion version; bool initiated; - - sys::Mutex closedLock; bool closed; bool joined; @@ -185,7 +183,7 @@ TCPConnector::~TCPConnector() { } void TCPConnector::connect(const std::string& host, int port){ - Mutex::ScopedLock l(closedLock); + Mutex::ScopedLock l(lock); assert(closed); try { socket.connect(host, port); @@ -207,7 +205,7 @@ void TCPConnector::connect(const std::string& host, int port){ } void TCPConnector::init(){ - Mutex::ScopedLock l(closedLock); + Mutex::ScopedLock l(lock); assert(joined); ProtocolInitiation init(version); writeDataBlock(init); @@ -216,17 +214,21 @@ void TCPConnector::init(){ } bool TCPConnector::closeInternal() { - Mutex::ScopedLock l(closedLock); - bool ret = !closed; + bool ret; + { + Mutex::ScopedLock l(lock); + ret = !closed; if (!closed) { closed = true; + aio->queueForDeletion(); poller->shutdown(); } - if (!joined && receiver.id() != Thread::current().id()) { - joined = true; - Mutex::ScopedUnlock u(closedLock); - receiver.join(); + if (joined || receiver.id() == Thread::current().id()) { + return ret; } + joined = true; + } + receiver.join(); return ret; } @@ -259,21 +261,19 @@ const std::string& TCPConnector::getIdentifier() const { } void TCPConnector::send(AMQFrame& frame) { + Mutex::ScopedLock l(lock); + frames.push_back(frame); + //only ask to write if this is the end of a frameset or if we + //already have a buffers worth of data + currentSize += frame.encodedSize(); bool notifyWrite = false; - { - Mutex::ScopedLock l(lock); - frames.push_back(frame); - //only ask to write if this is the end of a frameset or if we - //already have a buffers worth of data - currentSize += frame.encodedSize(); - if (frame.getEof()) { - lastEof = frames.size(); - notifyWrite = true; - } else { - notifyWrite = (currentSize >= maxFrameSize); - } + if (frame.getEof()) { + lastEof = frames.size(); + notifyWrite = true; + } else { + notifyWrite = (currentSize >= maxFrameSize); } - if (notifyWrite) aio->notifyPendingWrite(); + if (notifyWrite && !closed) aio->notifyPendingWrite(); } void TCPConnector::handleClosed() { @@ -384,14 +384,13 @@ void TCPConnector::run() { assert(protect); try { Dispatcher d(poller); - + for (int i = 0; i < 32; i++) { aio->queueReadBuffer(new Buff(maxFrameSize)); } - + aio->start(poller); d.run(); - aio->queueForDeletion(); socket.close(); } catch (const std::exception& e) { QPID_LOG(error, QPID_MSG("FAIL " << identifier << ": " << e.what())); diff --git a/qpid/cpp/src/qpid/client/Dispatcher.cpp b/qpid/cpp/src/qpid/client/Dispatcher.cpp index 27cc4184f9..8d8574520a 100644 --- a/qpid/cpp/src/qpid/client/Dispatcher.cpp +++ b/qpid/cpp/src/qpid/client/Dispatcher.cpp @@ -136,8 +136,7 @@ void Dispatcher::listen(const boost::intrusive_ptr<SubscriptionImpl>& subscripti void Dispatcher::cancel(const std::string& destination) { ScopedLock<Mutex> l(lock); - listeners.erase(destination); - if (autoStop && listeners.empty()) + if (listeners.erase(destination) && running && autoStop && listeners.empty()) queue->close(); } diff --git a/qpid/cpp/src/qpid/client/FailoverManager.cpp b/qpid/cpp/src/qpid/client/FailoverManager.cpp index ab9dbca70f..86b50a0a61 100644 --- a/qpid/cpp/src/qpid/client/FailoverManager.cpp +++ b/qpid/cpp/src/qpid/client/FailoverManager.cpp @@ -21,12 +21,15 @@ #include "FailoverManager.h" #include "qpid/Exception.h" #include "qpid/log/Statement.h" +#include "qpid/sys/Time.h" namespace qpid { namespace client { using qpid::sys::Monitor; +using qpid::sys::AbsTime; +using qpid::sys::Duration; FailoverManager::FailoverManager(const ConnectionSettings& s, ReconnectionStrategy* rs) : settings(s), strategy(rs), state(IDLE) {} @@ -35,15 +38,21 @@ void FailoverManager::execute(Command& c) { bool retry = false; bool completed = false; + AbsTime failed; while (!completed) { try { AsyncSession session = connect().newSession(); + if (retry) { + Duration failoverTime(failed, AbsTime::now()); + QPID_LOG(info, "Failed over for " << &c << " in " << (failoverTime/qpid::sys::TIME_MSEC) << " milliseconds"); + } c.execute(session, retry); session.sync();//TODO: shouldn't be required session.close(); completed = true; } catch(const TransportFailure&) { - retry = true; + retry = true; + failed = AbsTime::now(); } } } diff --git a/qpid/cpp/src/qpid/client/FailoverManager.h b/qpid/cpp/src/qpid/client/FailoverManager.h index 8b6eeda8a1..bef5e18840 100644 --- a/qpid/cpp/src/qpid/client/FailoverManager.h +++ b/qpid/cpp/src/qpid/client/FailoverManager.h @@ -27,6 +27,7 @@ #include "qpid/Exception.h" #include "qpid/client/AsyncSession.h" #include "qpid/sys/Monitor.h" +#include "qpid/client/ClientImportExport.h" #include <vector> namespace qpid { @@ -84,7 +85,7 @@ class FailoverManager * to edit or reorder the list of urls to which reconnection is * attempted */ - FailoverManager(const ConnectionSettings& settings, ReconnectionStrategy* strategy = 0); + QPID_CLIENT_EXTERN FailoverManager(const ConnectionSettings& settings, ReconnectionStrategy* strategy = 0); /** * Return the current connection if open or attept to reconnect to * the specified list of urls. If no list is specified the list of @@ -95,15 +96,15 @@ class FailoverManager * If the full list is tried and all attempts fail, * CannotConnectException is thrown. */ - Connection& connect(std::vector<Url> brokers = std::vector<Url>()); + QPID_CLIENT_EXTERN Connection& connect(std::vector<Url> brokers = std::vector<Url>()); /** * Return the current connection whether open or not */ - Connection& getConnection(); + QPID_CLIENT_EXTERN Connection& getConnection(); /** * Close the current connection */ - void close(); + QPID_CLIENT_EXTERN void close(); /** * Reliably execute the specified command. This involves creating * a session on which to carry out the work of the command, @@ -116,7 +117,7 @@ class FailoverManager * on failover to ensure they continue to use the same logical * connection. */ - void execute(Command&); + QPID_CLIENT_EXTERN void execute(Command&); private: enum State {IDLE, CONNECTING, CANT_CONNECT}; diff --git a/qpid/cpp/src/qpid/client/Future.h b/qpid/cpp/src/qpid/client/Future.h index 67f39cdf3f..ea01522fe8 100644 --- a/qpid/cpp/src/qpid/client/Future.h +++ b/qpid/cpp/src/qpid/client/Future.h @@ -30,6 +30,7 @@ #include "FutureCompletion.h" #include "FutureResult.h" #include "SessionImpl.h" +#include "ClientImportExport.h" namespace qpid { namespace client { @@ -54,9 +55,9 @@ public: } } - void wait(SessionImpl& session); - bool isComplete(SessionImpl& session); - void setFutureResult(boost::shared_ptr<FutureResult> r); + QPID_CLIENT_EXTERN void wait(SessionImpl& session); + QPID_CLIENT_EXTERN bool isComplete(SessionImpl& session); + QPID_CLIENT_EXTERN void setFutureResult(boost::shared_ptr<FutureResult> r); }; }} diff --git a/qpid/cpp/src/qpid/client/FutureResult.h b/qpid/cpp/src/qpid/client/FutureResult.h index e97d80476d..64428c0341 100644 --- a/qpid/cpp/src/qpid/client/FutureResult.h +++ b/qpid/cpp/src/qpid/client/FutureResult.h @@ -23,6 +23,8 @@ #define _FutureResult_ #include <string> + +#include "ClientImportExport.h" #include "qpid/framing/amqp_framing.h" #include "FutureCompletion.h" @@ -36,7 +38,7 @@ class FutureResult : public FutureCompletion { std::string result; public: - const std::string& getResult(SessionImpl& session) const; + QPID_CLIENT_EXTERN const std::string& getResult(SessionImpl& session) const; void received(const std::string& result); }; diff --git a/qpid/cpp/src/qpid/client/Handle.h b/qpid/cpp/src/qpid/client/Handle.h index 4fd82b7646..d8b822d0f9 100644 --- a/qpid/cpp/src/qpid/client/Handle.h +++ b/qpid/cpp/src/qpid/client/Handle.h @@ -22,6 +22,8 @@ * */ +#include "qpid/client/ClientImportExport.h" + namespace qpid { namespace client { @@ -34,23 +36,23 @@ template <class T> class HandlePrivate; */ template <class T> class Handle { public: - ~Handle(); - Handle(const Handle&); - Handle& operator=(const Handle&); + QPID_CLIENT_EXTERN ~Handle(); + QPID_CLIENT_EXTERN Handle(const Handle&); + QPID_CLIENT_EXTERN Handle& operator=(const Handle&); /**@return true if handle is valid, i.e. not null. */ - bool isValid() const { return impl; } + QPID_CLIENT_EXTERN bool isValid() const { return impl; } /**@return true if handle is null. It is an error to call any function on a null handle. */ - bool isNull() const { return !impl; } + QPID_CLIENT_EXTERN bool isNull() const { return !impl; } - operator bool() const { return impl; } - bool operator !() const { return impl; } + QPID_CLIENT_EXTERN operator bool() const { return impl; } + QPID_CLIENT_EXTERN bool operator !() const { return impl; } - void swap(Handle<T>&); + QPID_CLIENT_EXTERN void swap(Handle<T>&); protected: - Handle(T* =0); + QPID_CLIENT_EXTERN Handle(T* =0); T* impl; friend class HandlePrivate<T>; diff --git a/qpid/cpp/src/qpid/client/LocalQueue.h b/qpid/cpp/src/qpid/client/LocalQueue.h index 30ea00612d..5b739d4303 100644 --- a/qpid/cpp/src/qpid/client/LocalQueue.h +++ b/qpid/cpp/src/qpid/client/LocalQueue.h @@ -22,6 +22,7 @@ * */ +#include "ClientImportExport.h" #include "qpid/client/Message.h" #include "qpid/client/Subscription.h" #include "qpid/client/Demux.h" @@ -75,16 +76,16 @@ class LocalQueue { * * LocalQueue is an alternative to implementing a MessageListener. */ - LocalQueue(); + QPID_CLIENT_EXTERN LocalQueue(); - ~LocalQueue(); + QPID_CLIENT_EXTERN ~LocalQueue(); /** Wait up to timeout for the next message from the local queue. *@param result Set to the message from the queue. *@param timeout wait up this timeout for a message to appear. *@return true if result was set, false if queue was empty after timeout. */ - bool get(Message& result, sys::Duration timeout=0); + QPID_CLIENT_EXTERN bool get(Message& result, sys::Duration timeout=0); /** Get the next message off the local queue, or wait up to the timeout * for message from the broker queue. @@ -92,16 +93,16 @@ class LocalQueue { *@return message from the queue. *@throw ClosedException if subscription is closed or timeout exceeded. */ - Message get(sys::Duration timeout=sys::TIME_INFINITE); + QPID_CLIENT_EXTERN Message get(sys::Duration timeout=sys::TIME_INFINITE); /** Synonym for get() */ - Message pop(sys::Duration timeout=sys::TIME_INFINITE); + QPID_CLIENT_EXTERN Message pop(sys::Duration timeout=sys::TIME_INFINITE); /** Return true if local queue is empty. */ - bool empty() const; + QPID_CLIENT_EXTERN bool empty() const; /** Number of messages on the local queue */ - size_t size() const; + QPID_CLIENT_EXTERN size_t size() const; private: Demux::QueuePtr queue; diff --git a/qpid/cpp/src/qpid/client/Message.h b/qpid/cpp/src/qpid/client/Message.h index 3f932efd8b..235e20f97d 100644 --- a/qpid/cpp/src/qpid/client/Message.h +++ b/qpid/cpp/src/qpid/client/Message.h @@ -25,6 +25,7 @@ #include "qpid/client/Session.h" #include "qpid/framing/MessageTransferBody.h" #include "qpid/framing/TransferContent.h" +#include "qpid/client/ClientImportExport.h" namespace qpid { namespace client { @@ -111,7 +112,7 @@ public: *@param data Data for the message body. *@param routingKey Passed to the exchange that routes the message. */ - Message(const std::string& data=std::string(), + QPID_CLIENT_EXTERN Message(const std::string& data=std::string(), const std::string& routingKey=std::string()); /** The destination of messages sent to the broker is the exchange @@ -119,26 +120,26 @@ public: * the delivery tag identifyig the local subscription (often this * is the name of the subscribed queue.) */ - std::string getDestination() const; + QPID_CLIENT_EXTERN std::string getDestination() const; /** Check the redelivered flag. */ - bool isRedelivered() const; + QPID_CLIENT_EXTERN bool isRedelivered() const; /** Set the redelivered flag. */ - void setRedelivered(bool redelivered); + QPID_CLIENT_EXTERN void setRedelivered(bool redelivered); /** Get a modifyable reference to the message headers. */ - framing::FieldTable& getHeaders(); + QPID_CLIENT_EXTERN framing::FieldTable& getHeaders(); /** Get a non-modifyable reference to the message headers. */ - const framing::FieldTable& getHeaders() const; + QPID_CLIENT_EXTERN const framing::FieldTable& getHeaders() const; ///@internal - const framing::MessageTransferBody& getMethod() const; + QPID_CLIENT_EXTERN const framing::MessageTransferBody& getMethod() const; ///@internal - const framing::SequenceNumber& getId() const; + QPID_CLIENT_EXTERN const framing::SequenceNumber& getId() const; /**@internal for incoming messages */ - Message(const framing::FrameSet& frameset); + QPID_CLIENT_EXTERN Message(const framing::FrameSet& frameset); private: //method and id are only set for received messages: diff --git a/qpid/cpp/src/qpid/client/MessageListener.h b/qpid/cpp/src/qpid/client/MessageListener.h index 75aad6521b..b86aa10c54 100644 --- a/qpid/cpp/src/qpid/client/MessageListener.h +++ b/qpid/cpp/src/qpid/client/MessageListener.h @@ -19,6 +19,7 @@ * */ #include <string> +#include "qpid/client/ClientImportExport.h" #ifndef _MessageListener_ #define _MessageListener_ @@ -85,7 +86,7 @@ namespace client { class MessageListener{ public: - virtual ~MessageListener(); + QPID_CLIENT_EXTERN virtual ~MessageListener(); /** Called for each message arriving from the broker. Override * in your own subclass to process messages. diff --git a/qpid/cpp/src/qpid/client/MessageReplayTracker.h b/qpid/cpp/src/qpid/client/MessageReplayTracker.h index 45b16fb704..280cbae4a5 100644 --- a/qpid/cpp/src/qpid/client/MessageReplayTracker.h +++ b/qpid/cpp/src/qpid/client/MessageReplayTracker.h @@ -23,7 +23,7 @@ */ #include "AsyncSession.h" #include "Message.h" - +#include "qpid/client/ClientImportExport.h" #include <list> #include <string> @@ -37,13 +37,13 @@ namespace client { class MessageReplayTracker { public: - MessageReplayTracker(uint flushInterval); - void send(const Message& message, const std::string& destination = ""); - void init(AsyncSession session); - void replay(AsyncSession session); - void setFlushInterval(uint interval); - uint getFlushInterval(); - void checkCompletion(); + QPID_CLIENT_EXTERN MessageReplayTracker(uint flushInterval); + QPID_CLIENT_EXTERN void send(const Message& message, const std::string& destination = ""); + QPID_CLIENT_EXTERN void init(AsyncSession session); + QPID_CLIENT_EXTERN void replay(AsyncSession session); + QPID_CLIENT_EXTERN void setFlushInterval(uint interval); + QPID_CLIENT_EXTERN uint getFlushInterval(); + QPID_CLIENT_EXTERN void checkCompletion(); template <class F> void foreach(F& f) { for (std::list<ReplayRecord>::const_iterator i = buffer.begin(); i != buffer.end(); i++) { diff --git a/qpid/cpp/src/qpid/client/QueueOptions.h b/qpid/cpp/src/qpid/client/QueueOptions.h index d159378198..57d9487217 100644 --- a/qpid/cpp/src/qpid/client/QueueOptions.h +++ b/qpid/cpp/src/qpid/client/QueueOptions.h @@ -18,6 +18,8 @@ * under the License. * */ + +#include "ClientImportExport.h" #include "qpid/framing/FieldTable.h" #ifndef _QueueOptions_ @@ -36,8 +38,8 @@ enum QueueOrderingPolicy {FIFO, LVQ, LVQ_NO_BROWSE}; class QueueOptions: public framing::FieldTable { public: - QueueOptions(); - virtual ~QueueOptions(); + QPID_CLIENT_EXTERN QueueOptions(); + QPID_CLIENT_EXTERN virtual ~QueueOptions(); /** * Sets the queue sizing policy @@ -51,58 +53,58 @@ class QueueOptions: public framing::FieldTable * @param maxSize Set the max number of bytes for the sizing policies * @param setMaxCount Set the max number of messages for the sizing policies */ - void setSizePolicy(QueueSizePolicy sp, uint64_t maxSize, uint32_t maxCount ); + QPID_CLIENT_EXTERN void setSizePolicy(QueueSizePolicy sp, uint64_t maxSize, uint32_t maxCount ); /** * Enables the persisting of a queue to the store module when a cluster fails down to it's last * node. Does so optimistically. Will start persisting when cluster count >1 again. */ - void setPersistLastNode(); + QPID_CLIENT_EXTERN void setPersistLastNode(); /** * Sets the odering policy on the Queue, default ordering is FIFO. */ - void setOrdering(QueueOrderingPolicy op); + QPID_CLIENT_EXTERN void setOrdering(QueueOrderingPolicy op); /** * Use broker defualt sizing ploicy */ - void clearSizePolicy(); + QPID_CLIENT_EXTERN void clearSizePolicy(); /** * Clear Persist Last Node Policy */ - void clearPersistLastNode(); + QPID_CLIENT_EXTERN void clearPersistLastNode(); /** * get the key used match LVQ in args for message transfer */ - void getLVQKey(std::string& key); + QPID_CLIENT_EXTERN void getLVQKey(std::string& key); /** * Use default odering policy */ - void clearOrdering(); + QPID_CLIENT_EXTERN void clearOrdering(); /** * Turns on event generation for this queue (either enqueue only * or for enqueue and dequeue events); the events can then be * processed by a regsitered broker plugin. */ - void enableQueueEvents(bool enqueueOnly); + QPID_CLIENT_EXTERN void enableQueueEvents(bool enqueueOnly); - static const std::string strMaxCountKey; - static const std::string strMaxSizeKey; - static const std::string strTypeKey; - static const std::string strREJECT; - static const std::string strFLOW_TO_DISK; - static const std::string strRING; - static const std::string strRING_STRICT; - static const std::string strLastValueQueue; - static const std::string strPersistLastNode; - static const std::string strLVQMatchProperty; - static const std::string strLastValueQueueNoBrowse; - static const std::string strQueueEventMode; + static QPID_CLIENT_EXTERN const std::string strMaxCountKey; + static QPID_CLIENT_EXTERN const std::string strMaxSizeKey; + static QPID_CLIENT_EXTERN const std::string strTypeKey; + static QPID_CLIENT_EXTERN const std::string strREJECT; + static QPID_CLIENT_EXTERN const std::string strFLOW_TO_DISK; + static QPID_CLIENT_EXTERN const std::string strRING; + static QPID_CLIENT_EXTERN const std::string strRING_STRICT; + static QPID_CLIENT_EXTERN const std::string strLastValueQueue; + static QPID_CLIENT_EXTERN const std::string strPersistLastNode; + static QPID_CLIENT_EXTERN const std::string strLVQMatchProperty; + static QPID_CLIENT_EXTERN const std::string strLastValueQueueNoBrowse; + static QPID_CLIENT_EXTERN const std::string strQueueEventMode; }; } diff --git a/qpid/cpp/src/qpid/client/SessionBase_0_10.h b/qpid/cpp/src/qpid/client/SessionBase_0_10.h index 091c977053..3ae21936f6 100644 --- a/qpid/cpp/src/qpid/client/SessionBase_0_10.h +++ b/qpid/cpp/src/qpid/client/SessionBase_0_10.h @@ -33,6 +33,7 @@ #include "qpid/client/SessionImpl.h" #include "qpid/client/TypedResult.h" #include "qpid/shared_ptr.h" +#include "qpid/client/ClientImportExport.h" #include <string> namespace qpid { @@ -65,19 +66,19 @@ class SessionBase_0_10 { typedef framing::TransferContent DefaultContent; ///@internal - SessionBase_0_10(); - ~SessionBase_0_10(); + QPID_CLIENT_EXTERN SessionBase_0_10(); + QPID_CLIENT_EXTERN ~SessionBase_0_10(); /** Get the next message frame-set from the session. */ - framing::FrameSet::shared_ptr get(); + QPID_CLIENT_EXTERN framing::FrameSet::shared_ptr get(); /** Get the session ID */ - SessionId getId() const; + QPID_CLIENT_EXTERN SessionId getId() const; /** Close the session. * A session is automatically closed when all handles to it are destroyed. */ - void close(); + QPID_CLIENT_EXTERN void close(); /** * Synchronize the session: sync() waits until all commands issued @@ -88,25 +89,25 @@ class SessionBase_0_10 { * AsyncSession::executionSync() directly in the unusual event * that you want to do an asynchronous sync. */ - void sync(); + QPID_CLIENT_EXTERN void sync(); /** Set the timeout for this session. */ - uint32_t timeout(uint32_t seconds); + QPID_CLIENT_EXTERN uint32_t timeout(uint32_t seconds); /** Suspend the session - detach it from its connection */ - void suspend(); + QPID_CLIENT_EXTERN void suspend(); /** Resume a suspended session with a new connection */ - void resume(Connection); + QPID_CLIENT_EXTERN void resume(Connection); /** Get the channel associated with this session */ - uint16_t getChannel() const; + QPID_CLIENT_EXTERN uint16_t getChannel() const; - Execution& getExecution(); - void flush(); - void markCompleted(const framing::SequenceSet& ids, bool notifyPeer); - void markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer); - void sendCompletion(); + QPID_CLIENT_EXTERN Execution& getExecution(); + QPID_CLIENT_EXTERN void flush(); + QPID_CLIENT_EXTERN void markCompleted(const framing::SequenceSet& ids, bool notifyPeer); + QPID_CLIENT_EXTERN void markCompleted(const framing::SequenceNumber& id, bool cumulative, bool notifyPeer); + QPID_CLIENT_EXTERN void sendCompletion(); protected: boost::shared_ptr<SessionImpl> impl; diff --git a/qpid/cpp/src/qpid/client/SessionImpl.cpp b/qpid/cpp/src/qpid/client/SessionImpl.cpp index ee542a9cf8..5df376efa0 100644 --- a/qpid/cpp/src/qpid/client/SessionImpl.cpp +++ b/qpid/cpp/src/qpid/client/SessionImpl.cpp @@ -512,6 +512,7 @@ void SessionImpl::detach(const std::string& _name) if (id.getName() != _name) throw InternalErrorException("Incorrect session name"); setState(DETACHED); QPID_LOG(info, "Session detached by peer: " << id); + proxy.detached(_name, DETACH_CODE_NORMAL); } void SessionImpl::detached(const std::string& _name, uint8_t _code) { @@ -744,7 +745,8 @@ void SessionImpl::assertOpen() const void SessionImpl::handleClosed() { - demux.close(exceptionHolder.empty() ? new ClosedException() : exceptionHolder); + demux.close(exceptionHolder.empty() ? + sys::ExceptionHolder(new ClosedException()) : exceptionHolder); results.close(); } diff --git a/qpid/cpp/src/qpid/client/SslConnector.cpp b/qpid/cpp/src/qpid/client/SslConnector.cpp index 75c3f5677e..a4298dd4ca 100644 --- a/qpid/cpp/src/qpid/client/SslConnector.cpp +++ b/qpid/cpp/src/qpid/client/SslConnector.cpp @@ -221,6 +221,7 @@ bool SslConnector::closeInternal() { bool ret = !closed; if (!closed) { closed = true; + aio->queueForDeletion(); poller->shutdown(); } if (!joined && receiver.id() != Thread::current().id()) { @@ -386,7 +387,6 @@ void SslConnector::run(){ aio->start(poller); d.run(); - aio->queueForDeletion(); socket.close(); } catch (const std::exception& e) { QPID_LOG(error, e.what()); diff --git a/qpid/cpp/src/qpid/client/Subscription.h b/qpid/cpp/src/qpid/client/Subscription.h index 47bb5d42a5..43c6100254 100644 --- a/qpid/cpp/src/qpid/client/Subscription.h +++ b/qpid/cpp/src/qpid/client/Subscription.h @@ -26,6 +26,7 @@ #include "qpid/client/SubscriptionSettings.h" #include "qpid/client/Handle.h" #include "qpid/client/Message.h" +#include "qpid/client/ClientImportExport.h" namespace qpid { namespace client { @@ -39,74 +40,74 @@ class SubscriptionManager; */ class Subscription : public Handle<SubscriptionImpl> { public: - Subscription(SubscriptionImpl* si=0) : Handle<SubscriptionImpl>(si) {} + QPID_CLIENT_EXTERN Subscription(SubscriptionImpl* si=0) : Handle<SubscriptionImpl>(si) {} - /** The name of the subsctription, used as the "destination" for messages from the broker. + /** The name of the subscription, used as the "destination" for messages from the broker. * Usually the same as the queue name but can be set differently. */ - std::string getName() const; + QPID_CLIENT_EXTERN std::string getName() const; /** Name of the queue this subscription subscribes to */ - std::string getQueue() const; + QPID_CLIENT_EXTERN std::string getQueue() const; /** Get the flow control and acknowledgement settings for this subscription */ - const SubscriptionSettings& getSettings() const; + QPID_CLIENT_EXTERN const SubscriptionSettings& getSettings() const; /** Set the flow control parameters */ - void setFlowControl(const FlowControl&); + QPID_CLIENT_EXTERN void setFlowControl(const FlowControl&); /** Automatically acknowledge (acquire and accept) batches of n messages. * You can disable auto-acknowledgement by setting n=0, and use acquire() and accept() * to manually acquire and accept messages. */ - void setAutoAck(unsigned int n); + QPID_CLIENT_EXTERN void setAutoAck(unsigned int n); /** Get the set of ID's for messages received by this subscription but not yet acquired. * This will always be empty if getSettings().acquireMode=ACQUIRE_MODE_PRE_ACQUIRED */ - SequenceSet getUnacquired() const; + QPID_CLIENT_EXTERN SequenceSet getUnacquired() const; /** Get the set of ID's for messages received by this subscription but not yet accepted. */ - SequenceSet getUnaccepted() const; + QPID_CLIENT_EXTERN SequenceSet getUnaccepted() const; /** Acquire messageIds and remove them from the unacquired set. * oAdd them to the unaccepted set if getSettings().acceptMode == ACCEPT_MODE_EXPLICIT. */ - void acquire(const SequenceSet& messageIds); + QPID_CLIENT_EXTERN void acquire(const SequenceSet& messageIds); /** Accept messageIds and remove them from the unaccepted set. *@pre messageIds is a subset of getUnaccepted() */ - void accept(const SequenceSet& messageIds); + QPID_CLIENT_EXTERN void accept(const SequenceSet& messageIds); /** Release messageIds and remove them from the unaccepted set. *@pre messageIds is a subset of getUnaccepted() */ - void release(const SequenceSet& messageIds); + QPID_CLIENT_EXTERN void release(const SequenceSet& messageIds); /* Acquire a single message */ - void acquire(const Message& m) { acquire(SequenceSet(m.getId())); } + QPID_CLIENT_EXTERN void acquire(const Message& m) { acquire(SequenceSet(m.getId())); } /* Accept a single message */ - void accept(const Message& m) { accept(SequenceSet(m.getId())); } + QPID_CLIENT_EXTERN void accept(const Message& m) { accept(SequenceSet(m.getId())); } /* Release a single message */ - void release(const Message& m) { release(SequenceSet(m.getId())); } + QPID_CLIENT_EXTERN void release(const Message& m) { release(SequenceSet(m.getId())); } /** Get the session associated with this subscription */ - Session getSession() const; + QPID_CLIENT_EXTERN Session getSession() const; /** Get the subscription manager associated with this subscription */ - SubscriptionManager& getSubscriptionManager() const; + QPID_CLIENT_EXTERN SubscriptionManager& getSubscriptionManager() const; /** Cancel the subscription. */ - void cancel(); + QPID_CLIENT_EXTERN void cancel(); /** Grant the specified amount of message credit */ - void grantMessageCredit(uint32_t); + QPID_CLIENT_EXTERN void grantMessageCredit(uint32_t); /** Grant the specified amount of byte credit */ - void grantByteCredit(uint32_t); + QPID_CLIENT_EXTERN void grantByteCredit(uint32_t); friend class SubscriptionManager; }; diff --git a/qpid/cpp/src/qpid/client/SubscriptionImpl.h b/qpid/cpp/src/qpid/client/SubscriptionImpl.h index 74fbacb951..e2b970ce05 100644 --- a/qpid/cpp/src/qpid/client/SubscriptionImpl.h +++ b/qpid/cpp/src/qpid/client/SubscriptionImpl.h @@ -30,6 +30,7 @@ #include "qpid/framing/SequenceSet.h" #include "qpid/sys/Mutex.h" #include "qpid/RefCounted.h" +#include "qpid/client/ClientImportExport.h" #include <memory> namespace qpid { @@ -39,62 +40,62 @@ class SubscriptionManager; class SubscriptionImpl : public RefCounted, public MessageListener { public: - SubscriptionImpl(SubscriptionManager&, const std::string& queue, + QPID_CLIENT_EXTERN SubscriptionImpl(SubscriptionManager&, const std::string& queue, const SubscriptionSettings&, const std::string& name, MessageListener* =0); /** The name of the subsctription, used as the "destination" for messages from the broker. * Usually the same as the queue name but can be set differently. */ - std::string getName() const; + QPID_CLIENT_EXTERN std::string getName() const; /** Name of the queue this subscription subscribes to */ - std::string getQueue() const; + QPID_CLIENT_EXTERN std::string getQueue() const; /** Get the flow control and acknowledgement settings for this subscription */ - const SubscriptionSettings& getSettings() const; + QPID_CLIENT_EXTERN const SubscriptionSettings& getSettings() const; /** Set the flow control parameters */ - void setFlowControl(const FlowControl&); + QPID_CLIENT_EXTERN void setFlowControl(const FlowControl&); /** Automatically acknowledge (acquire and accept) batches of n messages. * You can disable auto-acknowledgement by setting n=0, and use acquire() and accept() * to manually acquire and accept messages. */ - void setAutoAck(size_t n); + QPID_CLIENT_EXTERN void setAutoAck(size_t n); /** Get the set of ID's for messages received by this subscription but not yet acquired. * This will always be empty if acquireMode=ACQUIRE_MODE_PRE_ACQUIRED */ - SequenceSet getUnacquired() const; + QPID_CLIENT_EXTERN SequenceSet getUnacquired() const; /** Get the set of ID's for messages acquired by this subscription but not yet accepted. */ - SequenceSet getUnaccepted() const; + QPID_CLIENT_EXTERN SequenceSet getUnaccepted() const; /** Acquire messageIds and remove them from the un-acquired set for the session. */ - void acquire(const SequenceSet& messageIds); + QPID_CLIENT_EXTERN void acquire(const SequenceSet& messageIds); /** Accept messageIds and remove them from the un-accepted set for the session. */ - void accept(const SequenceSet& messageIds); + QPID_CLIENT_EXTERN void accept(const SequenceSet& messageIds); /** Release messageIds and remove them from the un-accepted set for the session. */ - void release(const SequenceSet& messageIds); + QPID_CLIENT_EXTERN void release(const SequenceSet& messageIds); /** Get the session associated with this subscription */ - Session getSession() const; + QPID_CLIENT_EXTERN Session getSession() const; /** Get the subscription manager associated with this subscription */ - SubscriptionManager& getSubscriptionManager() const; + QPID_CLIENT_EXTERN SubscriptionManager& getSubscriptionManager() const; /** Send subscription request and issue appropriate flow control commands. */ - void subscribe(); + QPID_CLIENT_EXTERN void subscribe(); /** Cancel the subscription. */ - void cancel(); + QPID_CLIENT_EXTERN void cancel(); /** Grant specified credit for this subscription **/ - void grantCredit(framing::message::CreditUnit unit, uint32_t value); + QPID_CLIENT_EXTERN void grantCredit(framing::message::CreditUnit unit, uint32_t value); - void received(Message&); + QPID_CLIENT_EXTERN void received(Message&); /** * Set up demux diversion for messages sent to this subscription @@ -104,7 +105,7 @@ class SubscriptionImpl : public RefCounted, public MessageListener { * Cancel any demux diversion that may have been setup for this * subscription */ - void cancelDiversion(); + QPID_CLIENT_EXTERN void cancelDiversion(); private: diff --git a/qpid/cpp/src/qpid/client/SubscriptionManager.h b/qpid/cpp/src/qpid/client/SubscriptionManager.h index 6b45092931..91ad2b6d56 100644 --- a/qpid/cpp/src/qpid/client/SubscriptionManager.h +++ b/qpid/cpp/src/qpid/client/SubscriptionManager.h @@ -30,6 +30,7 @@ #include <qpid/client/LocalQueue.h> #include <qpid/client/Subscription.h> #include <qpid/sys/Runnable.h> +#include <qpid/client/ClientImportExport.h> #include <set> #include <sstream> @@ -97,7 +98,7 @@ class SubscriptionManager : public sys::Runnable { public: /** Create a new SubscriptionManager associated with a session */ - SubscriptionManager(const Session& session); + QPID_CLIENT_EXTERN SubscriptionManager(const Session& session); /** * Subscribe a MessagesListener to receive messages from queue. @@ -110,7 +111,7 @@ class SubscriptionManager : public sys::Runnable *@param settings settings for the subscription. *@param name unique destination name for the subscription, defaults to queue name. */ - Subscription subscribe(MessageListener& listener, + QPID_CLIENT_EXTERN Subscription subscribe(MessageListener& listener, const std::string& queue, const SubscriptionSettings& settings, const std::string& name=std::string()); @@ -125,7 +126,7 @@ class SubscriptionManager : public sys::Runnable *@param name unique destination name for the subscription, defaults to queue name. * If not specified, the queue name is used. */ - Subscription subscribe(LocalQueue& localQueue, + QPID_CLIENT_EXTERN Subscription subscribe(LocalQueue& localQueue, const std::string& queue, const SubscriptionSettings& settings, const std::string& name=std::string()); @@ -141,7 +142,7 @@ class SubscriptionManager : public sys::Runnable *@param name unique destination name for the subscription, defaults to queue name. * If not specified, the queue name is used. */ - Subscription subscribe(MessageListener& listener, + QPID_CLIENT_EXTERN Subscription subscribe(MessageListener& listener, const std::string& queue, const std::string& name=std::string()); @@ -154,7 +155,7 @@ class SubscriptionManager : public sys::Runnable *@param name unique destination name for the subscription, defaults to queue name. * If not specified, the queue name is used. */ - Subscription subscribe(LocalQueue& localQueue, + QPID_CLIENT_EXTERN Subscription subscribe(LocalQueue& localQueue, const std::string& queue, const std::string& name=std::string()); @@ -164,53 +165,53 @@ class SubscriptionManager : public sys::Runnable *@param timeout wait up this timeout for a message to appear. *@return true if result was set, false if no message available after timeout. */ - bool get(Message& result, const std::string& queue, sys::Duration timeout=0); + QPID_CLIENT_EXTERN bool get(Message& result, const std::string& queue, sys::Duration timeout=0); /** Get a single message from a queue. *@param timeout wait up this timeout for a message to appear. *@return message from the queue. *@throw Exception if the timeout is exceeded. */ - Message get(const std::string& queue, sys::Duration timeout=sys::TIME_INFINITE); + QPID_CLIENT_EXTERN Message get(const std::string& queue, sys::Duration timeout=sys::TIME_INFINITE); /** Get a subscription by name. *@throw Exception if not found. */ - Subscription getSubscription(const std::string& name) const; + QPID_CLIENT_EXTERN Subscription getSubscription(const std::string& name) const; /** Cancel a subscription. See also: Subscription.cancel() */ - void cancel(const std::string& name); + QPID_CLIENT_EXTERN void cancel(const std::string& name); /** Deliver messages in the current thread until stop() is called. * Only one thread may be running in a SubscriptionManager at a time. * @see run */ - void run(); + QPID_CLIENT_EXTERN void run(); /** Start a new thread to deliver messages. * Only one thread may be running in a SubscriptionManager at a time. * @see start */ - void start(); + QPID_CLIENT_EXTERN void start(); /** * Wait for the thread started by a call to start() to complete. */ - void wait(); + QPID_CLIENT_EXTERN void wait(); /** If set true, run() will stop when all subscriptions * are cancelled. If false, run will only stop when stop() * is called. True by default. */ - void setAutoStop(bool set=true); + QPID_CLIENT_EXTERN void setAutoStop(bool set=true); /** Stop delivery. Causes run() to return, or the thread started with start() to exit. */ - void stop(); + QPID_CLIENT_EXTERN void stop(); static const uint32_t UNLIMITED=0xFFFFFFFF; /** Set the flow control for a subscription. */ - void setFlowControl(const std::string& name, const FlowControl& flow); + QPID_CLIENT_EXTERN void setFlowControl(const std::string& name, const FlowControl& flow); /** Set the flow control for a subscription. *@param name: name of the subscription. @@ -218,22 +219,22 @@ class SubscriptionManager : public sys::Runnable *@param bytes: byte credit. *@param window: if true use window-based flow control. */ - void setFlowControl(const std::string& name, uint32_t messages, uint32_t bytes, bool window=true); + QPID_CLIENT_EXTERN void setFlowControl(const std::string& name, uint32_t messages, uint32_t bytes, bool window=true); /** Set the default settings for subscribe() calls that don't * include a SubscriptionSettings parameter. */ - void setDefaultSettings(const SubscriptionSettings& s) { defaultSettings = s; } + QPID_CLIENT_EXTERN void setDefaultSettings(const SubscriptionSettings& s) { defaultSettings = s; } /** Get the default settings for subscribe() calls that don't * include a SubscriptionSettings parameter. */ - const SubscriptionSettings& getDefaultSettings() const { return defaultSettings; } + QPID_CLIENT_EXTERN const SubscriptionSettings& getDefaultSettings() const { return defaultSettings; } /** Get the default settings for subscribe() calls that don't * include a SubscriptionSettings parameter. */ - SubscriptionSettings& getDefaultSettings() { return defaultSettings; } + QPID_CLIENT_EXTERN SubscriptionSettings& getDefaultSettings() { return defaultSettings; } /** * Set the default flow control settings for subscribe() calls @@ -243,7 +244,7 @@ class SubscriptionManager : public sys::Runnable *@param bytes: byte credit. *@param window: if true use window-based flow control. */ - void setFlowControl(uint32_t messages, uint32_t bytes, bool window=true) { + QPID_CLIENT_EXTERN void setFlowControl(uint32_t messages, uint32_t bytes, bool window=true) { defaultSettings.flowControl = FlowControl(messages, bytes, window); } @@ -251,16 +252,16 @@ class SubscriptionManager : public sys::Runnable *Set the default accept-mode for subscribe() calls that don't *include a SubscriptionSettings parameter. */ - void setAcceptMode(AcceptMode mode) { defaultSettings.acceptMode = mode; } + QPID_CLIENT_EXTERN void setAcceptMode(AcceptMode mode) { defaultSettings.acceptMode = mode; } /** * Set the default acquire-mode subscribe()s that don't specify SubscriptionSettings. */ - void setAcquireMode(AcquireMode mode) { defaultSettings.acquireMode = mode; } + QPID_CLIENT_EXTERN void setAcquireMode(AcquireMode mode) { defaultSettings.acquireMode = mode; } - void registerFailoverHandler ( boost::function<void ()> fh ); + QPID_CLIENT_EXTERN void registerFailoverHandler ( boost::function<void ()> fh ); - Session getSession() const; + QPID_CLIENT_EXTERN Session getSession() const; private: mutable sys::Mutex lock; diff --git a/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp new file mode 100644 index 0000000000..58956609a4 --- /dev/null +++ b/qpid/cpp/src/qpid/client/windows/SaslFactory.cpp @@ -0,0 +1,139 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/client/SaslFactory.h" +#include "qpid/client/ConnectionSettings.h" + +#include "qpid/Exception.h" +#include "qpid/framing/reply_exceptions.h" +#include "qpid/sys/SecurityLayer.h" +#include "qpid/log/Statement.h" + +#include "boost/tokenizer.hpp" + +namespace qpid { +namespace client { + +using qpid::sys::SecurityLayer; +using qpid::framing::InternalErrorException; + +class WindowsSasl : public Sasl +{ + public: + WindowsSasl(const ConnectionSettings&); + ~WindowsSasl(); + std::string start(const std::string& mechanisms); + std::string step(const std::string& challenge); + std::string getMechanism(); + std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize); + private: + ConnectionSettings settings; + std::string mechanism; +}; + +qpid::sys::Mutex SaslFactory::lock; +std::auto_ptr<SaslFactory> SaslFactory::instance; + +SaslFactory::SaslFactory() +{ +} + +SaslFactory::~SaslFactory() +{ +} + +SaslFactory& SaslFactory::getInstance() +{ + qpid::sys::Mutex::ScopedLock l(lock); + if (!instance.get()) { + instance = std::auto_ptr<SaslFactory>(new SaslFactory()); + } + return *instance; +} + +std::auto_ptr<Sasl> SaslFactory::create(const ConnectionSettings& settings) +{ + std::auto_ptr<Sasl> sasl(new WindowsSasl(settings)); + return sasl; +} + +namespace { + const std::string ANONYMOUS = "ANONYMOUS"; + const std::string PLAIN = "PLAIN"; +} + +WindowsSasl::WindowsSasl(const ConnectionSettings& s) + : settings(s) +{ +} + +WindowsSasl::~WindowsSasl() +{ +} + +std::string WindowsSasl::start(const std::string& mechanisms) +{ + QPID_LOG(debug, "WindowsSasl::start(" << mechanisms << ")"); + + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" "); + bool havePlain = false; + bool haveAnon = false; + tokenizer mechs(mechanisms, sep); + for (tokenizer::iterator mech = mechs.begin(); + mech != mechs.end(); + ++mech) { + if (*mech == ANONYMOUS) + haveAnon = true; + else if (*mech == PLAIN) + havePlain = true; + } + if (!haveAnon && !havePlain) + throw InternalErrorException(QPID_MSG("Sasl error: no common mechanism")); + + std::string resp = ""; + if (havePlain) { + mechanism = PLAIN; + resp = ((char)0) + settings.username + ((char)0) + settings.password; + } + else { + mechanism = ANONYMOUS; + } + return resp; +} + +std::string WindowsSasl::step(const std::string& challenge) +{ + // Shouldn't get this for PLAIN... + throw InternalErrorException(QPID_MSG("Sasl step error")); +} + +std::string WindowsSasl::getMechanism() +{ + return mechanism; +} + +std::auto_ptr<SecurityLayer> WindowsSasl::getSecurityLayer(uint16_t maxFrameSize) +{ + return std::auto_ptr<SecurityLayer>(0); +} + +}} // namespace qpid::client diff --git a/qpid/cpp/src/qpid/cluster/Cluster.cpp b/qpid/cpp/src/qpid/cluster/Cluster.cpp index 6221b0054c..f8e412f1e6 100644 --- a/qpid/cpp/src/qpid/cluster/Cluster.cpp +++ b/qpid/cpp/src/qpid/cluster/Cluster.cpp @@ -21,7 +21,9 @@ #include "Connection.h" #include "UpdateClient.h" #include "FailoverExchange.h" +#include "UpdateExchange.h" +#include "qpid/assert.h" #include "qmf/org/apache/qpid/cluster/ArgsClusterStopClusterNode.h" #include "qmf/org/apache/qpid/cluster/Package.h" #include "qpid/broker/Broker.h" @@ -91,9 +93,10 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) : cpg(*this), name(settings.name), myUrl(settings.url.empty() ? Url() : Url(settings.url)), - myId(cpg.self()), + self(cpg.self()), readMax(settings.readMax), writeEstimate(settings.writeEstimate), + expiryPolicy(new ExpiryPolicy(mcast, self, broker.getTimer())), mcast(cpg, poller, boost::bind(&Cluster::leave, this)), dispatcher(cpg, poller, boost::bind(&Cluster::leave, this)), deliverEventQueue(boost::bind(&Cluster::deliveredEvent, this, _1), @@ -104,15 +107,12 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) : boost::bind(&Cluster::leave, this), "Error delivering frames", poller), - connections(*this), - decoder(boost::bind(&PollableFrameQueue::push, &deliverFrameQueue, _1), connections), - expiryPolicy(new ExpiryPolicy(boost::bind(&Cluster::isLeader, this), mcast, myId, broker.getTimer())), - frameId(0), initialized(false), + decoder(boost::bind(&Cluster::deliverFrame, this, _1)), + discarding(true), state(INIT), lastSize(0), - lastBroker(false), - sequence(0) + lastBroker(false) { mAgent = ManagementAgent::Singleton::getInstance(); if (mAgent != 0){ @@ -122,7 +122,13 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) : mgmtObject->set_status("JOINING"); } + // Failover exchange provides membership updates to clients. failoverExchange.reset(new FailoverExchange(this)); + 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))); + if (settings.quorum) quorum.init(); cpg.join(name); // pump the CPG dispatch manually till we get initialized. @@ -149,21 +155,21 @@ void Cluster::initialize() { // Called in connection thread to insert a client connection. void Cluster::addLocalConnection(const boost::intrusive_ptr<Connection>& c) { - Lock l(lock); - connections.insert(c); + localConnections.insert(c); } // Called in connection thread to insert an updated shadow connection. void Cluster::addShadowConnection(const boost::intrusive_ptr<Connection>& c) { - Lock l(lock); - assert(state <= UPDATEE); // Only during update. - connections.insert(c); + // Safe to use connections here because we're pre-catchup, either + // discarding or stalled, so deliveredFrame is not processing any + // connection events. + assert(discarding); + connections.insert(ConnectionMap::value_type(c->getId(), c)); } +// Called by Connection::deliverClose() in deliverFrameQueue thread. void Cluster::erase(const ConnectionId& id) { - // Called only by Connection::deliverClose in deliver thread, no need to lock. connections.erase(id); - decoder.erase(id); } std::vector<string> Cluster::getIds() const { @@ -193,7 +199,6 @@ void Cluster::leave(Lock&) { if (state != LEFT) { state = LEFT; QPID_LOG(notice, *this << " leaving cluster " << name); - connections.clear(); try { broker.shutdown(); } catch (const std::exception& e) { QPID_LOG(critical, *this << " error during broker shutdown: " << e.what()); @@ -213,52 +218,88 @@ void Cluster::deliver( MemberId from(nodeid, pid); framing::Buffer buf(static_cast<char*>(msg), msg_len); Event e(Event::decodeCopy(from, buf)); - e.setSequence(sequence++); - if (from == myId) // Record self-deliveries for flow control. + if (from == self) // Record self-deliveries for flow control. mcast.selfDeliver(e); - deliver(e); + deliverEvent(e); } -void Cluster::deliver(const Event& e) { - if (state == LEFT) return; - QPID_LATENCY_INIT(e); +void Cluster::deliverEvent(const Event& e) { deliverEventQueue.push(e); } -// Handler for deliverEventQueue +void Cluster::deliverFrame(const EventFrame& e) { + deliverFrameQueue.push(e); +} + +// Handler for deliverEventQueue. +// This thread decodes frames from events. void Cluster::deliveredEvent(const Event& e) { - QPID_LATENCY_RECORD("delivered event queue", e); - Buffer buf(const_cast<char*>(e.getData()), e.getSize()); - if (e.getType() == CONTROL) { - AMQFrame frame; - while (frame.decode(buf)) - deliverFrameQueue.push(EventFrame(e, frame)); + QPID_LOG(trace, *this << " DLVR: " << e); + if (e.isCluster()) { + EventFrame ef(e, e.getFrame()); + // Stop the deliverEventQueue on update offers. + // This preserves the connection decoder fragments for an update. + ClusterUpdateOfferBody* offer = dynamic_cast<ClusterUpdateOfferBody*>(ef.frame.getBody()); + if (offer) + deliverEventQueue.stop(); + deliverFrame(ef); } - else if (e.getType() == DATA) - decoder.decode(e, e.getData()); + else if(!discarding) { + if (e.isControl()) + deliverFrame(EventFrame(e, e.getFrame())); + else + decoder.decode(e, e.getData()); +} + else // Discard connection events if discarding is set. + QPID_LOG(trace, *this << " DROP: " << e); } -// Handler for deliverFrameQueue +// Handler for deliverFrameQueue. +// This thread executes the main logic. void Cluster::deliveredFrame(const EventFrame& e) { Mutex::ScopedLock l(lock); - const_cast<AMQFrame&>(e.frame).setClusterId(frameId++); - QPID_LOG(trace, *this << " DLVR: " << e); - QPID_LATENCY_RECORD("delivered frame queue", e.frame); - if (e.isCluster()) { // Cluster control frame + if (e.isCluster()) { + QPID_LOG(trace, *this << " DLVR: " << e); ClusterDispatcher dispatch(*this, e.connectionId.getMember(), l); if (!framing::invoke(dispatch, *e.frame.getBody()).wasHandled()) throw Exception(QPID_MSG("Invalid cluster control")); } - else { // Connection frame. - if (state <= UPDATEE) { - QPID_LOG(trace, *this << " DROP: " << e); - return; - } - boost::intrusive_ptr<Connection> connection = connections.get(e.connectionId); - if (connection) // Ignore frames to closed local connections. + else if (state >= CATCHUP) { + QPID_LOG(trace, *this << " DLVR: " << e); + ConnectionPtr connection = getConnection(e.connectionId, l); + if (connection) connection->deliveredFrame(e); } - QPID_LATENCY_RECORD("processed", e.frame); + else // Drop connection frames while state < CATCHUP + QPID_LOG(trace, *this << " DROP: " << e); +} + +// Called in deliverFrameQueue thread +ConnectionPtr Cluster::getConnection(const ConnectionId& id, Lock&) { + ConnectionPtr cp; + ConnectionMap::iterator i = connections.find(id); + if (i != connections.end()) + cp = i->second; + else { + if(id.getMember() == self) + cp = localConnections.getErase(id); + else { + // New remote connection, create a shadow. + std::ostringstream mgmtId; + mgmtId << id; + cp = new Connection(*this, shadowOut, mgmtId.str(), id); + } + if (cp) + connections.insert(ConnectionMap::value_type(id, cp)); + } + return cp; +} + +Cluster::ConnectionVector Cluster::getConnections(Lock&) { + ConnectionVector result(connections.size()); + std::transform(connections.begin(), connections.end(), result.begin(), + boost::bind(&ConnectionMap::value_type::second, _1)); + return result; } struct AddrList { @@ -306,42 +347,45 @@ void Cluster::configChange ( std::string addresses; for (cpg_address* p = current; p < current+nCurrent; ++p) addresses.append(MemberId(*p).str()); - deliver(Event::control(ClusterConfigChangeBody(ProtocolVersion(), addresses), myId)); + deliverEvent(Event::control(ClusterConfigChangeBody(ProtocolVersion(), addresses), self)); } void Cluster::setReady(Lock&) { state = READY; if (mgmtObject!=0) mgmtObject->set_status("ACTIVE"); mcast.release(); + broker.getQueueEvents().enable(); } void Cluster::configChange(const MemberId&, const std::string& addresses, Lock& l) { bool memberChange = map.configChange(addresses); if (state == LEFT) return; - if (!map.isAlive(myId)) { // Final config change. + if (!map.isAlive(self)) { // Final config change. leave(l); return; } if (state == INIT) { // First configChange if (map.aliveCount() == 1) { - setClusterId(true); + setClusterId(true, l); + discarding = false; setReady(l); - map = ClusterMap(myId, myUrl, true); + map = ClusterMap(self, myUrl, true); memberUpdate(l); QPID_LOG(notice, *this << " first in cluster"); } else { // Joining established group. state = JOINER; QPID_LOG(info, *this << " joining cluster: " << map); - mcast.mcastControl(ClusterUpdateRequestBody(ProtocolVersion(), myUrl.str()), myId); + mcast.mcastControl(ClusterUpdateRequestBody(ProtocolVersion(), myUrl.str()), self); elders = map.getAlive(); - elders.erase(myId); + elders.erase(self); broker.getLinks().setPassive(true); + broker.getQueueEvents().disable(); } - } - else if (state >= READY && memberChange) { + } + else if (state >= CATCHUP && memberChange) { memberUpdate(l); elders = ClusterMap::intersection(elders, map.getAlive()); if (elders.empty()) { @@ -351,13 +395,11 @@ void Cluster::configChange(const MemberId&, const std::string& addresses, Lock& } } -bool Cluster::isLeader() const { return elders.empty(); } - -void Cluster::tryMakeOffer(const MemberId& id, Lock& ) { +void Cluster::makeOffer(const MemberId& id, Lock& ) { if (state == READY && map.isJoiner(id)) { state = OFFER; QPID_LOG(info, *this << " send update-offer to " << id); - mcast.mcastControl(ClusterUpdateOfferBody(ProtocolVersion(), id, clusterId), myId); + mcast.mcastControl(ClusterUpdateOfferBody(ProtocolVersion(), id, clusterId), self); } } @@ -367,88 +409,89 @@ void Cluster::tryMakeOffer(const MemberId& id, Lock& ) { // callbacks will be invoked. // void Cluster::brokerShutdown() { - if (state != LEFT) { - try { cpg.shutdown(); } - catch (const std::exception& e) { - QPID_LOG(error, *this << " shutting down CPG: " << e.what()); - } + try { cpg.shutdown(); } + catch (const std::exception& e) { + QPID_LOG(error, *this << " shutting down CPG: " << e.what()); } delete this; } void Cluster::updateRequest(const MemberId& id, const std::string& url, Lock& l) { map.updateRequest(id, url); - tryMakeOffer(id, l); + makeOffer(id, l); } void Cluster::ready(const MemberId& id, const std::string& url, Lock& l) { if (map.ready(id, Url(url))) memberUpdate(l); - if (state == CATCHUP && id == myId) { + if (state == CATCHUP && id == self) { setReady(l); QPID_LOG(notice, *this << " caught up, active cluster member"); } } void Cluster::updateOffer(const MemberId& updater, uint64_t updateeInt, const Uuid& uuid, Lock& l) { + // NOTE: deliverEventQueue has been stopped at the update offer by + // deliveredEvent in case an update is required. if (state == LEFT) return; MemberId updatee(updateeInt); boost::optional<Url> url = map.updateOffer(updater, updatee); - if (updater == myId) { + if (updater == self) { assert(state == OFFER); - if (url) { // My offer was first. + if (url) // My offer was first. updateStart(updatee, *url, l); - } else { // Another offer was first. + deliverEventQueue.start(); // Don't need to update setReady(l); QPID_LOG(info, *this << " cancelled update offer to " << updatee); - tryMakeOffer(map.firstJoiner(), l); // Maybe make another offer. + makeOffer(map.firstJoiner(), l); // Maybe make another offer. } } - else if (updatee == myId && url) { + else if (updatee == self && url) { assert(state == JOINER); - setClusterId(uuid); + setClusterId(uuid, l); state = UPDATEE; QPID_LOG(info, *this << " receiving update from " << updater); - deliverFrameQueue.stop(); checkUpdateIn(l); } + else + deliverEventQueue.start(); // Don't need to update } -void Cluster::updateStart(const MemberId& updatee, const Url& url, Lock&) { +void Cluster::updateStart(const MemberId& updatee, const Url& url, Lock& l) { + // NOTE: deliverEventQueue is already stopped at the stall point by deliveredEvent. if (state == LEFT) return; assert(state == OFFER); state = UPDATER; - QPID_LOG(info, *this << " stall for update to " << updatee << " at " << url); - deliverFrameQueue.stop(); - if (updateThread.id()) updateThread.join(); // Join the previous updatethread. + QPID_LOG(info, *this << " sending update to " << updatee << " at " << url); + if (updateThread.id()) + updateThread.join(); // Join the previous updateThread to avoid leaks. client::ConnectionSettings cs; cs.username = settings.username; cs.password = settings.password; cs.mechanism = settings.mechanism; updateThread = Thread( - new UpdateClient(myId, updatee, url, broker, map, frameId, connections.values(), + new UpdateClient(self, updatee, url, broker, map, *expiryPolicy, getConnections(l), decoder, boost::bind(&Cluster::updateOutDone, this), boost::bind(&Cluster::updateOutError, this, _1), cs)); } // Called in update thread. -void Cluster::updateInDone(const ClusterMap& m, uint64_t fid) { +void Cluster::updateInDone(const ClusterMap& m) { Lock l(lock); updatedMap = m; - frameId = fid; checkUpdateIn(l); } -void Cluster::checkUpdateIn(Lock& ) { - if (state == LEFT) return; +void Cluster::checkUpdateIn(Lock&) { if (state == UPDATEE && updatedMap) { map = *updatedMap; - mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), myId); + mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), self); state = CATCHUP; + discarding = false; // ok to set, we're stalled for update. QPID_LOG(info, *this << " received update, starting catch-up"); - deliverFrameQueue.start(); + deliverEventQueue.start(); } } @@ -462,8 +505,8 @@ void Cluster::updateOutDone(Lock& l) { assert(state == UPDATER); state = READY; mcast.release(); - deliverFrameQueue.start(); - tryMakeOffer(map.firstJoiner(), l); // Try another offer + deliverEventQueue.start(); // Start processing events again. + makeOffer(map.firstJoiner(), l); // Try another offer } void Cluster::updateOutError(const std::exception& e) { @@ -487,7 +530,7 @@ Manageable::status_t Cluster::ManagementMethod (uint32_t methodId, Args& args, s { _qmf::ArgsClusterStopClusterNode& iargs = (_qmf::ArgsClusterStopClusterNode&) args; stringstream stream; - stream << myId; + stream << self; if (iargs.i_brokerId == stream.str()) stopClusterNode(l); } @@ -508,7 +551,7 @@ void Cluster::stopClusterNode(Lock& l) { void Cluster::stopFullCluster(Lock& ) { QPID_LOG(notice, *this << " shutting down cluster " << name); - mcast.mcastControl(ClusterShutdownBody(), myId); + mcast.mcastControl(ClusterShutdownBody(), self); } void Cluster::memberUpdate(Lock& l) { @@ -518,13 +561,13 @@ void Cluster::memberUpdate(Lock& l) { size_t size = urls.size(); failoverExchange->setUrls(urls); - if (size == 1 && lastSize > 1 && state >= READY) { - QPID_LOG(info, *this << " last broker standing, update queue policies"); + if (size == 1 && lastSize > 1 && state >= CATCHUP) { + QPID_LOG(notice, *this << " last broker standing, update queue policies"); lastBroker = true; broker.getQueues().updateQueueClusterState(true); } else if (size > 1 && lastBroker) { - QPID_LOG(info, *this << " last broker standing joined by " << size-1 << " replicas, updating queue policies" << size); + QPID_LOG(notice, *this << " last broker standing joined by " << size-1 << " replicas, updating queue policies" << size); lastBroker = false; broker.getQueues().updateQueueClusterState(false); } @@ -546,17 +589,23 @@ void Cluster::memberUpdate(Lock& l) { mgmtObject->set_memberIDs(idstr); } - // Close connections belonging to members that have now been excluded - connections.update(myId, map); + // Erase connections belonging to members that have left the cluster. + ConnectionMap::iterator i = connections.begin(); + while (i != connections.end()) { + ConnectionMap::iterator j = i++; + MemberId m = j->second->getId().getMember(); + if (m != self && !map.isMember(m)) + connections.erase(j); + } } std::ostream& operator<<(std::ostream& o, const Cluster& cluster) { static const char* STATE[] = { "INIT", "JOINER", "UPDATEE", "CATCHUP", "READY", "OFFER", "UPDATER", "LEFT" }; - return o << cluster.myId << "(" << STATE[cluster.state] << ")"; + return o << cluster.self << "(" << STATE[cluster.state] << ")"; } MemberId Cluster::getId() const { - return myId; // Immutable, no need to lock. + return self; // Immutable, no need to lock. } broker::Broker& Cluster::getBroker() const { @@ -571,11 +620,11 @@ void Cluster::checkQuorum() { } } -void Cluster::setClusterId(const Uuid& uuid) { +void Cluster::setClusterId(const Uuid& uuid, Lock&) { clusterId = uuid; if (mgmtObject) { stringstream stream; - stream << myId; + stream << self; mgmtObject->set_clusterID(clusterId.str()); mgmtObject->set_memberID(stream.str()); } diff --git a/qpid/cpp/src/qpid/cluster/Cluster.h b/qpid/cpp/src/qpid/cluster/Cluster.h index 8c5eb06ff7..b716e2d781 100644 --- a/qpid/cpp/src/qpid/cluster/Cluster.h +++ b/qpid/cpp/src/qpid/cluster/Cluster.h @@ -19,34 +19,34 @@ * */ -#include "ClusterSettings.h" #include "ClusterMap.h" -#include "ConnectionMap.h" +#include "ClusterSettings.h" #include "Cpg.h" +#include "Decoder.h" #include "Event.h" +#include "EventFrame.h" +#include "ExpiryPolicy.h" #include "FailoverExchange.h" +#include "LockedConnectionMap.h" #include "Multicaster.h" -#include "EventFrame.h" #include "NoOpConnectionOutputHandler.h" +#include "PollableQueue.h" #include "PollerDispatch.h" #include "Quorum.h" -#include "Decoder.h" -#include "PollableQueue.h" -#include "ExpiryPolicy.h" +#include "qmf/org/apache/qpid/cluster/Cluster.h" +#include "qpid/Url.h" #include "qpid/broker/Broker.h" -#include "qpid/sys/Monitor.h" #include "qpid/management/Manageable.h" -#include "qpid/Url.h" -#include "qmf/org/apache/qpid/cluster/Cluster.h" +#include "qpid/sys/Monitor.h" -#include <boost/intrusive_ptr.hpp> #include <boost/bind.hpp> +#include <boost/intrusive_ptr.hpp> #include <boost/optional.hpp> #include <algorithm> -#include <vector> #include <map> +#include <vector> namespace qpid { @@ -58,6 +58,7 @@ class Uuid; namespace cluster { class Connection; +class EventFrame; /** * Connection to the cluster @@ -65,82 +66,91 @@ class Connection; class Cluster : private Cpg::Handler, public management::Manageable { public: typedef boost::intrusive_ptr<Connection> ConnectionPtr; - typedef std::vector<ConnectionPtr> Connections; + typedef std::vector<ConnectionPtr> ConnectionVector; - /** Construct the cluster in plugin earlyInitialize */ + // Public functions are thread safe unless otherwise mentioned in a comment. + + // Construct the cluster in plugin earlyInitialize. Cluster(const ClusterSettings&, broker::Broker&); virtual ~Cluster(); - /** Join the cluster in plugin initialize. Requires transport - * plugins to be available.. */ + // Called by plugin initialize: cluster start-up requires transport plugins . + // Thread safety: only called by plugin initialize. void initialize(); - // Connection map - called in connection threads. + // Connection map. void addLocalConnection(const ConnectionPtr&); void addShadowConnection(const ConnectionPtr&); void erase(const ConnectionId&); - // URLs of current cluster members - called in connection threads. + // URLs of current cluster members. std::vector<std::string> getIds() const; std::vector<Url> getUrls() const; boost::shared_ptr<FailoverExchange> getFailoverExchange() const { return failoverExchange; } - // Leave the cluster - called in any thread. + // Leave the cluster - called when fatal errors occur. void leave(); // Update completed - called in update thread - void updateInDone(const ClusterMap&, uint64_t frameId); + void updateInDone(const ClusterMap&); MemberId getId() const; broker::Broker& getBroker() const; Multicaster& getMulticast() { return mcast; } - boost::function<bool ()> isQuorate; - void checkQuorum(); // called in connection threads. + void checkQuorum(); size_t getReadMax() { return readMax; } size_t getWriteEstimate() { return writeEstimate; } - bool isLeader() const; // Called in deliver thread. + void deliverFrame(const EventFrame&); + + // Called only during update by Connection::shadowReady + Decoder& getDecoder() { return decoder; } + + ExpiryPolicy& getExpiryPolicy() { return *expiryPolicy; } private: typedef sys::Monitor::ScopedLock Lock; typedef PollableQueue<Event> PollableEventQueue; typedef PollableQueue<EventFrame> PollableFrameQueue; + typedef std::map<ConnectionId, ConnectionPtr> ConnectionMap; - // NB: The final Lock& parameter on functions below is used to mark functions - // that should only be called by a function that already holds the lock. - // The parameter makes it hard to forget since you have to have an instance of - // a Lock to call the unlocked functions. - + // NB: A dummy Lock& parameter marks functions that must only be + // called with Cluster::lock locked. + void leave(Lock&); std::vector<std::string> getIds(Lock&) const; std::vector<Url> getUrls(Lock&) const; - // Make an offer if we can - called in deliver thread. - void tryMakeOffer(const MemberId&, Lock&); - - // Called in main thread in ~Broker. + // == Called in main thread from Broker destructor. void brokerShutdown(); + // == Called in deliverEventQueue thread + void deliveredEvent(const Event&); + + // == Called in deliverFrameQueue thread + void deliveredFrame(const EventFrame&); + // Cluster controls implement XML methods from cluster.xml. - // Called in deliver thread. - // void updateRequest(const MemberId&, const std::string&, Lock&); void updateOffer(const MemberId& updater, uint64_t updatee, const framing::Uuid&, Lock&); void ready(const MemberId&, const std::string&, Lock&); void configChange(const MemberId&, const std::string& addresses, Lock& l); void messageExpired(const MemberId&, uint64_t, Lock& l); void shutdown(const MemberId&, Lock&); - void deliveredEvent(const Event&); - void deliveredFrame(const EventFrame&); - // Helper, called in deliver thread. + // Helper functions + ConnectionPtr getConnection(const ConnectionId&, Lock&); + ConnectionVector getConnections(Lock&); void updateStart(const MemberId& updatee, const Url& url, Lock&); - + void makeOffer(const MemberId&, Lock&); void setReady(Lock&); + void memberUpdate(Lock&); + void setClusterId(const framing::Uuid&, Lock&); + // == Called in CPG dispatch thread void deliver( // CPG deliver callback. cpg_handle_t /*handle*/, struct cpg_name *group, @@ -149,7 +159,7 @@ class Cluster : private Cpg::Handler, public management::Manageable { void* /*msg*/, int /*msg_len*/); - void deliver(const Event&); + void deliverEvent(const Event&); void configChange( // CPG config change callback. cpg_handle_t /*handle*/, @@ -159,23 +169,21 @@ class Cluster : private Cpg::Handler, public management::Manageable { struct cpg_address */*joined*/, int /*nJoined*/ ); + // == Called in management threads. virtual qpid::management::ManagementObject* GetManagementObject() const; virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text); void stopClusterNode(Lock&); void stopFullCluster(Lock&); - void memberUpdate(Lock&); - // Called in connection IO threads . + // == Called in connection IO threads . void checkUpdateIn(Lock&); - // Called in UpdateClient thread. + // == Called in UpdateClient thread. void updateOutDone(); void updateOutError(const std::exception&); void updateOutDone(Lock&); - void setClusterId(const framing::Uuid&); - // Immutable members set on construction, never changed. ClusterSettings settings; broker::Broker& broker; @@ -184,34 +192,38 @@ class Cluster : private Cpg::Handler, public management::Manageable { Cpg cpg; const std::string name; Url myUrl; - const MemberId myId; + const MemberId self; const size_t readMax; const size_t writeEstimate; framing::Uuid clusterId; NoOpConnectionOutputHandler shadowOut; qpid::management::ManagementAgent* mAgent; + boost::intrusive_ptr<ExpiryPolicy> expiryPolicy; // Thread safe members Multicaster mcast; PollerDispatch dispatcher; PollableEventQueue deliverEventQueue; PollableFrameQueue deliverFrameQueue; - ConnectionMap connections; boost::shared_ptr<FailoverExchange> failoverExchange; Quorum quorum; - - // Used only in delivery thread - Decoder decoder; - ClusterMap::Set elders; - boost::intrusive_ptr<ExpiryPolicy> expiryPolicy; - uint64_t frameId; + LockedConnectionMap localConnections; // Used only during initialization bool initialized; - // Remaining members are protected by lock + // Used only in deliverEventQueue thread or when stalled for update. + Decoder decoder; + bool discarding; + + // Remaining members are protected by lock. + // FIXME aconway 2009-03-06: Most of these members are also only used in + // deliverFrameQueue thread or during stall. Review and separate members + // that require a lock, drop lock when not needed. + // mutable sys::Monitor lock; + // Local cluster state, cluster map enum { INIT, ///< Initial state, no CPG messages received. @@ -223,15 +235,16 @@ class Cluster : private Cpg::Handler, public management::Manageable { UPDATER, ///< Offer accepted, sending a state update. LEFT ///< Final state, left the cluster. } state; + + ConnectionMap connections; ClusterMap map; + ClusterMap::Set elders; size_t lastSize; bool lastBroker; - uint64_t sequence; - - // Update related sys::Thread updateThread; boost::optional<ClusterMap> updatedMap; + friend std::ostream& operator<<(std::ostream&, const Cluster&); friend class ClusterDispatcher; }; diff --git a/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp b/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp index 132043f91a..adb6621caf 100644 --- a/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp +++ b/qpid/cpp/src/qpid/cluster/ClusterPlugin.cpp @@ -138,7 +138,6 @@ struct ClusterPlugin : public Plugin { broker->setConnectionFactory( boost::shared_ptr<sys::ConnectionCodec::Factory>( new ConnectionCodec::Factory(broker->getConnectionFactory(), *cluster))); - broker->getExchanges().registerExchange(cluster->getFailoverExchange()); ManagementBroker* mgmt = dynamic_cast<ManagementBroker*>(ManagementAgent::Singleton::getInstance()); if (mgmt) { std::auto_ptr<IdAllocator> allocator(new UpdateClientIdAllocator()); diff --git a/qpid/cpp/src/qpid/cluster/ClusterSettings.h b/qpid/cpp/src/qpid/cluster/ClusterSettings.h index a8f33be75e..88e8829dfe 100644 --- a/qpid/cpp/src/qpid/cluster/ClusterSettings.h +++ b/qpid/cpp/src/qpid/cluster/ClusterSettings.h @@ -35,7 +35,7 @@ struct ClusterSettings { size_t readMax, writeEstimate; std::string username, password, mechanism; - ClusterSettings() : quorum(false), readMax(10), writeEstimate(64), username("guest"), password("guest") {} + ClusterSettings() : quorum(false), readMax(10), writeEstimate(64) {} Url getUrl(uint16_t port) const { if (url.empty()) return Url::getIpAddressesUrl(port); diff --git a/qpid/cpp/src/qpid/cluster/Connection.cpp b/qpid/cpp/src/qpid/cluster/Connection.cpp index 1a3f7c4ef7..aa7d082720 100644 --- a/qpid/cpp/src/qpid/cluster/Connection.cpp +++ b/qpid/cpp/src/qpid/cluster/Connection.cpp @@ -40,6 +40,7 @@ #include "qpid/framing/ConnectionCloseOkBody.h" #include "qpid/log/Statement.h" #include "qpid/sys/LatencyMetric.h" +#include "qpid/sys/AtomicValue.h" #include <boost/current_function.hpp> @@ -58,27 +59,36 @@ using namespace framing; NoOpConnectionOutputHandler Connection::discardHandler; -// Shadow connections -Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out, - const std::string& wrappedId, ConnectionId myId) - : cluster(c), self(myId), catchUp(false), output(*this, out), - connection(&output, cluster.getBroker(), wrappedId), expectProtocolHeader(false) +namespace { +sys::AtomicValue<uint64_t> idCounter; +} + +// Shadow connection +Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out, const std::string& logId, const ConnectionId& id) + : cluster(c), self(id), catchUp(false), output(*this, out), + connection(&output, cluster.getBroker(), logId), expectProtocolHeader(false), + mcastFrameHandler(cluster.getMulticast(), self) { init(); } -// Local connections +// Local connection Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out, - const std::string& wrappedId, MemberId myId, bool isCatchUp, bool isLink) - : cluster(c), self(myId, this), catchUp(isCatchUp), output(*this, out), - connection(&output, cluster.getBroker(), wrappedId, isLink, catchUp ? ++catchUpId : 0), - expectProtocolHeader(isLink) + const std::string& logId, MemberId member, bool isCatchUp, bool isLink) + : cluster(c), self(member, ++idCounter), catchUp(isCatchUp), output(*this, out), + connection(&output, cluster.getBroker(), logId, isLink, catchUp ? ++catchUpId : 0), + expectProtocolHeader(isLink), mcastFrameHandler(cluster.getMulticast(), self) { init(); } void Connection::init() { QPID_LOG(debug, cluster << " new connection: " << *this); - if (isLocalClient()) { + if (isLocalClient()) { + connection.setClusterOrderOutput(mcastFrameHandler); // Actively send cluster-order frames from local node cluster.addLocalConnection(this); giveReadCredit(cluster.getReadMax()); } + else { // Shadow or catch-up connection + connection.setClusterOrderOutput(nullFrameHandler); // Passive, discard cluster-order frames + connection.setClientThrottling(false); // Disable client throttling, done by active node. + } } void Connection::giveReadCredit(int credit) { @@ -140,10 +150,16 @@ bool Connection::checkUnsupported(const AMQBody& body) { void Connection::deliveredFrame(const EventFrame& f) { assert(!catchUp); currentChannel = f.frame.getChannel(); - if (!framing::invoke(*this, *f.frame.getBody()).wasHandled() // Connection contol. + if (f.frame.getBody() // frame can be emtpy with just readCredit + && !framing::invoke(*this, *f.frame.getBody()).wasHandled() // Connection contol. && !checkUnsupported(*f.frame.getBody())) // Unsupported operation. { - connection.received(const_cast<AMQFrame&>(f.frame)); // Pass to broker connection. + if (f.type == DATA) // incoming data frames to broker::Connection + connection.received(const_cast<AMQFrame&>(f.frame)); + else { // frame control, send frame via SessionState + broker::SessionState* ss = connection.getChannel(f.frame.getChannel()).getSession(); + if (ss) ss->out(const_cast<AMQFrame&>(f.frame)); + } } giveReadCredit(f.readCredit); } @@ -186,12 +202,12 @@ void Connection::left() { connection.closed(); } -// Decode data from local clients. +// ConnectoinCodec::decode receives read buffers from directly-connected clients. size_t Connection::decode(const char* buffer, size_t size) { if (catchUp) { // Handle catch-up locally. Buffer buf(const_cast<char*>(buffer), size); while (localDecoder.decode(buf)) - received(localDecoder.frame); + received(localDecoder.getFrame()); } else { // Multicast local connections. assert(isLocal()); @@ -242,6 +258,7 @@ void Connection::sessionState( const SequenceSet& unknownCompleted, const SequenceSet& receivedIncomplete) { + sessionState().setState( replayStart, sendCommandPoint, @@ -253,21 +270,23 @@ void Connection::sessionState( QPID_LOG(debug, cluster << " received session state update for " << sessionState().getId()); } -void Connection::shadowReady(uint64_t memberId, uint64_t connectionId, const string& username) { - ConnectionId shadow = ConnectionId(memberId, connectionId); - QPID_LOG(debug, cluster << " catch-up connection " << *this << " becomes shadow " << shadow); - self = shadow; +void Connection::shadowReady(uint64_t memberId, uint64_t connectionId, const string& username, const string& fragment) { + ConnectionId shadowId = ConnectionId(memberId, connectionId); + QPID_LOG(debug, cluster << " catch-up connection " << *this << " becomes shadow " << shadowId); + self = shadowId; connection.setUserId(username); + // OK to use decoder here because we are stalled for update. + cluster.getDecoder().get(self).setFragment(fragment.data(), fragment.size()); } -void Connection::membership(const FieldTable& joiners, const FieldTable& members, uint64_t frameId) { +void Connection::membership(const FieldTable& joiners, const FieldTable& members) { QPID_LOG(debug, cluster << " incoming update complete on connection " << *this); - cluster.updateInDone(ClusterMap(joiners, members), frameId); + cluster.updateInDone(ClusterMap(joiners, members)); self.second = 0; // Mark this as completed update connection. } bool Connection::isLocal() const { - return self.first == cluster.getId() && self.second == this; + return self.first == cluster.getId() && self.second; } bool Connection::isShadow() const { @@ -333,6 +352,10 @@ void Connection::queuePosition(const string& qname, const SequenceNumber& positi q->setPosition(position); } +void Connection::expiryId(uint64_t id) { + cluster.getExpiryPolicy().setId(id); +} + std::ostream& operator<<(std::ostream& o, const Connection& c) { const char* type="unknown"; if (c.isLocal()) type = "local"; diff --git a/qpid/cpp/src/qpid/cluster/Connection.h b/qpid/cpp/src/qpid/cluster/Connection.h index 98b47e1bc0..6434f763a8 100644 --- a/qpid/cpp/src/qpid/cluster/Connection.h +++ b/qpid/cpp/src/qpid/cluster/Connection.h @@ -27,14 +27,15 @@ #include "OutputInterceptor.h" #include "NoOpConnectionOutputHandler.h" #include "EventFrame.h" +#include "McastFrameHandler.h" #include "qpid/broker/Connection.h" #include "qpid/amqp_0_10/Connection.h" #include "qpid/sys/AtomicValue.h" #include "qpid/sys/ConnectionInputHandler.h" #include "qpid/sys/ConnectionOutputHandler.h" -#include "qpid/framing/FrameDecoder.h" #include "qpid/framing/SequenceNumber.h" +#include "qpid/framing/FrameDecoder.h" #include <iosfwd> @@ -63,10 +64,10 @@ class Connection : public: typedef sys::PollableQueue<EventFrame> PollableFrameQueue; - /** Local connection, use this in ConnectionId */ - Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& id, MemberId, bool catchUp, bool isLink); - /** Shadow connection */ - Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& id, ConnectionId); + /** Local connection. */ + Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& logId, MemberId, bool catchUp, bool isLink); + /** Shadow connection. */ + Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& logId, const ConnectionId& id); ~Connection(); ConnectionId getId() const { return self; } @@ -99,7 +100,7 @@ class Connection : /** Called if the connectors member has left the cluster */ void left(); - // ConnectionCodec methods + // ConnectionCodec methods - called by IO layer with a read buffer. size_t decode(const char* buffer, size_t size); // Called for data delivered from the cluster. @@ -117,9 +118,9 @@ class Connection : const framing::SequenceNumber& received, const framing::SequenceSet& unknownCompleted, const SequenceSet& receivedIncomplete); - void shadowReady(uint64_t memberId, uint64_t connectionId, const std::string& username); + void shadowReady(uint64_t memberId, uint64_t connectionId, const std::string& username, const std::string& fragment); - void membership(const framing::FieldTable&, const framing::FieldTable&, uint64_t frameId); + void membership(const framing::FieldTable&, const framing::FieldTable&); void deliveryRecord(const std::string& queue, const framing::SequenceNumber& position, @@ -134,6 +135,7 @@ class Connection : uint32_t credit); void queuePosition(const std::string&, const framing::SequenceNumber&); + void expiryId(uint64_t); void txStart(); void txAccept(const framing::SequenceSet&); @@ -148,8 +150,12 @@ class Connection : void exchange(const std::string& encoded); void giveReadCredit(int credit); - + private: + struct NullFrameHandler : public framing::FrameHandler { + void handle(framing::AMQFrame&) {} + }; + void init(); bool checkUnsupported(const framing::AMQBody& body); void deliverClose(); @@ -174,6 +180,8 @@ class Connection : framing::ChannelId currentChannel; boost::shared_ptr<broker::TxBuffer> txBuffer; bool expectProtocolHeader; + McastFrameHandler mcastFrameHandler; + NullFrameHandler nullFrameHandler; static qpid::sys::AtomicValue<uint64_t> catchUpId; diff --git a/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp b/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp index 442ac1438f..007337792b 100644 --- a/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp +++ b/qpid/cpp/src/qpid/cluster/ConnectionCodec.cpp @@ -44,18 +44,15 @@ ConnectionCodec::Factory::create(ProtocolVersion v, sys::OutputControl& out, con return 0; } -// Used for outgoing Link connections, we don't care. +// Used for outgoing Link connections sys::ConnectionCodec* -ConnectionCodec::Factory::create(sys::OutputControl& out, const std::string& id) { - return new ConnectionCodec(out, id, cluster, false, true); - //return next->create(out, id); +ConnectionCodec::Factory::create(sys::OutputControl& out, const std::string& logId) { + return new ConnectionCodec(out, logId, cluster, false, true); } -ConnectionCodec::ConnectionCodec(sys::OutputControl& out, const std::string& id, Cluster& cluster, bool catchUp, bool isLink) - : codec(out, id, isLink), - interceptor(new Connection(cluster, codec, id, cluster.getId(), catchUp, isLink)), - id(interceptor->getId()), - localId(id) +ConnectionCodec::ConnectionCodec(sys::OutputControl& out, const std::string& logId, Cluster& cluster, bool catchUp, bool isLink) + : codec(out, logId, isLink), + interceptor(new Connection(cluster, codec, logId, cluster.getId(), catchUp, isLink)) { std::auto_ptr<sys::ConnectionInputHandler> ih(new ProxyInputHandler(interceptor)); codec.setInputHandler(ih); diff --git a/qpid/cpp/src/qpid/cluster/ConnectionCodec.h b/qpid/cpp/src/qpid/cluster/ConnectionCodec.h index 69c2b0c3c8..ea01b7abb9 100644 --- a/qpid/cpp/src/qpid/cluster/ConnectionCodec.h +++ b/qpid/cpp/src/qpid/cluster/ConnectionCodec.h @@ -56,7 +56,7 @@ class ConnectionCodec : public sys::ConnectionCodec { sys::ConnectionCodec* create(sys::OutputControl&, const std::string& id); }; - ConnectionCodec(sys::OutputControl& out, const std::string& id, Cluster& c, bool catchUp, bool isLink); + ConnectionCodec(sys::OutputControl& out, const std::string& logId, Cluster& c, bool catchUp, bool isLink); ~ConnectionCodec(); // ConnectionCodec functions. @@ -71,8 +71,6 @@ class ConnectionCodec : public sys::ConnectionCodec { private: amqp_0_10::Connection codec; boost::intrusive_ptr<cluster::Connection> interceptor; - cluster::ConnectionId id; - std::string localId; }; }} // namespace qpid::cluster diff --git a/qpid/cpp/src/qpid/cluster/ConnectionDecoder.cpp b/qpid/cpp/src/qpid/cluster/ConnectionDecoder.cpp deleted file mode 100644 index 3c18cf751e..0000000000 --- a/qpid/cpp/src/qpid/cluster/ConnectionDecoder.cpp +++ /dev/null @@ -1,57 +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 "ConnectionDecoder.h" -#include "EventFrame.h" -#include "ConnectionMap.h" - -namespace qpid { -namespace cluster { - -using namespace framing; - -ConnectionDecoder::ConnectionDecoder(const Handler& h) : handler(h) {} - -void ConnectionDecoder::decode(const EventHeader& eh, const void* data, ConnectionMap& map) { - assert(eh.getType() == DATA); // Only handle connection data events. - const char* cp = static_cast<const char*>(data); - Buffer buf(const_cast<char*>(cp), eh.getSize()); - if (decoder.decode(buf)) { // Decoded a frame - AMQFrame frame(decoder.frame); - while (decoder.decode(buf)) { - handler(EventFrame(eh, frame)); - frame = decoder.frame; - } - // Set read-credit on the last frame ending in this event. - // Credit will be given when this frame is processed. - handler(EventFrame(eh, frame, 1)); - } - else { - // We must give 1 unit read credit per event. - // This event does not complete any frames so - // we give read credit directly. - ConnectionPtr connection = map.getLocal(eh.getConnectionId()); - if (connection) - connection->giveReadCredit(1); - } -} - -}} // namespace qpid::cluster diff --git a/qpid/cpp/src/qpid/cluster/ConnectionMap.cpp b/qpid/cpp/src/qpid/cluster/ConnectionMap.cpp deleted file mode 100644 index b412bb13cc..0000000000 --- a/qpid/cpp/src/qpid/cluster/ConnectionMap.cpp +++ /dev/null @@ -1,96 +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 "ConnectionMap.h" -#include "Cluster.h" -#include "qpid/framing/reply_exceptions.h" -#include "qpid/log/Statement.h" - -namespace qpid { -namespace cluster { - -using framing::InternalErrorException; - -void ConnectionMap::insert(ConnectionPtr p) { - std::pair<Map::iterator, bool> ib = map.insert(Map::value_type(p->getId(), p)); - if (!ib.second) { - assert(0); - throw InternalErrorException(QPID_MSG("Duplicate connection replica: " << p->getId())); - } -} - -void ConnectionMap::erase(const ConnectionId& id) { - Map::iterator i = map.find(id); - if (i == map.end()) { - assert(0); - QPID_LOG(warning, "Erase non-existent connection replica: " << id); - } - map.erase(i); -} - -ConnectionMap::ConnectionPtr ConnectionMap::get(const ConnectionId& id) { - Map::const_iterator i = map.find(id); - if (i == map.end()) { - // Deleted local connection. - if(id.getMember() == cluster.getId()) - return 0; - // New remote connection, create a shadow. - std::ostringstream mgmtId; - mgmtId << id; - ConnectionPtr cp = new Connection(cluster, shadowOut, mgmtId.str(), id); - std::pair<Map::iterator, bool> ib = map.insert(Map::value_type(id, cp)); - if (!ib.second) - throw InternalErrorException(QPID_MSG("Duplicate entry in cluster connection map: " << id)); - i = ib.first; - } - return i->second; -} - -ConnectionMap::ConnectionPtr ConnectionMap::getLocal(const ConnectionId& id) { - if (id.getMember() != cluster.getId()) return 0; - Map::const_iterator i = map.find(id); - assert(i != map.end()); // FIXME aconway 2009-02-11: remove or exception. - return i == map.end() ? 0 : i->second; -} - -ConnectionMap::Vector ConnectionMap::values() const { - Vector result(map.size()); - std::transform(map.begin(), map.end(), result.begin(), - boost::bind(&Map::value_type::second, _1)); - return result; -} - -void ConnectionMap::update(MemberId myId, const ClusterMap& cluster) { - for (Map::iterator i = map.begin(); i != map.end(); ) { - MemberId member = i->first.getMember(); - if (member != myId && !cluster.isMember(member)) { - i->second->left(); - map.erase(i++); - } else { - i++; - } - } -} - -void ConnectionMap::clear() { - map.clear(); -} - -}} // namespace qpid::cluster diff --git a/qpid/cpp/src/qpid/cluster/ConnectionMap.h b/qpid/cpp/src/qpid/cluster/ConnectionMap.h deleted file mode 100644 index f8aa663339..0000000000 --- a/qpid/cpp/src/qpid/cluster/ConnectionMap.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef QPID_CLUSTER_CONNECTIONMAP_H -#define QPID_CLUSTER_CONNECTIONMAP_H - -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -#include "types.h" -#include "Connection.h" -#include "ClusterMap.h" -#include "NoOpConnectionOutputHandler.h" -#include "qpid/sys/Mutex.h" -#include <boost/intrusive_ptr.hpp> -#include <map> - -namespace qpid { -namespace cluster { - -class Cluster; - -/** - * Thread safe map of connections. The map is used in: - * - deliver thread to look connections and create new shadow connections. - * - local catch-up connection threads to add a caught-up shadow connections. - * - local client connection threads when local connections are created. - */ -class ConnectionMap { - public: - typedef boost::intrusive_ptr<cluster::Connection> ConnectionPtr; - typedef std::vector<ConnectionPtr> Vector; - - ConnectionMap(Cluster& c) : cluster(c) {} - - /** Insert a local connection or a caught up shadow connection. - * Called in local connection thread. - */ - void insert(ConnectionPtr p); - - /** Erase a closed connection. Called in deliver thread. */ - void erase(const ConnectionId& id); - - /** Get an existing connection. Returns 0 if id is a closed local - * connections, frames for closed connections should be ignored. - */ - ConnectionPtr get(const ConnectionId& id); - - /** If ID is a local connection and in the map return it, else return 0 */ - ConnectionPtr getLocal(const ConnectionId& id); - - /** Get connections for sending an update. */ - Vector values() const; - - /** Remove connections who's members are no longer in the cluster. Deliver thread. */ - void update(MemberId myId, const ClusterMap& cluster); - - - void clear(); - - size_t size() const; - - private: - typedef std::map<ConnectionId, ConnectionPtr> Map; - - Cluster& cluster; - NoOpConnectionOutputHandler shadowOut; - Map map; -}; - - -}} // namespace qpid::cluster - -#endif /*!QPID_CLUSTER_CONNECTIONMAP_H*/ diff --git a/qpid/cpp/src/qpid/cluster/Cpg.cpp b/qpid/cpp/src/qpid/cluster/Cpg.cpp index c5a1b72003..915a578989 100644 --- a/qpid/cpp/src/qpid/cluster/Cpg.cpp +++ b/qpid/cpp/src/qpid/cluster/Cpg.cpp @@ -107,17 +107,16 @@ void Cpg::leave() { check(cpg_leave(handle, &group), cantLeaveMsg(group)); } -bool Cpg::isFlowControlEnabled() { - cpg_flow_control_state_t flowState; - check(cpg_flow_control_state_get(handle, &flowState), "Cannot get CPG flow control status."); - return flowState == CPG_FLOW_CONTROL_ENABLED; -} + + bool Cpg::mcast(const iovec* iov, int iovLen) { - if (isFlowControlEnabled()) { - QPID_LOG(debug, "CPG flow control enabled") + // Check for flow control + cpg_flow_control_state_t flowState; + check(cpg_flow_control_state_get(handle, &flowState), "Cannot get CPG flow control status."); + if (flowState == CPG_FLOW_CONTROL_ENABLED) return false; - } + cpg_error_t result; do { result = cpg_mcast_joined(handle, CPG_TYPE_AGREED, const_cast<iovec*>(iov), iovLen); @@ -149,9 +148,13 @@ void Cpg::dispatchBlocking() { string Cpg::errorStr(cpg_error_t err, const std::string& msg) { std::ostringstream os; os << msg << ": "; + // FIXME aconway 2009-03-11: The commented out cases below are + // because of mistakes in the latest corosync header files. + // The code should be re-instated when that is sorted out. + // switch (err) { case CPG_OK: os << "ok"; break; - case CPG_ERR_LIBRARY: os << "library"; break; + // case CPG_ERR_LIBRARY: os << "library"; break; case CPG_ERR_TIMEOUT: os << "timeout"; break; case CPG_ERR_TRY_AGAIN: os << "try again"; break; case CPG_ERR_INVALID_PARAM: os << "invalid param"; break; @@ -161,8 +164,8 @@ string Cpg::errorStr(cpg_error_t err, const std::string& msg) { case CPG_ERR_NOT_EXIST: os << "not exist"; break; case CPG_ERR_EXIST: os << "exist"; break; case CPG_ERR_NOT_SUPPORTED: os << "not supported"; break; - case CPG_ERR_SECURITY: os << "security"; break; - case CPG_ERR_TOO_MANY_GROUPS: os << "too many groups"; break; + // case CPG_ERR_SECURITY: os << "security"; break; + // case CPG_ERR_TOO_MANY_GROUPS: os << "too many groups"; break; default: os << ": unknown cpg error " << err; }; os << " (" << err << ")"; @@ -203,13 +206,19 @@ ostream& operator<<(ostream& o, const ConnectionId& c) { std::string MemberId::str() const { char s[8]; - reinterpret_cast<uint32_t&>(s[0]) = htonl(first); - reinterpret_cast<uint32_t&>(s[4]) = htonl(second); + uint32_t x; + x = htonl(first); + ::memcpy(s, &x, 4); + x = htonl(second); + ::memcpy(s+4, &x, 4); return std::string(s,8); } MemberId::MemberId(const std::string& s) { - first = ntohl(reinterpret_cast<const uint32_t&>(s[0])); - second = ntohl(reinterpret_cast<const uint32_t&>(s[4])); + uint32_t x; + memcpy(&x, &s[0], 4); + first = ntohl(x); + memcpy(&x, &s[4], 4); + second = ntohl(x); } }} // namespace qpid::cluster diff --git a/qpid/cpp/src/qpid/cluster/Cpg.h b/qpid/cpp/src/qpid/cluster/Cpg.h index 5ac5a5bdbc..ac27a09ae6 100644 --- a/qpid/cpp/src/qpid/cluster/Cpg.h +++ b/qpid/cpp/src/qpid/cluster/Cpg.h @@ -114,8 +114,6 @@ class Cpg : public sys::IOHandle { int getFd(); - bool isFlowControlEnabled(); - private: static std::string errorStr(cpg_error_t err, const std::string& msg); static std::string cantJoinMsg(const Name&); diff --git a/qpid/cpp/src/qpid/cluster/Decoder.cpp b/qpid/cpp/src/qpid/cluster/Decoder.cpp index 1ba36bb521..b337ef43f4 100644 --- a/qpid/cpp/src/qpid/cluster/Decoder.cpp +++ b/qpid/cpp/src/qpid/cluster/Decoder.cpp @@ -18,33 +18,44 @@ * under the License. * */ - #include "Decoder.h" -#include "Event.h" +#include "EventFrame.h" +#include "qpid/framing/ClusterConnectionDeliverCloseBody.h" #include "qpid/framing/Buffer.h" -#include "qpid/ptr_map.h" +#include "qpid/framing/AMQFrame.h" + namespace qpid { namespace cluster { -using namespace framing; - -Decoder::Decoder(const Handler& h, ConnectionMap& cm) : handler(h), connections(cm) {} - -void Decoder::decode(const EventHeader& eh, const void* data) { - ConnectionId id = eh.getConnectionId(); - Map::iterator i = map.find(id); - if (i == map.end()) { - std::pair<Map::iterator, bool> ib = map.insert(id, new ConnectionDecoder(handler)); - i = ib.first; +void Decoder::decode(const EventHeader& eh, const char* data) { + assert(eh.getType() == DATA); // Only handle connection data events. + const char* cp = static_cast<const char*>(data); + framing::Buffer buf(const_cast<char*>(cp), eh.getSize()); + framing::FrameDecoder& decoder = map[eh.getConnectionId()]; + if (decoder.decode(buf)) { // Decoded a frame + framing::AMQFrame frame(decoder.getFrame()); + while (decoder.decode(buf)) { + process(EventFrame(eh, frame)); + frame = decoder.getFrame(); + } + // Set read-credit on the last frame ending in this event. + // Credit will be given when this frame is processed. + process(EventFrame(eh, frame, 1)); } - ptr_map_ptr(i)->decode(eh, data, connections); + else { + // We must give 1 unit read credit per event. + // This event does not complete any frames so + // send an empty frame with the read credit. + process(EventFrame(eh, framing::AMQFrame(), 1)); + } } -void Decoder::erase(const ConnectionId& c) { - Map::iterator i = map.find(c); - if (i != map.end()) - map.erase(i); +void Decoder::process(const EventFrame& ef) { + //need to check that this is not the empty frame mentioned above + if (ef.frame.getBody() && ef.frame.getMethod() && ef.frame.getMethod()->isA<framing::ClusterConnectionDeliverCloseBody>()) + map.erase(ef.connectionId); + callback(ef); } }} // namespace qpid::cluster diff --git a/qpid/cpp/src/qpid/cluster/Decoder.h b/qpid/cpp/src/qpid/cluster/Decoder.h index 50f6afa491..acde4258a2 100644 --- a/qpid/cpp/src/qpid/cluster/Decoder.h +++ b/qpid/cpp/src/qpid/cluster/Decoder.h @@ -22,44 +22,36 @@ * */ -#include "ConnectionDecoder.h" #include "types.h" -#include <boost/ptr_container/ptr_map.hpp> +#include "qpid/framing/FrameDecoder.h" +#include <boost/function.hpp> +#include <map> namespace qpid { namespace cluster { +class EventFrame; class EventHeader; -class ConnectionMap; /** - * Holds a map of ConnectionDecoders. Decodes Events into EventFrames - * and forwards EventFrames to a handler. - * - * THREAD UNSAFE: Called sequentially with un-decoded cluster events from CPG. + * A map of decoders for connections. */ class Decoder { public: - typedef boost::function<void(const EventFrame&)> Handler; - - Decoder(const Handler& h, ConnectionMap&); + typedef boost::function<void(const EventFrame&)> FrameHandler; - /** Takes EventHeader + data rather than Event so that the caller can - * pass a pointer to connection data or a CPG buffer directly without copy. - */ - void decode(const EventHeader& eh, const void* data); - - /** Erase the decoder for a connection. */ + Decoder(FrameHandler fh) : callback(fh) {} + void decode(const EventHeader& eh, const char* data); void erase(const ConnectionId&); + framing::FrameDecoder& get(const ConnectionId& c) { return map[c]; } private: - typedef boost::ptr_map<ConnectionId, ConnectionDecoder> Map; - Handler handler; + typedef std::map<ConnectionId, framing::FrameDecoder> Map; Map map; - ConnectionMap& connections; + void process(const EventFrame&); + FrameHandler callback; }; - }} // namespace qpid::cluster #endif /*!QPID_CLUSTER_DECODER_H*/ diff --git a/qpid/cpp/src/qpid/cluster/Event.cpp b/qpid/cpp/src/qpid/cluster/Event.cpp index e30b961b3e..1cb010c266 100644 --- a/qpid/cpp/src/qpid/cluster/Event.cpp +++ b/qpid/cpp/src/qpid/cluster/Event.cpp @@ -23,6 +23,7 @@ #include "Cpg.h" #include "qpid/framing/Buffer.h" #include "qpid/framing/AMQFrame.h" +#include "qpid/assert.h" #include <ostream> #include <iterator> #include <algorithm> @@ -31,6 +32,7 @@ namespace qpid { namespace cluster { using framing::Buffer; +using framing::AMQFrame; const size_t EventHeader::HEADER_SIZE = sizeof(uint8_t) + // type @@ -42,7 +44,7 @@ const size_t EventHeader::HEADER_SIZE = ; EventHeader::EventHeader(EventType t, const ConnectionId& c, size_t s) - : type(t), connectionId(c), size(s), sequence(0) {} + : type(t), connectionId(c), size(s) {} Event::Event() {} @@ -57,7 +59,7 @@ void EventHeader::decode(const MemberId& m, framing::Buffer& buf) { type = (EventType)buf.getOctet(); if(type != DATA && type != CONTROL) throw Exception("Invalid multicast event type"); - connectionId = ConnectionId(m, reinterpret_cast<Connection*>(buf.getLongLong())); + connectionId = ConnectionId(m, buf.getLongLong()); size = buf.getLong(); #ifdef QPID_LATENCY_METRIC latency_metric_timestamp = buf.getLongLong(); @@ -74,14 +76,17 @@ Event Event::decodeCopy(const MemberId& m, framing::Buffer& buf) { return e; } -Event Event::control(const framing::AMQBody& body, const ConnectionId& cid) { - framing::AMQFrame f(body); +Event Event::control(const framing::AMQFrame& f, const ConnectionId& cid) { Event e(CONTROL, cid, f.encodedSize()); Buffer buf(e); f.encode(buf); return e; } +Event Event::control(const framing::AMQBody& body, const ConnectionId& cid) { + return control(framing::AMQFrame(body), cid); +} + iovec Event::toIovec() { encodeHeader(); iovec iov = { const_cast<char*>(getStore()), getStoreSize() }; @@ -90,7 +95,7 @@ iovec Event::toIovec() { void EventHeader::encode(Buffer& b) const { b.putOctet(type); - b.putLongLong(reinterpret_cast<uint64_t>(connectionId.getPointer())); + b.putLongLong(connectionId.getNumber()); b.putLong(size); #ifdef QPID_LATENCY_METRIC b.putLongLong(latency_metric_timestamp); @@ -108,12 +113,22 @@ Event::operator Buffer() const { return Buffer(const_cast<char*>(getData()), getSize()); } +AMQFrame Event::getFrame() const { + assert(type == CONTROL); + Buffer buf(*this); + AMQFrame frame; + QPID_ASSERT(frame.decode(buf)); + return frame; +} + static const char* EVENT_TYPE_NAMES[] = { "data", "control" }; +std::ostream& operator << (std::ostream& o, EventType t) { + return o << EVENT_TYPE_NAMES[t]; +} + std::ostream& operator << (std::ostream& o, const EventHeader& e) { - o << "[event " << e.getConnectionId() << "/" << e.getSequence() - << " " << EVENT_TYPE_NAMES[e.getType()] - << " " << e.getSize() << " bytes]"; + o << "Event[" << e.getConnectionId() << " " << e.getType() << " " << e.getSize() << " bytes]"; return o; } diff --git a/qpid/cpp/src/qpid/cluster/Event.h b/qpid/cpp/src/qpid/cluster/Event.h index f1de248f89..e05ad60bcf 100644 --- a/qpid/cpp/src/qpid/cluster/Event.h +++ b/qpid/cpp/src/qpid/cluster/Event.h @@ -24,6 +24,7 @@ #include "types.h" #include "qpid/RefCountedBuffer.h" +#include "qpid/framing/AMQFrame.h" #include "qpid/sys/LatencyMetric.h" #include <sys/uio.h> // For iovec #include <iosfwd> @@ -34,6 +35,7 @@ namespace qpid { namespace framing { class AMQBody; +class AMQFrame; class Buffer; } @@ -55,11 +57,9 @@ class EventHeader : public ::qpid::sys::LatencyMetricTimestamp { /** Size of header + payload. */ size_t getStoreSize() { return size + HEADER_SIZE; } - uint64_t getSequence() const { return sequence; } - void setSequence(uint64_t n) { sequence = n; } - - bool isCluster() const { return connectionId.getPointer() == 0; } - bool isConnection() const { return connectionId.getPointer() != 0; } + bool isCluster() const { return connectionId.getNumber() == 0; } + bool isConnection() const { return connectionId.getNumber() != 0; } + bool isControl() const { return type == CONTROL; } protected: static const size_t HEADER_SIZE; @@ -67,7 +67,6 @@ class EventHeader : public ::qpid::sys::LatencyMetricTimestamp { EventType type; ConnectionId connectionId; size_t size; - uint64_t sequence; }; /** @@ -83,8 +82,11 @@ class Event : public EventHeader { /** Create an event copied from delivered data. */ static Event decodeCopy(const MemberId& m, framing::Buffer&); - /** Create an event containing a control */ + /** Create a control event. */ static Event control(const framing::AMQBody&, const ConnectionId&); + + /** Create a control event. */ + static Event control(const framing::AMQFrame&, const ConnectionId&); // Data excluding header. char* getData() { return store + HEADER_SIZE; } @@ -93,6 +95,8 @@ class Event : public EventHeader { // Store including header char* getStore() { return store; } const char* getStore() const { return store; } + + framing::AMQFrame getFrame() const; operator framing::Buffer() const; @@ -105,6 +109,7 @@ class Event : public EventHeader { }; std::ostream& operator << (std::ostream&, const EventHeader&); + }} // namespace qpid::cluster #endif /*!QPID_CLUSTER_EVENT_H*/ diff --git a/qpid/cpp/src/qpid/cluster/EventFrame.cpp b/qpid/cpp/src/qpid/cluster/EventFrame.cpp index ba01c170dd..9350c801f5 100644 --- a/qpid/cpp/src/qpid/cluster/EventFrame.cpp +++ b/qpid/cpp/src/qpid/cluster/EventFrame.cpp @@ -24,16 +24,20 @@ namespace qpid { namespace cluster { -EventFrame::EventFrame() : sequence(0) {} +EventFrame::EventFrame() {} EventFrame::EventFrame(const EventHeader& e, const framing::AMQFrame& f, int rc) - : connectionId(e.getConnectionId()), frame(f), sequence(e.getSequence()), readCredit(rc) + : connectionId(e.getConnectionId()), frame(f), readCredit(rc), type(e.getType()) { QPID_LATENCY_INIT(frame); } std::ostream& operator<<(std::ostream& o, const EventFrame& e) { - return o << e.connectionId << "/" << e.sequence << " " << e.frame << " rc=" << e.readCredit; + if (e.frame.getBody()) o << e.frame; + else o << "null-frame"; + o << " " << e.type << " " << e.connectionId; + if (e.readCredit) o << " read-credit=" << e.readCredit; + return o; } }} // namespace qpid::cluster diff --git a/qpid/cpp/src/qpid/cluster/EventFrame.h b/qpid/cpp/src/qpid/cluster/EventFrame.h index 7f33cedb5b..d6ff58dd38 100644 --- a/qpid/cpp/src/qpid/cluster/EventFrame.h +++ b/qpid/cpp/src/qpid/cluster/EventFrame.h @@ -42,22 +42,15 @@ struct EventFrame EventFrame(const EventHeader& e, const framing::AMQFrame& f, int rc=0); - bool isCluster() const { return !connectionId.getPointer(); } - bool isConnection() const { return connectionId.getPointer(); } + bool isCluster() const { return connectionId.getNumber() == 0; } + bool isConnection() const { return connectionId.getNumber() != 0; } bool isLastInEvent() const { return readCredit; } - // True if this frame follows immediately after frame e. - bool follows(const EventFrame& e) const { - return sequence == e.sequence || (sequence == e.sequence+1 && e.readCredit); - } - - bool operator<(const EventFrame& e) const { return sequence < e.sequence; } - ConnectionId connectionId; framing::AMQFrame frame; - uint64_t sequence; - int readCredit; // last frame in an event, give credit when processed. + int readCredit; ///< last frame in an event, give credit when processed. + EventType type; }; std::ostream& operator<<(std::ostream& o, const EventFrame& e); diff --git a/qpid/cpp/src/qpid/cluster/ExpiryPolicy.cpp b/qpid/cpp/src/qpid/cluster/ExpiryPolicy.cpp index 690acfc3ad..409180c499 100644 --- a/qpid/cpp/src/qpid/cluster/ExpiryPolicy.cpp +++ b/qpid/cpp/src/qpid/cluster/ExpiryPolicy.cpp @@ -30,48 +30,46 @@ namespace qpid { namespace cluster { -ExpiryPolicy::ExpiryPolicy(const boost::function<bool()> & f, Multicaster& m, const MemberId& id, broker::Timer& t) - : expiredPolicy(new Expired), isLeader(f), mcast(m), memberId(id), timer(t) {} - -namespace { -uint64_t clusterId(const broker::Message& m) { - assert(m.getFrames().begin() != m.getFrames().end()); - return m.getFrames().begin()->getClusterId(); -} +ExpiryPolicy::ExpiryPolicy(Multicaster& m, const MemberId& id, broker::Timer& t) + : expiryId(0), expiredPolicy(new Expired), mcast(m), memberId(id), timer(t) {} struct ExpiryTask : public broker::TimerTask { ExpiryTask(const boost::intrusive_ptr<ExpiryPolicy>& policy, uint64_t id, sys::AbsTime when) - : TimerTask(when), expiryPolicy(policy), messageId(id) {} - void fire() { expiryPolicy->sendExpire(messageId); } + : TimerTask(when), expiryPolicy(policy), expiryId(id) {} + void fire() { expiryPolicy->sendExpire(expiryId); } boost::intrusive_ptr<ExpiryPolicy> expiryPolicy; - const uint64_t messageId; + const uint64_t expiryId; }; -} void ExpiryPolicy::willExpire(broker::Message& m) { - timer.add(new ExpiryTask(this, clusterId(m), m.getExpiration())); + uint64_t id = expiryId++; + assert(unexpiredById.find(id) == unexpiredById.end()); + assert(unexpiredByMessage.find(&m) == unexpiredByMessage.end()); + unexpiredById[id] = &m; + unexpiredByMessage[&m] = id; + timer.add(new ExpiryTask(this, id, m.getExpiration())); } bool ExpiryPolicy::hasExpired(broker::Message& m) { - sys::Mutex::ScopedLock l(lock); - IdSet::iterator i = expired.find(clusterId(m)); - if (i != expired.end()) { - expired.erase(i); - const_cast<broker::Message&>(m).setExpiryPolicy(expiredPolicy); // hasExpired() == true; - return true; - } - return false; + return unexpiredByMessage.find(&m) == unexpiredByMessage.end(); } void ExpiryPolicy::sendExpire(uint64_t id) { - sys::Mutex::ScopedLock l(lock); - if (isLeader()) - mcast.mcastControl(framing::ClusterMessageExpiredBody(framing::ProtocolVersion(), id), memberId); + mcast.mcastControl(framing::ClusterMessageExpiredBody(framing::ProtocolVersion(), id), memberId); } void ExpiryPolicy::deliverExpire(uint64_t id) { - sys::Mutex::ScopedLock l(lock); - expired.insert(id); + IdMessageMap::iterator i = unexpiredById.find(id); + if (i != unexpiredById.end()) { + i->second->setExpiryPolicy(expiredPolicy); // hasExpired() == true; + unexpiredByMessage.erase(i->second); + unexpiredById.erase(i); + } +} + +boost::optional<uint64_t> ExpiryPolicy::getId(broker::Message& m) { + MessageIdMap::iterator i = unexpiredByMessage.find(&m); + return i == unexpiredByMessage.end() ? boost::optional<uint64_t>() : i->second; } bool ExpiryPolicy::Expired::hasExpired(broker::Message&) { return true; } diff --git a/qpid/cpp/src/qpid/cluster/ExpiryPolicy.h b/qpid/cpp/src/qpid/cluster/ExpiryPolicy.h index 7fb63c731e..9f8b1a9236 100644 --- a/qpid/cpp/src/qpid/cluster/ExpiryPolicy.h +++ b/qpid/cpp/src/qpid/cluster/ExpiryPolicy.h @@ -27,11 +27,15 @@ #include "qpid/sys/Mutex.h" #include <boost/function.hpp> #include <boost/intrusive_ptr.hpp> -#include <set> +#include <boost/optional.hpp> +#include <map> namespace qpid { -namespace broker { class Timer; } +namespace broker { +class Timer; +class Message; +} namespace cluster { class Multicaster; @@ -42,7 +46,7 @@ class Multicaster; class ExpiryPolicy : public broker::ExpiryPolicy { public: - ExpiryPolicy(const boost::function<bool()> & isLeader, Multicaster&, const MemberId&, broker::Timer&); + ExpiryPolicy(Multicaster&, const MemberId&, broker::Timer&); void willExpire(broker::Message&); @@ -54,18 +58,24 @@ class ExpiryPolicy : public broker::ExpiryPolicy // Cluster delivers expiry notice. void deliverExpire(uint64_t); + void setId(uint64_t id) { expiryId = id; } + uint64_t getId() const { return expiryId; } + + boost::optional<uint64_t> getId(broker::Message&); + private: - sys::Mutex lock; - typedef std::set<uint64_t> IdSet; + typedef std::map<broker::Message*, uint64_t> MessageIdMap; + typedef std::map<uint64_t, broker::Message*> IdMessageMap; struct Expired : public broker::ExpiryPolicy { bool hasExpired(broker::Message&); void willExpire(broker::Message&); }; - IdSet expired; + MessageIdMap unexpiredByMessage; + IdMessageMap unexpiredById; + uint64_t expiryId; boost::intrusive_ptr<Expired> expiredPolicy; - boost::function<bool()> isLeader; Multicaster& mcast; MemberId memberId; broker::Timer& timer; diff --git a/qpid/cpp/src/qpid/cluster/ConnectionDecoder.h b/qpid/cpp/src/qpid/cluster/LockedConnectionMap.h index 449387c1cc..8b2f6dae8e 100644 --- a/qpid/cpp/src/qpid/cluster/ConnectionDecoder.h +++ b/qpid/cpp/src/qpid/cluster/LockedConnectionMap.h @@ -1,5 +1,5 @@ -#ifndef QPID_CLUSTER_CONNECTIONDECODER_H -#define QPID_CLUSTER_CONNECTIONDECODER_H +#ifndef QPID_CLUSTER_LOCKEDCONNECTIONMAP_H +#define QPID_CLUSTER_LOCKEDCONNECTIONMAP_H /* * @@ -22,40 +22,41 @@ * */ -#include "qpid/framing/FrameDecoder.h" -#include <boost/function.hpp> +#include "types.h" +#include "qpid/sys/Mutex.h" +#include "Connection.h" namespace qpid { namespace cluster { -class EventHeader; -class EventFrame; -class ConnectionMap; - /** - * Decodes delivered connection data Event's as EventFrame's for a - * connection replica, local or shadow. Manages state for frame - * fragments and flow control. - * - * THREAD UNSAFE: connection events are decoded in sequence. + * Thread safe map of connections. */ -class ConnectionDecoder +class LockedConnectionMap { public: - typedef boost::function<void(const EventFrame&)> Handler; - - ConnectionDecoder(const Handler& h); - - /** Takes EventHeader + data rather than Event so that the caller can - * pass a pointer to connection data or a CPG buffer directly without copy. - */ - void decode(const EventHeader& eh, const void* data, ConnectionMap& connections); + void insert(const ConnectionPtr& c) { + sys::Mutex::ScopedLock l(lock); + map[c->getId()] = c; + } + + ConnectionPtr getErase(const ConnectionId& c) { + sys::Mutex::ScopedLock l(lock); + Map::iterator i = map.find(c); + if (i != map.end()) { + ConnectionPtr cp = i->second; + map.erase(i); + return cp; + } + else + return 0; + } private: - Handler handler; - framing::FrameDecoder decoder; + typedef std::map<ConnectionId, ConnectionPtr> Map; + mutable sys::Mutex lock; + Map map; }; - }} // namespace qpid::cluster -#endif /*!QPID_CLUSTER_CONNECTIONDECODER_H*/ +#endif /*!QPID_CLUSTER_LOCKEDCONNECTIONMAP_H*/ diff --git a/qpid/cpp/src/qpid/sys/posix/PollableCondition.h b/qpid/cpp/src/qpid/cluster/McastFrameHandler.h index 4ec277b0ec..5127c31c84 100644 --- a/qpid/cpp/src/qpid/sys/posix/PollableCondition.h +++ b/qpid/cpp/src/qpid/cluster/McastFrameHandler.h @@ -1,5 +1,5 @@ -#ifndef QPID_SYS_POSIX_POLLABLECONDITION_H -#define QPID_SYS_POSIX_POLLABLECONDITION_H +#ifndef QPID_CLUSTER_MCASTFRAMEHANDLER_H +#define QPID_CLUSTER_MCASTFRAMEHANDLER_H /* * @@ -22,35 +22,25 @@ * */ -#include "qpid/sys/IOHandle.h" +#include "types.h" +#include "Multicaster.h" +#include "qpid/framing/FrameHandler.h" namespace qpid { -namespace sys { +namespace cluster { /** - * A pollable condition to integrate in-process conditions with IO - * conditions in a polling loop. - * - * Setting the condition makes it readable for a poller. - * - * Writable/disconnected conditions are undefined and should not be - * polled for. + * A frame handler that multicasts frames as CONTROL events. */ -class PollableCondition : public sys::IOHandle { +class McastFrameHandler : public framing::FrameHandler +{ public: - PollableCondition(); - - /** Set the condition, triggers readable in a poller. */ - void set(); - - /** Get the current state of the condition, then clear it. - *@return The state of the condition before it was cleared. - */ - bool clear(); - + McastFrameHandler(Multicaster& m, const ConnectionId& cid) : mcast(m), connection(cid) {} + void handle(framing::AMQFrame& frame) { mcast.mcastControl(frame, connection); } private: - int writeFd; + Multicaster& mcast; + ConnectionId connection; }; -}} // namespace qpid::sys +}} // namespace qpid::cluster -#endif /*!QPID_SYS_POSIX_POLLABLECONDITION_H*/ +#endif /*!QPID_CLUSTER_MCASTFRAMEHANDLER_H*/ diff --git a/qpid/cpp/src/qpid/cluster/Multicaster.cpp b/qpid/cpp/src/qpid/cluster/Multicaster.cpp index 239b3f5f35..f0738ab08f 100644 --- a/qpid/cpp/src/qpid/cluster/Multicaster.cpp +++ b/qpid/cpp/src/qpid/cluster/Multicaster.cpp @@ -24,6 +24,7 @@ #include "qpid/log/Statement.h" #include "qpid/sys/LatencyMetric.h" #include "qpid/framing/AMQBody.h" +#include "qpid/framing/AMQFrame.h" namespace qpid { namespace cluster { @@ -43,6 +44,11 @@ void Multicaster::mcastControl(const framing::AMQBody& body, const ConnectionId& mcast(Event::control(body, id)); } +void Multicaster::mcastControl(const framing::AMQFrame& frame, const ConnectionId& id) { + QPID_LOG(trace, "MCAST " << id << ": " << frame); + mcast(Event::control(frame, id)); +} + void Multicaster::mcastBuffer(const char* data, size_t size, const ConnectionId& id) { Event e(DATA, id, size); memcpy(e.getData(), data, size); diff --git a/qpid/cpp/src/qpid/cluster/Multicaster.h b/qpid/cpp/src/qpid/cluster/Multicaster.h index 1dfee47bd5..d1c3115977 100644 --- a/qpid/cpp/src/qpid/cluster/Multicaster.h +++ b/qpid/cpp/src/qpid/cluster/Multicaster.h @@ -50,6 +50,7 @@ class Multicaster boost::function<void()> onError ); void mcastControl(const framing::AMQBody& controlBody, const ConnectionId&); + void mcastControl(const framing::AMQFrame& controlFrame, const ConnectionId&); void mcastBuffer(const char*, size_t, const ConnectionId&); void mcast(const Event& e); /** End holding mode, held events are mcast */ diff --git a/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp b/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp index 45a369eea9..cd42446016 100644 --- a/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp +++ b/qpid/cpp/src/qpid/cluster/OutputInterceptor.cpp @@ -70,17 +70,12 @@ void OutputInterceptor::giveReadCredit(int32_t credit) { // Called in write thread when the IO layer has no more data to write. // We do nothing in the write thread, we run doOutput only on delivery // of doOutput requests. -bool OutputInterceptor::doOutput() { - QPID_LOG(trace, parent << " write idle."); - return false; -} +bool OutputInterceptor::doOutput() { return false; } // Delivery of doOutput allows us to run the real connection doOutput() // which tranfers frames to the codec for writing. // void OutputInterceptor::deliverDoOutput(size_t requested) { - QPID_LATENCY_RECORD("deliver do-output", *this); - QPID_LATENCY_CLEAR(*this); size_t buf = getBuffered(); if (parent.isLocal()) writeEstimate.delivered(requested, sent, buf); // Update the estimate. @@ -91,9 +86,7 @@ void OutputInterceptor::deliverDoOutput(size_t requested) { moreOutput = parent.getBrokerConnection().doOutput(); } while (sent < requested && moreOutput); sent += buf; // Include buffered data in the sent total. - - QPID_LOG(trace, "Delivered doOutput: requested=" << requested << " output=" << sent << " more=" << moreOutput); - + QPID_LOG(trace, parent << " delivereDoOutput: requested=" << requested << " sent=" << sent << " more=" << moreOutput); if (parent.isLocal() && moreOutput) { QPID_LOG(trace, parent << " deliverDoOutput - sending doOutput, more output available."); sendDoOutput(); diff --git a/qpid/cpp/src/qpid/cluster/PollableQueue.h b/qpid/cpp/src/qpid/cluster/PollableQueue.h index e0422e2449..a44c39ad85 100644 --- a/qpid/cpp/src/qpid/cluster/PollableQueue.h +++ b/qpid/cpp/src/qpid/cluster/PollableQueue.h @@ -52,6 +52,8 @@ template <class T> class PollableQueue : public sys::PollableQueue<T> { } catch (const std::exception& e) { QPID_LOG(error, message << ": " << e.what()); + values.clear(); + this->stop(); error(); } } diff --git a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp index 18746ccb7e..97eae7efa3 100644 --- a/qpid/cpp/src/qpid/cluster/UpdateClient.cpp +++ b/qpid/cpp/src/qpid/cluster/UpdateClient.cpp @@ -22,6 +22,8 @@ #include "Cluster.h" #include "ClusterMap.h" #include "Connection.h" +#include "Decoder.h" +#include "ExpiryPolicy.h" #include "qpid/client/SessionBase_0_10Access.h" #include "qpid/client/ConnectionAccess.h" #include "qpid/broker/Broker.h" @@ -86,33 +88,40 @@ void send(client::AsyncSession& s, const AMQBody& body) { // TODO aconway 2008-09-24: optimization: update connections/sessions in parallel. UpdateClient::UpdateClient(const MemberId& updater, const MemberId& updatee, const Url& url, - broker::Broker& broker, const ClusterMap& m, uint64_t frameId_, - const Cluster::Connections& cons, + broker::Broker& broker, const ClusterMap& m, ExpiryPolicy& expiry_, + const Cluster::ConnectionVector& cons, Decoder& decoder_, const boost::function<void()>& ok, const boost::function<void(const std::exception&)>& fail, const client::ConnectionSettings& cs ) : updaterId(updater), updateeId(updatee), updateeUrl(url), updaterBroker(broker), map(m), - frameId(frameId_), connections(cons), + expiry(expiry_), connections(cons), decoder(decoder_), connection(catchUpConnection()), shadowConnection(catchUpConnection()), - done(ok), failed(fail) + done(ok), failed(fail), connectionSettings(cs) { connection.open(url, cs); - session = connection.newSession("update_shared"); + session = connection.newSession(UPDATE); } UpdateClient::~UpdateClient() {} // Reserved exchange/queue name for catch-up, avoid clashes with user queues/exchanges. -const std::string UpdateClient::UPDATE("qpid.qpid-update"); +const std::string UpdateClient::UPDATE("qpid.cluster-update"); + +void UpdateClient::run() { + try { + update(); + done(); + } catch (const std::exception& e) { + failed(e); + } + delete this; +} void UpdateClient::update() { QPID_LOG(debug, updaterId << " updating state to " << updateeId << " at " << updateeUrl); Broker& b = updaterBroker; b.getExchanges().eachExchange(boost::bind(&UpdateClient::updateExchange, this, _1)); - - // Update exchange is used to route messages to the proper queue without modifying routing key. - session.exchangeDeclare(arg::exchange=UPDATE, arg::type="fanout", arg::autoDelete=true); b.getQueues().eachQueue(boost::bind(&UpdateClient::updateQueue, this, _1)); // Update queue is used to transfer acquired messages that are no longer on their original queue. session.queueDeclare(arg::queue=UPDATE, arg::autoDelete=true); @@ -121,25 +130,15 @@ void UpdateClient::update() { std::for_each(connections.begin(), connections.end(), boost::bind(&UpdateClient::updateConnection, this, _1)); + ClusterConnectionProxy(session).expiryId(expiry.getId()); ClusterConnectionMembershipBody membership; map.toMethodBody(membership); - membership.setFrameId(frameId); AMQFrame frame(membership); client::ConnectionAccess::getImpl(connection)->handle(frame); connection.close(); QPID_LOG(debug, updaterId << " updated state to " << updateeId << " at " << updateeUrl); } -void UpdateClient::run() { - try { - update(); - done(); - } catch (const std::exception& e) { - failed(e); - } - delete this; -} - namespace { template <class T> std::string encode(const T& t) { std::string encoded; @@ -152,8 +151,7 @@ template <class T> std::string encode(const T& t) { void UpdateClient::updateExchange(const boost::shared_ptr<Exchange>& ex) { QPID_LOG(debug, updaterId << " updating exchange " << ex->getName()); - ClusterConnectionProxy proxy(session); - proxy.exchange(encode(*ex)); + ClusterConnectionProxy(session).exchange(encode(*ex)); } /** Bind a queue to the update exchange and update messges to it @@ -164,24 +162,40 @@ class MessageUpdater { bool haveLastPos; framing::SequenceNumber lastPos; client::AsyncSession session; - + ExpiryPolicy& expiry; + public: - MessageUpdater(const string& q, const client::AsyncSession s) : queue(q), haveLastPos(false), session(s) { + MessageUpdater(const string& q, const client::AsyncSession s, ExpiryPolicy& expiry_) : queue(q), haveLastPos(false), session(s), expiry(expiry_) { session.exchangeBind(queue, UpdateClient::UPDATE); } ~MessageUpdater() { - session.exchangeUnbind(queue, UpdateClient::UPDATE); + try { + session.exchangeUnbind(queue, UpdateClient::UPDATE); + } + catch (const std::exception& e) { + // Don't throw in a destructor. + QPID_LOG(error, "Unbinding update queue " << queue << ": " << e.what()); + } } void updateQueuedMessage(const broker::QueuedMessage& message) { + // Send the queue position if necessary. if (!haveLastPos || message.position - lastPos != 1) { ClusterConnectionProxy(session).queuePosition(queue, message.position.getValue()-1); haveLastPos = true; } lastPos = message.position; + + // Send the expiry ID if necessary. + if (message.payload->getProperties<DeliveryProperties>()->getTtl()) { + boost::optional<uint64_t> expiryId = expiry.getId(*message.payload); + if (!expiryId) return; // Message already expired, don't replicate. + ClusterConnectionProxy(session).expiryId(*expiryId); + } + SessionBase_0_10Access sb(session); framing::MessageTransferBody transfer( framing::ProtocolVersion(), UpdateClient::UPDATE, message::ACCEPT_MODE_NONE, message::ACQUIRE_MODE_PRE_ACQUIRED); @@ -204,16 +218,13 @@ class MessageUpdater { void updateMessage(const boost::intrusive_ptr<broker::Message>& message) { updateQueuedMessage(broker::QueuedMessage(0, message, haveLastPos? lastPos.getValue()+1 : 1)); } - - }; - void UpdateClient::updateQueue(const boost::shared_ptr<Queue>& q) { QPID_LOG(debug, updaterId << " updating queue " << q->getName()); ClusterConnectionProxy proxy(session); proxy.queue(encode(*q)); - MessageUpdater updater(q->getName(), session); + MessageUpdater updater(q->getName(), session, expiry); q->eachMessage(boost::bind(&MessageUpdater::updateQueuedMessage, &updater, _1)); q->eachBinding(boost::bind(&UpdateClient::updateBinding, this, q->getName(), _1)); } @@ -228,13 +239,16 @@ void UpdateClient::updateConnection(const boost::intrusive_ptr<Connection>& upda shadowConnection = catchUpConnection(); broker::Connection& bc = updateConnection->getBrokerConnection(); - // FIXME aconway 2008-10-20: What authentication info to use on reconnect? - shadowConnection.open(updateeUrl, bc.getUserId(), ""/*password*/, "/"/*vhost*/, bc.getFrameMax()); + connectionSettings.maxFrameSize = bc.getFrameMax(); + shadowConnection.open(updateeUrl, connectionSettings); bc.eachSessionHandler(boost::bind(&UpdateClient::updateSession, this, _1)); + // Safe to use decoder here because we are stalled for update. + std::pair<const char*, size_t> fragment = decoder.get(updateConnection->getId()).getFragment(); ClusterConnectionProxy(shadowConnection).shadowReady( updateConnection->getId().getMember(), - reinterpret_cast<uint64_t>(updateConnection->getId().getPointer()), - updateConnection->getBrokerConnection().getUserId() + updateConnection->getId().getNumber(), + bc.getUserId(), + string(fragment.first, fragment.second) ); shadowConnection.close(); QPID_LOG(debug, updaterId << " updated connection " << *updateConnection); @@ -269,7 +283,7 @@ void UpdateClient::updateSession(broker::SessionHandler& sh) { SequenceNumber received = ss->receiverGetReceived().command; if (inProgress) --received; - + // Reset command-sequence state. proxy.sessionState( ss->senderGetReplayPoint().command, @@ -285,9 +299,6 @@ void UpdateClient::updateSession(broker::SessionHandler& sh) { if (inProgress) { inProgress->getFrames().map(simpl->out); } - - // FIXME aconway 2008-09-23: update session replay list. - QPID_LOG(debug, updaterId << " updated session " << sh.getSession()->getId()); } @@ -322,7 +333,7 @@ void UpdateClient::updateUnacked(const broker::DeliveryRecord& dr) { // If the message is acquired then it is no longer on the // updatees queue, put it on the update queue for updatee to pick up. // - MessageUpdater(UPDATE, shadowSession).updateQueuedMessage(dr.getMessage()); + MessageUpdater(UPDATE, shadowSession, expiry).updateQueuedMessage(dr.getMessage()); } ClusterConnectionProxy(shadowSession).deliveryRecord( dr.getQueue()->getName(), @@ -341,8 +352,8 @@ void UpdateClient::updateUnacked(const broker::DeliveryRecord& dr) { class TxOpUpdater : public broker::TxOpConstVisitor, public MessageUpdater { public: - TxOpUpdater(UpdateClient& dc, client::AsyncSession s) - : MessageUpdater(UpdateClient::UPDATE, s), parent(dc), session(s), proxy(s) {} + TxOpUpdater(UpdateClient& dc, client::AsyncSession s, ExpiryPolicy& expiry) + : MessageUpdater(UpdateClient::UPDATE, s, expiry), parent(dc), session(s), proxy(s) {} void operator()(const broker::DtxAck& ) { throw InternalErrorException("DTX transactions not currently supported by cluster."); @@ -385,7 +396,7 @@ void UpdateClient::updateTxState(broker::SemanticState& s) { broker::TxBuffer::shared_ptr txBuffer = s.getTxBuffer(); if (txBuffer) { proxy.txStart(); - TxOpUpdater updater(*this, shadowSession); + TxOpUpdater updater(*this, shadowSession, expiry); txBuffer->accept(updater); proxy.txEnd(); } diff --git a/qpid/cpp/src/qpid/cluster/UpdateClient.h b/qpid/cpp/src/qpid/cluster/UpdateClient.h index 23f647c820..23d061b7e4 100644 --- a/qpid/cpp/src/qpid/cluster/UpdateClient.h +++ b/qpid/cpp/src/qpid/cluster/UpdateClient.h @@ -46,6 +46,7 @@ class SessionHandler; class DeliveryRecord; class SessionState; class SemanticState; +class Decoder; } // namespace broker @@ -54,6 +55,8 @@ namespace cluster { class Cluster; class Connection; class ClusterMap; +class Decoder; +class ExpiryPolicy; /** * A client that updates the contents of a local broker to a remote one using AMQP. @@ -63,8 +66,8 @@ class UpdateClient : public sys::Runnable { static const std::string UPDATE; // Name for special update queue and exchange. UpdateClient(const MemberId& updater, const MemberId& updatee, const Url&, - broker::Broker& donor, const ClusterMap& map, uint64_t sequence, - const std::vector<boost::intrusive_ptr<Connection> >& , + broker::Broker& donor, const ClusterMap& map, ExpiryPolicy& expiry, + const std::vector<boost::intrusive_ptr<Connection> >&, Decoder&, const boost::function<void()>& done, const boost::function<void(const std::exception&)>& fail, const client::ConnectionSettings& @@ -92,12 +95,14 @@ class UpdateClient : public sys::Runnable { Url updateeUrl; broker::Broker& updaterBroker; ClusterMap map; - uint64_t frameId; + ExpiryPolicy& expiry; std::vector<boost::intrusive_ptr<Connection> > connections; + Decoder& decoder; client::Connection connection, shadowConnection; client::AsyncSession session, shadowSession; boost::function<void()> done; boost::function<void(const std::exception& e)> failed; + client::ConnectionSettings connectionSettings; }; }} // namespace qpid::cluster diff --git a/qpid/cpp/src/qpid/cluster/UpdateExchange.h b/qpid/cpp/src/qpid/cluster/UpdateExchange.h new file mode 100644 index 0000000000..7a4a484c8a --- /dev/null +++ b/qpid/cpp/src/qpid/cluster/UpdateExchange.h @@ -0,0 +1,45 @@ +#ifndef QPID_CLUSTER_UPDATEEXCHANGE_H +#define QPID_CLUSTER_UPDATEEXCHANGE_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "UpdateClient.h" +#include "qpid/broker/FanOutExchange.h" + + +namespace qpid { +namespace cluster { + +/** + * A keyless exchange (like fanout exchange) that does not modify deliver-properties.exchange + * on messages. + */ +class UpdateExchange : public broker::FanOutExchange +{ + public: + UpdateExchange(management::Manageable* parent) : broker::Exchange(UpdateClient::UPDATE, parent), broker::FanOutExchange(UpdateClient::UPDATE, parent) {} + void setProperties(const boost::intrusive_ptr<broker::Message>&) {} +}; + +}} // namespace qpid::cluster + +#endif /*!QPID_CLUSTER_UPDATEEXCHANGE_H*/ diff --git a/qpid/cpp/src/qpid/cluster/types.h b/qpid/cpp/src/qpid/cluster/types.h index d1d6fdc427..c19152e4d8 100644 --- a/qpid/cpp/src/qpid/cluster/types.h +++ b/qpid/cpp/src/qpid/cluster/types.h @@ -68,16 +68,17 @@ inline bool operator==(const cpg_address& caddr, const MemberId& id) { return id std::ostream& operator<<(std::ostream&, const MemberId&); -struct ConnectionId : public std::pair<MemberId, Connection*> { - ConnectionId(const MemberId& m=MemberId(), Connection* c=0) : std::pair<MemberId, Connection*> (m,c) {} - ConnectionId(uint64_t m, uint64_t c) - : std::pair<MemberId, Connection*>(MemberId(m), reinterpret_cast<Connection*>(c)) {} +struct ConnectionId : public std::pair<MemberId, uint64_t> { + ConnectionId(const MemberId& m=MemberId(), uint64_t c=0) : std::pair<MemberId, uint64_t> (m,c) {} + ConnectionId(uint64_t m, uint64_t c) : std::pair<MemberId, uint64_t>(MemberId(m), c) {} MemberId getMember() const { return first; } - Connection* getPointer() const { return second; } + uint64_t getNumber() const { return second; } }; std::ostream& operator<<(std::ostream&, const ConnectionId&); +std::ostream& operator<<(std::ostream&, EventType); + }} // namespace qpid::cluster #endif /*!QPID_CLUSTER_TYPES_H*/ diff --git a/qpid/cpp/src/qpid/console/Agent.h b/qpid/cpp/src/qpid/console/Agent.h index 3307a1b44b..884d4c92bd 100644 --- a/qpid/cpp/src/qpid/console/Agent.h +++ b/qpid/cpp/src/qpid/console/Agent.h @@ -22,6 +22,7 @@ #define _QPID_CONSOLE_AGENT_H_ #include "Broker.h" +#include "ConsoleImportExport.h" namespace qpid { namespace console { @@ -30,7 +31,7 @@ namespace console { * * \ingroup qmfconsoleapi */ - class Agent { + class QPID_CONSOLE_EXTERN Agent { public: typedef std::vector<Agent*> Vector; @@ -49,7 +50,7 @@ namespace console { const std::string label; }; - std::ostream& operator<<(std::ostream& o, const Agent& agent); + QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Agent& agent); } } diff --git a/qpid/cpp/src/qpid/console/Broker.h b/qpid/cpp/src/qpid/console/Broker.h index 9df2380dff..ddbd973dfe 100644 --- a/qpid/cpp/src/qpid/console/Broker.h +++ b/qpid/cpp/src/qpid/console/Broker.h @@ -21,6 +21,7 @@ #ifndef _QPID_CONSOLE_BROKER_H_ #define _QPID_CONSOLE_BROKER_H_ +#include "ConsoleImportExport.h" #include "qpid/client/Connection.h" #include "qpid/client/ConnectionSettings.h" #include "qpid/client/SubscriptionManager.h" @@ -50,8 +51,9 @@ namespace console { */ class Broker : public client::MessageListener { public: - Broker(SessionManager& sm, client::ConnectionSettings& settings); - ~Broker(); + QPID_CONSOLE_EXTERN Broker(SessionManager& sm, + client::ConnectionSettings& settings); + QPID_CONSOLE_EXTERN ~Broker(); bool isConnected() const { return connected; } const std::string& getError() const { return error; } @@ -61,7 +63,7 @@ namespace console { void addBinding(const std::string& key) { connThreadBody.bindExchange("qpid.management", key); } - std::string getUrl() const; + QPID_CONSOLE_EXTERN std::string getUrl() const; private: friend class SessionManager; @@ -120,10 +122,10 @@ namespace console { void setBrokerId(const framing::Uuid& id) { brokerId = id; } void appendAgents(std::vector<Agent*>& agents) const; - friend std::ostream& operator<<(std::ostream& o, const Broker& k); + friend QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Broker& k); }; - std::ostream& operator<<(std::ostream& o, const Broker& k); + QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Broker& k); } } diff --git a/qpid/cpp/src/qpid/console/ClassKey.cpp b/qpid/cpp/src/qpid/console/ClassKey.cpp index 1780b03f94..b97eb3ca44 100644 --- a/qpid/cpp/src/qpid/console/ClassKey.cpp +++ b/qpid/cpp/src/qpid/console/ClassKey.cpp @@ -21,6 +21,7 @@ #include "ClassKey.h" #include <string.h> +#include <cstdio> using namespace std; using namespace qpid::console; diff --git a/qpid/cpp/src/qpid/console/ClassKey.h b/qpid/cpp/src/qpid/console/ClassKey.h index f6617e22d5..821b01c4ef 100644 --- a/qpid/cpp/src/qpid/console/ClassKey.h +++ b/qpid/cpp/src/qpid/console/ClassKey.h @@ -22,6 +22,7 @@ #define _QPID_CONSOLE_CLASSKEY_H_ #include <string> +#include "ConsoleImportExport.h" #include "Package.h" #include "qpid/framing/Buffer.h" @@ -32,7 +33,7 @@ namespace console { * * \ingroup qmfconsoleapi */ - class ClassKey { + class QPID_CONSOLE_EXTERN ClassKey { public: static const int HASH_SIZE = 16; @@ -57,7 +58,7 @@ namespace console { uint8_t hash[HASH_SIZE]; }; - std::ostream& operator<<(std::ostream& o, const ClassKey& k); + QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const ClassKey& k); } } diff --git a/qpid/cpp/src/qpid/console/ConsoleImportExport.h b/qpid/cpp/src/qpid/console/ConsoleImportExport.h new file mode 100644 index 0000000000..e2d0af9db3 --- /dev/null +++ b/qpid/cpp/src/qpid/console/ConsoleImportExport.h @@ -0,0 +1,33 @@ +#ifndef QPID_CONSOLE_IMPORT_EXPORT_H +#define QPID_CONSOLE_IMPORT_EXPORT_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. + */ + +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) +#if defined(CONSOLE_EXPORT) +#define QPID_CONSOLE_EXTERN __declspec(dllexport) +#else +#define QPID_CONSOLE_EXTERN __declspec(dllimport) +#endif +#else +#define QPID_CONSOLE_EXTERN +#endif + +#endif diff --git a/qpid/cpp/src/qpid/console/ConsoleListener.h b/qpid/cpp/src/qpid/console/ConsoleListener.h index d0db6034f6..d661c63120 100644 --- a/qpid/cpp/src/qpid/console/ConsoleListener.h +++ b/qpid/cpp/src/qpid/console/ConsoleListener.h @@ -22,6 +22,7 @@ #define _QPID_CONSOLE_CONSOLE_LISTENER_H_ #include <string> +#include "ConsoleImportExport.h" #include "Broker.h" #include "ClassKey.h" #include "Object.h" @@ -36,7 +37,7 @@ namespace console { * * \ingroup qmfconsoleapi */ - class ConsoleListener{ + class QPID_CONSOLE_EXTERN ConsoleListener{ public: virtual ~ConsoleListener() {}; diff --git a/qpid/cpp/src/qpid/console/Event.h b/qpid/cpp/src/qpid/console/Event.h index 14f5a64716..4d51708965 100644 --- a/qpid/cpp/src/qpid/console/Event.h +++ b/qpid/cpp/src/qpid/console/Event.h @@ -21,6 +21,7 @@ #ifndef _QPID_CONSOLE_EVENT_H_ #define _QPID_CONSOLE_EVENT_H_ +#include "ConsoleImportExport.h" #include "Object.h" #include "qpid/framing/Uuid.h" #include "qpid/framing/FieldTable.h" @@ -46,26 +47,28 @@ namespace console { SEV_WARNING = 4, SEV_NOTICE = 5, SEV_INFO = 6, SEV_DEBUG = 7 } Severity; - Event(Broker* broker, SchemaClass* schemaClass, framing::Buffer& buffer); + QPID_CONSOLE_EXTERN Event(Broker* broker, + SchemaClass* schemaClass, + framing::Buffer& buffer); Broker* getBroker() const { return broker; } - const ClassKey& getClassKey() const; + QPID_CONSOLE_EXTERN const ClassKey& getClassKey() const; SchemaClass* getSchema() const { return schema; } const Object::AttributeMap& getAttributes() const { return attributes; } uint64_t getTimestamp() const { return timestamp; } uint8_t getSeverity() const { return severity; } - std::string getSeverityString() const; + QPID_CONSOLE_EXTERN std::string getSeverityString() const; - ObjectId attrRef(const std::string& key) const; - uint32_t attrUint(const std::string& key) const; - int32_t attrInt(const std::string& key) const; - uint64_t attrUint64(const std::string& key) const; - int64_t attrInt64(const std::string& key) const; - std::string attrString(const std::string& key) const; - bool attrBool(const std::string& key) const; - float attrFloat(const std::string& key) const; - double attrDouble(const std::string& key) const; - framing::Uuid attrUuid(const std::string& key) const; - framing::FieldTable attrMap(const std::string& key) const; + QPID_CONSOLE_EXTERN ObjectId attrRef(const std::string& key) const; + QPID_CONSOLE_EXTERN uint32_t attrUint(const std::string& key) const; + QPID_CONSOLE_EXTERN int32_t attrInt(const std::string& key) const; + QPID_CONSOLE_EXTERN uint64_t attrUint64(const std::string& key) const; + QPID_CONSOLE_EXTERN int64_t attrInt64(const std::string& key) const; + QPID_CONSOLE_EXTERN std::string attrString(const std::string& key) const; + QPID_CONSOLE_EXTERN bool attrBool(const std::string& key) const; + QPID_CONSOLE_EXTERN float attrFloat(const std::string& key) const; + QPID_CONSOLE_EXTERN double attrDouble(const std::string& key) const; + QPID_CONSOLE_EXTERN framing::Uuid attrUuid(const std::string& key) const; + QPID_CONSOLE_EXTERN framing::FieldTable attrMap(const std::string& key) const; private: Broker* broker; @@ -75,7 +78,7 @@ namespace console { Object::AttributeMap attributes; }; - std::ostream& operator<<(std::ostream& o, const Event& event); + QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Event& event); } } diff --git a/qpid/cpp/src/qpid/console/Object.h b/qpid/cpp/src/qpid/console/Object.h index 2c6993fc8a..d2fb09ecca 100644 --- a/qpid/cpp/src/qpid/console/Object.h +++ b/qpid/cpp/src/qpid/console/Object.h @@ -21,6 +21,7 @@ #ifndef _QPID_CONSOLE_OBJECT_H_ #define _QPID_CONSOLE_OBJECT_H_ +#include "ConsoleImportExport.h" #include "ObjectId.h" #include "qpid/framing/Uuid.h" #include "qpid/framing/FieldTable.h" @@ -55,47 +56,50 @@ namespace console { public: typedef std::vector<Object> Vector; struct AttributeMap : public std::map<std::string, boost::shared_ptr<Value> > { - void addRef(const std::string& key, const ObjectId& val); - void addUint(const std::string& key, uint32_t val); - void addInt(const std::string& key, int32_t val); - void addUint64(const std::string& key, uint64_t val); - void addInt64(const std::string& key, int64_t val); - void addString(const std::string& key, const std::string& val); - void addBool(const std::string& key, bool val); - void addFloat(const std::string& key, float val); - void addDouble(const std::string& key, double val); - void addUuid(const std::string& key, const framing::Uuid& val); - void addMap(const std::string& key, const framing::FieldTable& val); + QPID_CONSOLE_EXTERN void addRef(const std::string& key, const ObjectId& val); + QPID_CONSOLE_EXTERN void addUint(const std::string& key, uint32_t val); + QPID_CONSOLE_EXTERN void addInt(const std::string& key, int32_t val); + QPID_CONSOLE_EXTERN void addUint64(const std::string& key, uint64_t val); + QPID_CONSOLE_EXTERN void addInt64(const std::string& key, int64_t val); + QPID_CONSOLE_EXTERN void addString(const std::string& key, const std::string& val); + QPID_CONSOLE_EXTERN void addBool(const std::string& key, bool val); + QPID_CONSOLE_EXTERN void addFloat(const std::string& key, float val); + QPID_CONSOLE_EXTERN void addDouble(const std::string& key, double val); + QPID_CONSOLE_EXTERN void addUuid(const std::string& key, const framing::Uuid& val); + QPID_CONSOLE_EXTERN void addMap(const std::string& key, const framing::FieldTable& val); }; - Object(Broker* broker, SchemaClass* schemaClass, framing::Buffer& buffer, bool prop, bool stat); - ~Object(); + QPID_CONSOLE_EXTERN Object(Broker* broker, SchemaClass* schemaClass, framing::Buffer& buffer, bool prop, bool stat); + QPID_CONSOLE_EXTERN ~Object(); Broker* getBroker() const { return broker; } const ObjectId& getObjectId() const { return objectId; } - const ClassKey& getClassKey() const; + QPID_CONSOLE_EXTERN const ClassKey& getClassKey() const; SchemaClass* getSchema() const { return schema; } uint64_t getCurrentTime() const { return currentTime; } uint64_t getCreateTime() const { return createTime; } uint64_t getDeleteTime() const { return deleteTime; } bool isDeleted() const { return deleteTime != 0; } - std::string getIndex() const; - void mergeUpdate(const Object& updated); + QPID_CONSOLE_EXTERN std::string getIndex() const; + QPID_CONSOLE_EXTERN void mergeUpdate(const Object& updated); const AttributeMap& getAttributes() const { return attributes; } - void invokeMethod(const std::string name, const AttributeMap& args, MethodResponse& result); - void handleMethodResp(framing::Buffer& buffer, uint32_t sequence); + QPID_CONSOLE_EXTERN void invokeMethod(const std::string name, + const AttributeMap& args, + MethodResponse& result); + QPID_CONSOLE_EXTERN void handleMethodResp(framing::Buffer& buffer, + uint32_t sequence); - ObjectId attrRef(const std::string& key) const; - uint32_t attrUint(const std::string& key) const; - int32_t attrInt(const std::string& key) const; - uint64_t attrUint64(const std::string& key) const; - int64_t attrInt64(const std::string& key) const; - std::string attrString(const std::string& key) const; - bool attrBool(const std::string& key) const; - float attrFloat(const std::string& key) const; - double attrDouble(const std::string& key) const; - framing::Uuid attrUuid(const std::string& key) const; - framing::FieldTable attrMap(const std::string& key) const; + QPID_CONSOLE_EXTERN ObjectId attrRef(const std::string& key) const; + QPID_CONSOLE_EXTERN uint32_t attrUint(const std::string& key) const; + QPID_CONSOLE_EXTERN int32_t attrInt(const std::string& key) const; + QPID_CONSOLE_EXTERN uint64_t attrUint64(const std::string& key) const; + QPID_CONSOLE_EXTERN int64_t attrInt64(const std::string& key) const; + QPID_CONSOLE_EXTERN std::string attrString(const std::string& key) const; + QPID_CONSOLE_EXTERN bool attrBool(const std::string& key) const; + QPID_CONSOLE_EXTERN float attrFloat(const std::string& key) const; + QPID_CONSOLE_EXTERN double attrDouble(const std::string& key) const; + QPID_CONSOLE_EXTERN framing::Uuid attrUuid(const std::string& key) const; + QPID_CONSOLE_EXTERN framing::FieldTable attrMap(const std::string& key) const; private: Broker* broker; @@ -111,7 +115,7 @@ namespace console { void parsePresenceMasks(framing::Buffer& buffer, std::set<std::string>& excludeList); }; - std::ostream& operator<<(std::ostream& o, const Object& object); + QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Object& object); } } diff --git a/qpid/cpp/src/qpid/console/ObjectId.h b/qpid/cpp/src/qpid/console/ObjectId.h index 73304ca306..ac0e8d8b03 100644 --- a/qpid/cpp/src/qpid/console/ObjectId.h +++ b/qpid/cpp/src/qpid/console/ObjectId.h @@ -22,6 +22,7 @@ #define _QPID_CONSOLE_OBJECTID_H #include <iostream> +#include "ConsoleImportExport.h" #include "qpid/sys/IntegerTypes.h" namespace qpid { @@ -34,7 +35,7 @@ namespace console { * * \ingroup qmfconsoleapi */ - class ObjectId { + class QPID_CONSOLE_EXTERN ObjectId { public: ObjectId() : first(0), second(0) {} ObjectId(framing::Buffer& buffer); @@ -61,7 +62,7 @@ namespace console { uint64_t second; }; - std::ostream& operator<<(std::ostream& o, const ObjectId& id); + QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const ObjectId& id); } } diff --git a/qpid/cpp/src/qpid/console/Package.h b/qpid/cpp/src/qpid/console/Package.h index 18203cb807..3cc63c8b75 100644 --- a/qpid/cpp/src/qpid/console/Package.h +++ b/qpid/cpp/src/qpid/console/Package.h @@ -23,6 +23,7 @@ #include <string> #include <map> +#include "ConsoleImportExport.h" #include "qpid/sys/IntegerTypes.h" namespace qpid { diff --git a/qpid/cpp/src/qpid/console/SequenceManager.h b/qpid/cpp/src/qpid/console/SequenceManager.h index c7a8c20fe6..5a041f530b 100644 --- a/qpid/cpp/src/qpid/console/SequenceManager.h +++ b/qpid/cpp/src/qpid/console/SequenceManager.h @@ -21,6 +21,7 @@ #ifndef _QPID_CONSOLE_SEQUENCEMANAGER_H_ #define _QPID_CONSOLE_SEQUENCEMANAGER_H_ +#include "ConsoleImportExport.h" #include "qpid/sys/Mutex.h" #include <map> #include <string> @@ -38,8 +39,8 @@ namespace console { typedef std::set<uint32_t> set; SequenceManager() : sequence(0) {} - uint32_t reserve(const std::string& context = ""); - std::string release(uint32_t seq); + QPID_CONSOLE_EXTERN uint32_t reserve(const std::string& context = ""); + QPID_CONSOLE_EXTERN std::string release(uint32_t seq); private: sys::Mutex lock; diff --git a/qpid/cpp/src/qpid/console/SessionManager.h b/qpid/cpp/src/qpid/console/SessionManager.h index ab6e111caa..4341fe317c 100644 --- a/qpid/cpp/src/qpid/console/SessionManager.h +++ b/qpid/cpp/src/qpid/console/SessionManager.h @@ -22,6 +22,7 @@ * */ +#include "ConsoleImportExport.h" #include "Broker.h" #include "Package.h" #include "SequenceManager.h" @@ -80,8 +81,8 @@ class SessionManager * and bindClass methods. If userBindings is false, the listener will receive * updates for all object classes. */ - SessionManager(ConsoleListener* listener = 0, - Settings settings = Settings()); + QPID_CONSOLE_EXTERN SessionManager(ConsoleListener* listener = 0, + Settings settings = Settings()); /** Connect a broker to the console session * @@ -89,32 +90,33 @@ class SessionManager *@return broker object if operation is successful * an exception shall be thrown. */ - Broker* addBroker(client::ConnectionSettings& settings); + QPID_CONSOLE_EXTERN Broker* addBroker(client::ConnectionSettings& settings); /** Disconnect a broker from the console session * *@param broker The broker object returned from an earlier call to addBroker. */ - void delBroker(Broker* broker); + QPID_CONSOLE_EXTERN void delBroker(Broker* broker); /** Get a list of known management packages * *@param packages Vector of package names returned by the session manager. */ - void getPackages(NameVector& packages); + QPID_CONSOLE_EXTERN void getPackages(NameVector& packages); /** Get a list of class keys associated with a package * *@param classKeys List of class keys returned by the session manager. *@param packageName Name of package being queried. */ - void getClasses(KeyVector& classKeys, const std::string& packageName); + QPID_CONSOLE_EXTERN void getClasses(KeyVector& classKeys, + const std::string& packageName); /** Get the schema of a class given its class key * *@param classKey Class key of the desired schema. */ - SchemaClass& getSchema(const ClassKey& classKey); + QPID_CONSOLE_EXTERN SchemaClass& getSchema(const ClassKey& classKey); /** Request that updates be received for all classes within a package * @@ -123,7 +125,7 @@ class SessionManager * *@param packageName Name of the package to which to bind. */ - void bindPackage(const std::string& packageName); + QPID_CONSOLE_EXTERN void bindPackage(const std::string& packageName); /** Request update to be received for a particular class * @@ -132,8 +134,9 @@ class SessionManager * *@param classKey Class key of class to which to bind. */ - void bindClass(const ClassKey& classKey); - void bindClass(const std::string& packageName, const std::string& className); + QPID_CONSOLE_EXTERN void bindClass(const ClassKey& classKey); + QPID_CONSOLE_EXTERN void bindClass(const std::string& packageName, + const std::string& className); /** Get a list of qmf agents known to the session manager. * @@ -141,7 +144,8 @@ class SessionManager *@param broker Return agents registered with this broker only. If NULL, return agents * from all connected brokers. */ - void getAgents(Agent::Vector& agents, Broker* broker = 0); + QPID_CONSOLE_EXTERN void getAgents(Agent::Vector& agents, + Broker* broker = 0); /** Get objects from agents. There are four variants of this method with different ways of * specifying from which class objects are being queried. @@ -153,8 +157,10 @@ class SessionManager *@param broker Restrict the query to this broker, or all brokers if NULL. *@param agent Restrict the query to this agent, or all agents if NULL. */ - void getObjects(Object::Vector& objects, const std::string& className, - Broker* broker = 0, Agent* agent = 0); + QPID_CONSOLE_EXTERN void getObjects(Object::Vector& objects, + const std::string& className, + Broker* broker = 0, + Agent* agent = 0); //void getObjects(Object::Vector& objects, const ClassKey& classKey, // Broker* broker = 0, Agent* agent = 0); //void getObjects(Object::Vector& objects, const ObjectId& objectId, diff --git a/qpid/cpp/src/qpid/framing/AMQBody.h b/qpid/cpp/src/qpid/framing/AMQBody.h index 9e66b9738f..60ac2d3b7e 100644 --- a/qpid/cpp/src/qpid/framing/AMQBody.h +++ b/qpid/cpp/src/qpid/framing/AMQBody.h @@ -26,6 +26,7 @@ #include "qpid/framing/BodyFactory.h" #include <boost/intrusive_ptr.hpp> #include <ostream> +#include "qpid/CommonImportExport.h" namespace qpid { namespace framing { @@ -48,7 +49,7 @@ struct AMQBodyConstVisitor { class AMQBody : public RefCounted { public: AMQBody() {} - virtual ~AMQBody(); + QPID_COMMON_EXTERN virtual ~AMQBody(); // Make AMQBody copyable even though RefCounted. AMQBody(const AMQBody&) : RefCounted() {} @@ -71,7 +72,7 @@ class AMQBody : public RefCounted { virtual boost::intrusive_ptr<AMQBody> clone() const = 0; }; -std::ostream& operator<<(std::ostream& out, const AMQBody& body) ; +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& out, const AMQBody& body) ; enum BodyTypes { METHOD_BODY = 1, diff --git a/qpid/cpp/src/qpid/framing/AMQContentBody.h b/qpid/cpp/src/qpid/framing/AMQContentBody.h index a81cf36168..9606ae5ec5 100644 --- a/qpid/cpp/src/qpid/framing/AMQContentBody.h +++ b/qpid/cpp/src/qpid/framing/AMQContentBody.h @@ -21,6 +21,7 @@ #include "amqp_types.h" #include "AMQBody.h" #include "Buffer.h" +#include "qpid/CommonImportExport.h" #ifndef _AMQContentBody_ #define _AMQContentBody_ @@ -33,18 +34,18 @@ class AMQContentBody : public AMQBody string data; public: - AMQContentBody(); - AMQContentBody(const string& data); + QPID_COMMON_EXTERN AMQContentBody(); + QPID_COMMON_EXTERN AMQContentBody(const string& data); inline virtual ~AMQContentBody(){} - inline uint8_t type() const { return CONTENT_BODY; }; - inline const string& getData() const { return data; } - inline string& getData() { return data; } - uint32_t encodedSize() const; - void encode(Buffer& buffer) const; - void decode(Buffer& buffer, uint32_t size); - void print(std::ostream& out) const; - void accept(AMQBodyConstVisitor& v) const { v.visit(*this); } - boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); } + QPID_COMMON_EXTERN inline uint8_t type() const { return CONTENT_BODY; }; + QPID_COMMON_EXTERN inline const string& getData() const { return data; } + QPID_COMMON_EXTERN inline string& getData() { return data; } + QPID_COMMON_EXTERN uint32_t encodedSize() const; + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer, uint32_t size); + QPID_COMMON_EXTERN void print(std::ostream& out) const; + QPID_COMMON_EXTERN void accept(AMQBodyConstVisitor& v) const { v.visit(*this); } + QPID_COMMON_EXTERN boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); } }; } diff --git a/qpid/cpp/src/qpid/framing/AMQFrame.cpp b/qpid/cpp/src/qpid/framing/AMQFrame.cpp index 80c8e0b56d..9473b2a513 100644 --- a/qpid/cpp/src/qpid/framing/AMQFrame.cpp +++ b/qpid/cpp/src/qpid/framing/AMQFrame.cpp @@ -41,7 +41,7 @@ AMQFrame::AMQFrame(const boost::intrusive_ptr<AMQBody>& b) : body(b) { init(); } AMQFrame::AMQFrame(const AMQBody& b) : body(b.clone()) { init(); } -AMQFrame::~AMQFrame() {} +AMQFrame::~AMQFrame() { init(); } AMQBody* AMQFrame::getBody() { // Non-const AMQBody* may be used to modify the body. diff --git a/qpid/cpp/src/qpid/framing/AMQFrame.h b/qpid/cpp/src/qpid/framing/AMQFrame.h index 028d0c1d8a..34319e7ed4 100644 --- a/qpid/cpp/src/qpid/framing/AMQFrame.h +++ b/qpid/cpp/src/qpid/framing/AMQFrame.h @@ -29,6 +29,7 @@ #include "qpid/sys/LatencyMetric.h" #include <boost/intrusive_ptr.hpp> #include <boost/cast.hpp> +#include "qpid/CommonImportExport.h" namespace qpid { namespace framing { @@ -36,15 +37,15 @@ namespace framing { class AMQFrame : public AMQDataBlock, public sys::LatencyMetricTimestamp { public: - AMQFrame(const boost::intrusive_ptr<AMQBody>& b=0); - AMQFrame(const AMQBody& b); - ~AMQFrame(); + QPID_COMMON_EXTERN AMQFrame(const boost::intrusive_ptr<AMQBody>& b=0); + QPID_COMMON_EXTERN AMQFrame(const AMQBody& b); + QPID_COMMON_EXTERN ~AMQFrame(); ChannelId getChannel() const { return channel; } void setChannel(ChannelId c) { channel = c; } - AMQBody* getBody(); - const AMQBody* getBody() const; + QPID_COMMON_EXTERN AMQBody* getBody(); + QPID_COMMON_EXTERN const AMQBody* getBody() const; AMQMethodBody* getMethod() { return getBody()->getMethod(); } const AMQMethodBody* getMethod() const { return getBody()->getMethod(); } @@ -59,9 +60,9 @@ class AMQFrame : public AMQDataBlock, public sys::LatencyMetricTimestamp return boost::polymorphic_downcast<const T*>(getBody()); } - void encode(Buffer& buffer) const; - bool decode(Buffer& buffer); - uint32_t encodedSize() const; + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN bool decode(Buffer& buffer); + QPID_COMMON_EXTERN uint32_t encodedSize() const; // 0-10 terminology: first/last frame (in segment) first/last segment (in assembly) @@ -88,13 +89,10 @@ class AMQFrame : public AMQDataBlock, public sys::LatencyMetricTimestamp void setEos(bool isEos) { eos = isEos; } static uint16_t DECODE_SIZE_MIN; - static uint32_t frameOverhead(); + QPID_COMMON_EXTERN static uint32_t frameOverhead(); /** Must point to at least DECODE_SIZE_MIN bytes of data */ static uint16_t decodeSize(char* data); - uint64_t getClusterId() const { return clusterId; } - void setClusterId(uint64_t id) { clusterId = id; } - private: void init(); @@ -106,10 +104,9 @@ class AMQFrame : public AMQDataBlock, public sys::LatencyMetricTimestamp bool bos : 1; bool eos : 1; mutable uint32_t encodedSizeCache; - uint64_t clusterId; // Used to identify frames in a clustered broekr. }; -std::ostream& operator<<(std::ostream&, const AMQFrame&); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const AMQFrame&); }} // namespace qpid::framing diff --git a/qpid/cpp/src/qpid/framing/AMQHeaderBody.h b/qpid/cpp/src/qpid/framing/AMQHeaderBody.h index 9846544949..b8099f2e51 100644 --- a/qpid/cpp/src/qpid/framing/AMQHeaderBody.h +++ b/qpid/cpp/src/qpid/framing/AMQHeaderBody.h @@ -26,6 +26,7 @@ #include "Buffer.h" #include "qpid/framing/DeliveryProperties.h" #include "qpid/framing/MessageProperties.h" +#include "qpid/CommonImportExport.h" #include <iostream> #include <boost/optional.hpp> @@ -83,12 +84,12 @@ public: inline uint8_t type() const { return HEADER_BODY; } - uint32_t encodedSize() const; - void encode(Buffer& buffer) const; - void decode(Buffer& buffer, uint32_t size); - uint64_t getContentLength() const; - void print(std::ostream& out) const; - void accept(AMQBodyConstVisitor&) const; + QPID_COMMON_EXTERN uint32_t encodedSize() const; + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer, uint32_t size); + QPID_COMMON_EXTERN uint64_t getContentLength() const; + QPID_COMMON_EXTERN void print(std::ostream& out) const; + QPID_COMMON_EXTERN void accept(AMQBodyConstVisitor&) const; template <class T> T* get(bool create) { boost::optional<T>& p=properties.OptProps<T>::props; diff --git a/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h b/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h index 3fb41c128e..5d3f633576 100644 --- a/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h +++ b/qpid/cpp/src/qpid/framing/AMQHeartbeatBody.h @@ -21,6 +21,7 @@ #include "amqp_types.h" #include "AMQBody.h" #include "Buffer.h" +#include "qpid/CommonImportExport.h" #ifndef _AMQHeartbeatBody_ #define _AMQHeartbeatBody_ @@ -31,12 +32,12 @@ namespace framing { class AMQHeartbeatBody : public AMQBody { public: - virtual ~AMQHeartbeatBody(); + QPID_COMMON_EXTERN virtual ~AMQHeartbeatBody(); inline uint32_t encodedSize() const { return 0; } inline uint8_t type() const { return HEARTBEAT_BODY; } inline void encode(Buffer& ) const {} inline void decode(Buffer& , uint32_t /*size*/) {} - virtual void print(std::ostream& out) const; + QPID_COMMON_EXTERN virtual void print(std::ostream& out) const; void accept(AMQBodyConstVisitor& v) const { v.visit(*this); } boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); } }; diff --git a/qpid/cpp/src/qpid/framing/AMQMethodBody.h b/qpid/cpp/src/qpid/framing/AMQMethodBody.h index cc7489ddd9..a38726b0fc 100644 --- a/qpid/cpp/src/qpid/framing/AMQMethodBody.h +++ b/qpid/cpp/src/qpid/framing/AMQMethodBody.h @@ -25,7 +25,7 @@ #include "AMQBody.h" #include "qpid/framing/ProtocolVersion.h" #include "qpid/shared_ptr.h" - +#include "qpid/CommonImportExport.h" #include <ostream> #include <assert.h> @@ -40,7 +40,7 @@ class MethodBodyConstVisitor; class AMQMethodBody : public AMQBody { public: AMQMethodBody() {} - virtual ~AMQMethodBody(); + QPID_COMMON_EXTERN virtual ~AMQMethodBody(); virtual void accept(MethodBodyConstVisitor&) const = 0; diff --git a/qpid/cpp/src/qpid/framing/AccumulatedAck.h b/qpid/cpp/src/qpid/framing/AccumulatedAck.h index ea78b797e0..ede73897c7 100644 --- a/qpid/cpp/src/qpid/framing/AccumulatedAck.h +++ b/qpid/cpp/src/qpid/framing/AccumulatedAck.h @@ -27,6 +27,7 @@ #include <ostream> #include "SequenceNumber.h" #include "SequenceNumberSet.h" +#include "qpid/CommonImportExport.h" namespace qpid { namespace framing { @@ -58,17 +59,17 @@ namespace qpid { */ std::list<Range> ranges; - explicit AccumulatedAck(SequenceNumber r = SequenceNumber()); - void update(SequenceNumber firstTag, SequenceNumber lastTag); - void consolidate(); - void clear(); - bool covers(SequenceNumber tag) const; + QPID_COMMON_EXTERN explicit AccumulatedAck(SequenceNumber r = SequenceNumber()); + QPID_COMMON_EXTERN void update(SequenceNumber firstTag, SequenceNumber lastTag); + QPID_COMMON_EXTERN void consolidate(); + QPID_COMMON_EXTERN void clear(); + QPID_COMMON_EXTERN bool covers(SequenceNumber tag) const; void collectRanges(SequenceNumberSet& set) const; - void update(const SequenceNumber cumulative, const SequenceNumberSet& range); + QPID_COMMON_EXTERN void update(const SequenceNumber cumulative, const SequenceNumberSet& range); void operator()(SequenceNumber first, SequenceNumber last) { update(first, last); } }; - std::ostream& operator<<(std::ostream&, const Range&); - std::ostream& operator<<(std::ostream&, const AccumulatedAck&); + QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const Range&); + QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const AccumulatedAck&); } } diff --git a/qpid/cpp/src/qpid/framing/Array.h b/qpid/cpp/src/qpid/framing/Array.h index 183fcb6d5c..0b6b704ed2 100644 --- a/qpid/cpp/src/qpid/framing/Array.h +++ b/qpid/cpp/src/qpid/framing/Array.h @@ -24,6 +24,7 @@ #include <boost/shared_ptr.hpp> #include <iostream> #include <vector> +#include "qpid/CommonImportExport.h" #ifndef _Array_ #define _Array_ @@ -41,38 +42,38 @@ class Array typedef ValueVector::const_iterator const_iterator; typedef ValueVector::iterator iterator; - uint32_t encodedSize() const; - void encode(Buffer& buffer) const; - void decode(Buffer& buffer); + QPID_COMMON_EXTERN uint32_t encodedSize() const; + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer); - int count() const; - bool operator==(const Array& other) const; + QPID_COMMON_EXTERN int count() const; + QPID_COMMON_EXTERN bool operator==(const Array& other) const; - Array(); - Array(TypeCode type); - Array(uint8_t type); + QPID_COMMON_EXTERN Array(); + QPID_COMMON_EXTERN Array(TypeCode type); + QPID_COMMON_EXTERN Array(uint8_t type); //creates a longstr array - Array(const std::vector<std::string>& in); + QPID_COMMON_EXTERN Array(const std::vector<std::string>& in); - TypeCode getType() const { return type; } + QPID_COMMON_EXTERN TypeCode getType() const { return type; } // std collection interface. - const_iterator begin() const { return values.begin(); } - const_iterator end() const { return values.end(); } - iterator begin() { return values.begin(); } - iterator end(){ return values.end(); } - - ValuePtr front() const { return values.front(); } - ValuePtr back() const { return values.back(); } - size_t size() const { return values.size(); } - - void insert(iterator i, ValuePtr value); - void erase(iterator i) { values.erase(i); } - void push_back(ValuePtr value) { values.insert(end(), value); } - void pop_back() { values.pop_back(); } + QPID_COMMON_EXTERN const_iterator begin() const { return values.begin(); } + QPID_COMMON_EXTERN const_iterator end() const { return values.end(); } + QPID_COMMON_EXTERN iterator begin() { return values.begin(); } + QPID_COMMON_EXTERN iterator end(){ return values.end(); } + + QPID_COMMON_EXTERN ValuePtr front() const { return values.front(); } + QPID_COMMON_EXTERN ValuePtr back() const { return values.back(); } + QPID_COMMON_EXTERN size_t size() const { return values.size(); } + + QPID_COMMON_EXTERN void insert(iterator i, ValuePtr value); + QPID_COMMON_EXTERN void erase(iterator i) { values.erase(i); } + QPID_COMMON_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); } + QPID_COMMON_EXTERN void pop_back() { values.pop_back(); } // Non-std interface - void add(ValuePtr value) { push_back(value); } + QPID_COMMON_EXTERN void add(ValuePtr value) { push_back(value); } template <class T> void collect(std::vector<T>& out) const @@ -86,7 +87,7 @@ class Array TypeCode type; ValueVector values; - friend std::ostream& operator<<(std::ostream& out, const Array& body); + friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& out, const Array& body); }; } diff --git a/qpid/cpp/src/qpid/framing/Buffer.h b/qpid/cpp/src/qpid/framing/Buffer.h index 828e6e963a..57fb1e32a0 100644 --- a/qpid/cpp/src/qpid/framing/Buffer.h +++ b/qpid/cpp/src/qpid/framing/Buffer.h @@ -20,6 +20,7 @@ */ #include "amqp_types.h" #include "qpid/Exception.h" +#include "qpid/CommonImportExport.h" #include <boost/iterator/iterator_facade.hpp> #ifndef _Buffer_ @@ -66,65 +67,65 @@ class Buffer friend class Iterator; - Buffer(char* data=0, uint32_t size=0); + QPID_COMMON_EXTERN Buffer(char* data=0, uint32_t size=0); - void record(); - void restore(bool reRecord = false); - void reset(); + QPID_COMMON_EXTERN void record(); + QPID_COMMON_EXTERN void restore(bool reRecord = false); + QPID_COMMON_EXTERN void reset(); - uint32_t available() { return size - position; } - uint32_t getSize() { return size; } - uint32_t getPosition() { return position; } - Iterator getIterator() { return Iterator(*this); } - char* getPointer() { return data; } + QPID_COMMON_EXTERN uint32_t available() { return size - position; } + QPID_COMMON_EXTERN uint32_t getSize() { return size; } + QPID_COMMON_EXTERN uint32_t getPosition() { return position; } + QPID_COMMON_EXTERN Iterator getIterator() { return Iterator(*this); } + QPID_COMMON_EXTERN char* getPointer() { return data; } - void putOctet(uint8_t i); - void putShort(uint16_t i); - void putLong(uint32_t i); - void putLongLong(uint64_t i); - void putInt8(int8_t i); - void putInt16(int16_t i); - void putInt32(int32_t i); - void putInt64(int64_t i); - void putFloat(float f); - void putDouble(double f); - void putBin128(uint8_t* b); - - uint8_t getOctet(); - uint16_t getShort(); - uint32_t getLong(); - uint64_t getLongLong(); - int8_t getInt8(); - int16_t getInt16(); - int32_t getInt32(); - int64_t getInt64(); - float getFloat(); - double getDouble(); + QPID_COMMON_EXTERN void putOctet(uint8_t i); + QPID_COMMON_EXTERN void putShort(uint16_t i); + QPID_COMMON_EXTERN void putLong(uint32_t i); + QPID_COMMON_EXTERN void putLongLong(uint64_t i); + QPID_COMMON_EXTERN void putInt8(int8_t i); + QPID_COMMON_EXTERN void putInt16(int16_t i); + QPID_COMMON_EXTERN void putInt32(int32_t i); + QPID_COMMON_EXTERN void putInt64(int64_t i); + QPID_COMMON_EXTERN void putFloat(float f); + QPID_COMMON_EXTERN void putDouble(double f); + QPID_COMMON_EXTERN void putBin128(uint8_t* b); + + QPID_COMMON_EXTERN uint8_t getOctet(); + QPID_COMMON_EXTERN uint16_t getShort(); + QPID_COMMON_EXTERN uint32_t getLong(); + QPID_COMMON_EXTERN uint64_t getLongLong(); + QPID_COMMON_EXTERN int8_t getInt8(); + QPID_COMMON_EXTERN int16_t getInt16(); + QPID_COMMON_EXTERN int32_t getInt32(); + QPID_COMMON_EXTERN int64_t getInt64(); + QPID_COMMON_EXTERN float getFloat(); + QPID_COMMON_EXTERN double getDouble(); template <int n> - uint64_t getUInt(); + QPID_COMMON_EXTERN uint64_t getUInt(); template <int n> - void putUInt(uint64_t); + QPID_COMMON_EXTERN void putUInt(uint64_t); - void putShortString(const string& s); - void putMediumString(const string& s); - void putLongString(const string& s); - void getShortString(string& s); - void getMediumString(string& s); - void getLongString(string& s); - void getBin128(uint8_t* b); + QPID_COMMON_EXTERN void putShortString(const string& s); + QPID_COMMON_EXTERN void putMediumString(const string& s); + QPID_COMMON_EXTERN void putLongString(const string& s); + QPID_COMMON_EXTERN void getShortString(string& s); + QPID_COMMON_EXTERN void getMediumString(string& s); + QPID_COMMON_EXTERN void getLongString(string& s); + QPID_COMMON_EXTERN void getBin128(uint8_t* b); - void putRawData(const string& s); - void getRawData(string& s, uint32_t size); + QPID_COMMON_EXTERN void putRawData(const string& s); + QPID_COMMON_EXTERN void getRawData(string& s, uint32_t size); - void putRawData(const uint8_t* data, size_t size); - void getRawData(uint8_t* data, size_t size); + QPID_COMMON_EXTERN void putRawData(const uint8_t* data, size_t size); + QPID_COMMON_EXTERN void getRawData(uint8_t* data, size_t size); template <class T> void put(const T& data) { data.encode(*this); } template <class T> void get(T& data) { data.decode(*this); } - void dump(std::ostream&) const; + QPID_COMMON_EXTERN void dump(std::ostream&) const; }; std::ostream& operator<<(std::ostream&, const Buffer&); diff --git a/qpid/cpp/src/qpid/framing/FieldTable.h b/qpid/cpp/src/qpid/framing/FieldTable.h index 9e1214a28c..a07568559f 100644 --- a/qpid/cpp/src/qpid/framing/FieldTable.h +++ b/qpid/cpp/src/qpid/framing/FieldTable.h @@ -23,6 +23,7 @@ #include <boost/shared_ptr.hpp> #include <map> #include "amqp_types.h" +#include "qpid/CommonImportExport.h" #ifndef _FieldTable_ #define _FieldTable_ @@ -51,45 +52,45 @@ class FieldTable typedef std::map<std::string, ValuePtr> ValueMap; typedef ValueMap::iterator iterator; - FieldTable() {}; - FieldTable(const FieldTable& ft); - ~FieldTable(); - FieldTable& operator=(const FieldTable& ft); - uint32_t encodedSize() const; - void encode(Buffer& buffer) const; - void decode(Buffer& buffer); - - int count() const; - void set(const std::string& name, const ValuePtr& value); - ValuePtr get(const std::string& name) const; - bool isSet(const std::string& name) const { return get(name).get() != 0; } - - void setString(const std::string& name, const std::string& value); - void setInt(const std::string& name, const int value); - void setInt64(const std::string& name, const int64_t value); - void setTimestamp(const std::string& name, const uint64_t value); - void setUInt64(const std::string& name, const uint64_t value); - void setTable(const std::string& name, const FieldTable& value); - void setArray(const std::string& name, const Array& value); - void setFloat(const std::string& name, const float value); - void setDouble(const std::string& name, const double value); + QPID_COMMON_EXTERN FieldTable() {}; + QPID_COMMON_EXTERN FieldTable(const FieldTable& ft); + QPID_COMMON_EXTERN ~FieldTable(); + QPID_COMMON_EXTERN FieldTable& operator=(const FieldTable& ft); + QPID_COMMON_EXTERN uint32_t encodedSize() const; + QPID_COMMON_EXTERN void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN void decode(Buffer& buffer); + + QPID_COMMON_EXTERN int count() const; + QPID_COMMON_EXTERN void set(const std::string& name, const ValuePtr& value); + QPID_COMMON_EXTERN ValuePtr get(const std::string& name) const; + QPID_COMMON_EXTERN bool isSet(const std::string& name) const { return get(name).get() != 0; } + + QPID_COMMON_EXTERN void setString(const std::string& name, const std::string& value); + QPID_COMMON_EXTERN void setInt(const std::string& name, const int value); + QPID_COMMON_EXTERN void setInt64(const std::string& name, const int64_t value); + QPID_COMMON_EXTERN void setTimestamp(const std::string& name, const uint64_t value); + QPID_COMMON_EXTERN void setUInt64(const std::string& name, const uint64_t value); + QPID_COMMON_EXTERN void setTable(const std::string& name, const FieldTable& value); + QPID_COMMON_EXTERN void setArray(const std::string& name, const Array& value); + QPID_COMMON_EXTERN void setFloat(const std::string& name, const float value); + QPID_COMMON_EXTERN void setDouble(const std::string& name, const double value); //void setDecimal(string& name, xxx& value); - int getAsInt(const std::string& name) const; - uint64_t getAsUInt64(const std::string& name) const; - int64_t getAsInt64(const std::string& name) const; - std::string getAsString(const std::string& name) const; + QPID_COMMON_EXTERN int getAsInt(const std::string& name) const; + QPID_COMMON_EXTERN uint64_t getAsUInt64(const std::string& name) const; + QPID_COMMON_EXTERN int64_t getAsInt64(const std::string& name) const; + QPID_COMMON_EXTERN std::string getAsString(const std::string& name) const; - bool getTable(const std::string& name, FieldTable& value) const; - bool getArray(const std::string& name, Array& value) const; - bool getFloat(const std::string& name, float& value) const; - bool getDouble(const std::string& name, double& value) const; + QPID_COMMON_EXTERN bool getTable(const std::string& name, FieldTable& value) const; + QPID_COMMON_EXTERN bool getArray(const std::string& name, Array& value) const; + QPID_COMMON_EXTERN bool getFloat(const std::string& name, float& value) const; + QPID_COMMON_EXTERN bool getDouble(const std::string& name, double& value) const; //bool getTimestamp(const std::string& name, uint64_t& value) const; //bool getDecimal(string& name, xxx& value); - void erase(const std::string& name); + QPID_COMMON_EXTERN void erase(const std::string& name); - bool operator==(const FieldTable& other) const; + QPID_COMMON_EXTERN bool operator==(const FieldTable& other) const; // Map-like interface. // TODO: may need to duplicate into versions that return mutable iterator @@ -107,7 +108,7 @@ class FieldTable private: ValueMap values; - friend std::ostream& operator<<(std::ostream& out, const FieldTable& body); + QPID_COMMON_EXTERN friend std::ostream& operator<<(std::ostream& out, const FieldTable& body); }; //class FieldNotFoundException{}; diff --git a/qpid/cpp/src/qpid/framing/FieldValue.h b/qpid/cpp/src/qpid/framing/FieldValue.h index 29760619e5..0f27700ac8 100644 --- a/qpid/cpp/src/qpid/framing/FieldValue.h +++ b/qpid/cpp/src/qpid/framing/FieldValue.h @@ -25,6 +25,7 @@ #include "amqp_types.h" #include "Buffer.h" #include "FieldTable.h" +#include "qpid/CommonImportExport.h" #include "assert.h" @@ -87,8 +88,8 @@ class FieldValue { bool empty() const { return data.get() == 0; } void encode(Buffer& buffer); void decode(Buffer& buffer); - bool operator==(const FieldValue&) const; - bool operator!=(const FieldValue& v) const { return !(*this == v); } + QPID_COMMON_EXTERN bool operator==(const FieldValue&) const; + QPID_COMMON_EXTERN bool operator!=(const FieldValue& v) const { return !(*this == v); } void print(std::ostream& out) const; @@ -244,28 +245,28 @@ class EncodedValue : public FieldValue::Data { class Str8Value : public FieldValue { public: - Str8Value(const std::string& v); + QPID_COMMON_EXTERN Str8Value(const std::string& v); }; class Str16Value : public FieldValue { public: - Str16Value(const std::string& v); + QPID_COMMON_EXTERN Str16Value(const std::string& v); }; class Struct32Value : public FieldValue { public: - Struct32Value(const std::string& v); + QPID_COMMON_EXTERN Struct32Value(const std::string& v); }; class FloatValue : public FieldValue { public: - FloatValue(float f); + QPID_COMMON_EXTERN FloatValue(float f); }; class DoubleValue : public FieldValue { public: - DoubleValue(double f); + QPID_COMMON_EXTERN DoubleValue(double f); }; /* @@ -273,32 +274,32 @@ class DoubleValue : public FieldValue */ class IntegerValue : public FieldValue { public: - IntegerValue(int v); + QPID_COMMON_EXTERN IntegerValue(int v); }; class TimeValue : public FieldValue { public: - TimeValue(uint64_t v); + QPID_COMMON_EXTERN TimeValue(uint64_t v); }; class Integer64Value : public FieldValue { public: - Integer64Value(int64_t v); + QPID_COMMON_EXTERN Integer64Value(int64_t v); }; class Unsigned64Value : public FieldValue { public: - Unsigned64Value(uint64_t v); + QPID_COMMON_EXTERN Unsigned64Value(uint64_t v); }; class FieldTableValue : public FieldValue { public: - FieldTableValue(const FieldTable&); + QPID_COMMON_EXTERN FieldTableValue(const FieldTable&); }; class ArrayValue : public FieldValue { public: - ArrayValue(const Array&); + QPID_COMMON_EXTERN ArrayValue(const Array&); }; template <class T> diff --git a/qpid/cpp/src/qpid/framing/FrameDecoder.cpp b/qpid/cpp/src/qpid/framing/FrameDecoder.cpp index cbdac181e9..1e73ee1e51 100644 --- a/qpid/cpp/src/qpid/framing/FrameDecoder.cpp +++ b/qpid/cpp/src/qpid/framing/FrameDecoder.cpp @@ -21,8 +21,9 @@ #include "FrameDecoder.h" #include "Buffer.h" #include "qpid/log/Statement.h" -#include <algorithm> #include "qpid/framing/reply_exceptions.h" +#include <algorithm> +#include <string.h> namespace qpid { namespace framing { @@ -67,4 +68,13 @@ bool FrameDecoder::decode(Buffer& buffer) { return false; } +void FrameDecoder::setFragment(const char* data, size_t size) { + fragment.resize(size); + ::memcpy(&fragment[0], data, size); +} + +std::pair<const char*, size_t> FrameDecoder::getFragment() const { + return std::pair<const char*, size_t>(&fragment[0], fragment.size()); +} + }} // namespace qpid::framing diff --git a/qpid/cpp/src/qpid/framing/FrameDecoder.h b/qpid/cpp/src/qpid/framing/FrameDecoder.h index 7f974dadc3..961cc666a9 100644 --- a/qpid/cpp/src/qpid/framing/FrameDecoder.h +++ b/qpid/cpp/src/qpid/framing/FrameDecoder.h @@ -35,9 +35,16 @@ class FrameDecoder { public: bool decode(Buffer& buffer); - AMQFrame frame; + const AMQFrame& getFrame() const { return frame; } + AMQFrame& getFrame() { return frame; } + + void setFragment(const char*, size_t); + std::pair<const char*, size_t> getFragment() const; + private: std::vector<char> fragment; + AMQFrame frame; + }; }} // namespace qpid::framing diff --git a/qpid/cpp/src/qpid/framing/FrameSet.h b/qpid/cpp/src/qpid/framing/FrameSet.h index b13ca16e97..e3e8727600 100644 --- a/qpid/cpp/src/qpid/framing/FrameSet.h +++ b/qpid/cpp/src/qpid/framing/FrameSet.h @@ -23,6 +23,7 @@ #include "qpid/framing/amqp_framing.h" #include "qpid/framing/AMQFrame.h" #include "qpid/framing/SequenceNumber.h" +#include "qpid/CommonImportExport.h" #ifndef _FrameSet_ #define _FrameSet_ @@ -44,20 +45,20 @@ class FrameSet public: typedef boost::shared_ptr<FrameSet> shared_ptr; - FrameSet(const SequenceNumber& id); - void append(const AMQFrame& part); - bool isComplete() const; + QPID_COMMON_EXTERN FrameSet(const SequenceNumber& id); + QPID_COMMON_EXTERN void append(const AMQFrame& part); + QPID_COMMON_EXTERN bool isComplete() const; - uint64_t getContentSize() const; + QPID_COMMON_EXTERN uint64_t getContentSize() const; - void getContent(std::string&) const; - std::string getContent() const; + QPID_COMMON_EXTERN void getContent(std::string&) const; + QPID_COMMON_EXTERN std::string getContent() const; bool isContentBearing() const; - const AMQMethodBody* getMethod() const; - const AMQHeaderBody* getHeaders() const; - AMQHeaderBody* getHeaders(); + QPID_COMMON_EXTERN const AMQMethodBody* getMethod() const; + QPID_COMMON_EXTERN const AMQHeaderBody* getHeaders() const; + QPID_COMMON_EXTERN AMQHeaderBody* getHeaders(); template <class T> bool isA() const { const AMQMethodBody* method = getMethod(); diff --git a/qpid/cpp/src/qpid/framing/ProtocolInitiation.h b/qpid/cpp/src/qpid/framing/ProtocolInitiation.h index 6584fee55c..7a82b3575f 100644 --- a/qpid/cpp/src/qpid/framing/ProtocolInitiation.h +++ b/qpid/cpp/src/qpid/framing/ProtocolInitiation.h @@ -22,6 +22,7 @@ #include "Buffer.h" #include "AMQDataBlock.h" #include "ProtocolVersion.h" +#include "qpid/CommonImportExport.h" #ifndef _ProtocolInitiation_ #define _ProtocolInitiation_ @@ -35,12 +36,12 @@ private: ProtocolVersion version; public: - ProtocolInitiation(); - ProtocolInitiation(uint8_t major, uint8_t minor); - ProtocolInitiation(ProtocolVersion p); - virtual ~ProtocolInitiation(); - virtual void encode(Buffer& buffer) const; - virtual bool decode(Buffer& buffer); + QPID_COMMON_EXTERN ProtocolInitiation(); + QPID_COMMON_EXTERN ProtocolInitiation(uint8_t major, uint8_t minor); + QPID_COMMON_EXTERN ProtocolInitiation(ProtocolVersion p); + QPID_COMMON_EXTERN virtual ~ProtocolInitiation(); + QPID_COMMON_EXTERN virtual void encode(Buffer& buffer) const; + QPID_COMMON_EXTERN virtual bool decode(Buffer& buffer); inline virtual uint32_t encodedSize() const { return 8; } inline uint8_t getMajor() const { return version.getMajor(); } inline uint8_t getMinor() const { return version.getMinor(); } @@ -48,7 +49,7 @@ public: bool operator==(ProtocolVersion v) const { return v == getVersion(); } }; -std::ostream& operator<<(std::ostream& o, const framing::ProtocolInitiation& pi); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& o, const framing::ProtocolInitiation& pi); } diff --git a/qpid/cpp/src/qpid/framing/ProtocolVersion.h b/qpid/cpp/src/qpid/framing/ProtocolVersion.h index 9a7ebec491..681c9daf21 100644 --- a/qpid/cpp/src/qpid/framing/ProtocolVersion.h +++ b/qpid/cpp/src/qpid/framing/ProtocolVersion.h @@ -22,6 +22,7 @@ #define _ProtocolVersion_ #include "amqp_types.h" +#include "qpid/CommonImportExport.h" namespace qpid { @@ -38,16 +39,16 @@ public: explicit ProtocolVersion(uint8_t _major=0, uint8_t _minor=0) : major_(_major), minor_(_minor) {} - uint8_t getMajor() const { return major_; } - void setMajor(uint8_t major) { major_ = major; } - uint8_t getMinor() const { return minor_; } - void setMinor(uint8_t minor) { minor_ = minor; } - const std::string toString() const; + QPID_COMMON_EXTERN uint8_t getMajor() const { return major_; } + QPID_COMMON_EXTERN void setMajor(uint8_t major) { major_ = major; } + QPID_COMMON_EXTERN uint8_t getMinor() const { return minor_; } + QPID_COMMON_EXTERN void setMinor(uint8_t minor) { minor_ = minor; } + QPID_COMMON_EXTERN const std::string toString() const; - ProtocolVersion& operator=(ProtocolVersion p); + QPID_COMMON_EXTERN ProtocolVersion& operator=(ProtocolVersion p); - bool operator==(ProtocolVersion p) const; - bool operator!=(ProtocolVersion p) const { return ! (*this == p); } + QPID_COMMON_EXTERN bool operator==(ProtocolVersion p) const; + QPID_COMMON_EXTERN bool operator!=(ProtocolVersion p) const { return ! (*this == p); } }; } // namespace framing diff --git a/qpid/cpp/src/qpid/framing/Proxy.h b/qpid/cpp/src/qpid/framing/Proxy.h index 5e2c886af2..a9a6ce981e 100644 --- a/qpid/cpp/src/qpid/framing/Proxy.h +++ b/qpid/cpp/src/qpid/framing/Proxy.h @@ -22,6 +22,8 @@ #include "FrameHandler.h" #include "ProtocolVersion.h" +#include "qpid/CommonImportExport.h" + namespace qpid { namespace framing { @@ -37,19 +39,19 @@ class Proxy { Proxy& proxy; public: - ScopedSync(Proxy& p); - ~ScopedSync(); + QPID_COMMON_EXTERN ScopedSync(Proxy& p); + QPID_COMMON_EXTERN ~ScopedSync(); }; - Proxy(FrameHandler& h); - virtual ~Proxy(); + QPID_COMMON_EXTERN Proxy(FrameHandler& h); + QPID_COMMON_EXTERN virtual ~Proxy(); - void send(const AMQBody&); + QPID_COMMON_EXTERN void send(const AMQBody&); - ProtocolVersion getVersion() const; + QPID_COMMON_EXTERN ProtocolVersion getVersion() const; - FrameHandler& getHandler(); - void setHandler(FrameHandler&); + QPID_COMMON_EXTERN FrameHandler& getHandler(); + QPID_COMMON_EXTERN void setHandler(FrameHandler&); private: FrameHandler* out; bool sync; diff --git a/qpid/cpp/src/qpid/framing/SendContent.h b/qpid/cpp/src/qpid/framing/SendContent.h index dcd5202b3e..745c948c9e 100644 --- a/qpid/cpp/src/qpid/framing/SendContent.h +++ b/qpid/cpp/src/qpid/framing/SendContent.h @@ -22,6 +22,7 @@ #include "qpid/framing/amqp_framing.h" #include "qpid/framing/AMQFrame.h" #include "qpid/framing/FrameHandler.h" +#include "qpid/CommonImportExport.h" #ifndef _SendContent_ #define _SendContent_ @@ -44,8 +45,8 @@ class SendContent void sendFragment(const AMQContentBody& body, uint32_t offset, uint16_t size, bool first, bool last) const; void setFlags(AMQFrame& f, bool first, bool last) const; public: - SendContent(FrameHandler& _handler, uint16_t _maxFrameSize, uint frameCount); - void operator()(const AMQFrame& f); + QPID_COMMON_EXTERN SendContent(FrameHandler& _handler, uint16_t _maxFrameSize, uint frameCount); + QPID_COMMON_EXTERN void operator()(const AMQFrame& f); }; } diff --git a/qpid/cpp/src/qpid/framing/SequenceNumber.h b/qpid/cpp/src/qpid/framing/SequenceNumber.h index 930e146863..3b18ce1360 100644 --- a/qpid/cpp/src/qpid/framing/SequenceNumber.h +++ b/qpid/cpp/src/qpid/framing/SequenceNumber.h @@ -23,6 +23,7 @@ #include "amqp_types.h" #include <iosfwd> +#include "qpid/CommonImportExport.h" namespace qpid { namespace framing { @@ -37,22 +38,22 @@ class SequenceNumber int32_t value; public: - SequenceNumber(); - SequenceNumber(uint32_t v); + QPID_COMMON_EXTERN SequenceNumber(); + QPID_COMMON_EXTERN SequenceNumber(uint32_t v); - SequenceNumber& operator++();//prefix ++ - const SequenceNumber operator++(int);//postfix ++ - SequenceNumber& operator--();//prefix ++ - bool operator==(const SequenceNumber& other) const; - bool operator!=(const SequenceNumber& other) const; - bool operator<(const SequenceNumber& other) const; - bool operator>(const SequenceNumber& other) const; - bool operator<=(const SequenceNumber& other) const; - bool operator>=(const SequenceNumber& other) const; + QPID_COMMON_EXTERN SequenceNumber& operator++();//prefix ++ + QPID_COMMON_EXTERN const SequenceNumber operator++(int);//postfix ++ + QPID_COMMON_EXTERN SequenceNumber& operator--();//prefix ++ + QPID_COMMON_EXTERN bool operator==(const SequenceNumber& other) const; + QPID_COMMON_EXTERN bool operator!=(const SequenceNumber& other) const; + QPID_COMMON_EXTERN bool operator<(const SequenceNumber& other) const; + QPID_COMMON_EXTERN bool operator>(const SequenceNumber& other) const; + QPID_COMMON_EXTERN bool operator<=(const SequenceNumber& other) const; + QPID_COMMON_EXTERN bool operator>=(const SequenceNumber& other) const; uint32_t getValue() const { return (uint32_t) value; } operator uint32_t() const { return (uint32_t) value; } - friend int32_t operator-(const SequenceNumber& a, const SequenceNumber& b); + QPID_COMMON_EXTERN friend int32_t operator-(const SequenceNumber& a, const SequenceNumber& b); void encode(Buffer& buffer) const; void decode(Buffer& buffer); @@ -67,7 +68,7 @@ struct Window SequenceNumber lwm; }; -std::ostream& operator<<(std::ostream& o, const SequenceNumber& n); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream& o, const SequenceNumber& n); }} // namespace qpid::framing diff --git a/qpid/cpp/src/qpid/framing/SequenceNumberSet.h b/qpid/cpp/src/qpid/framing/SequenceNumberSet.h index 666307f9d9..8e023ba535 100644 --- a/qpid/cpp/src/qpid/framing/SequenceNumberSet.h +++ b/qpid/cpp/src/qpid/framing/SequenceNumberSet.h @@ -27,6 +27,7 @@ #include "SequenceNumber.h" #include "qpid/framing/reply_exceptions.h" #include "qpid/InlineVector.h" +#include "qpid/CommonImportExport.h" namespace qpid { namespace framing { @@ -41,8 +42,8 @@ public: void encode(Buffer& buffer) const; void decode(Buffer& buffer); uint32_t encodedSize() const; - SequenceNumberSet condense() const; - void addRange(const SequenceNumber& start, const SequenceNumber& end); + QPID_COMMON_EXTERN SequenceNumberSet condense() const; + QPID_COMMON_EXTERN void addRange(const SequenceNumber& start, const SequenceNumber& end); template <class T> void processRanges(T& t) const @@ -58,7 +59,7 @@ public: } } - friend std::ostream& operator<<(std::ostream&, const SequenceNumberSet&); + friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SequenceNumberSet&); }; diff --git a/qpid/cpp/src/qpid/framing/SequenceSet.h b/qpid/cpp/src/qpid/framing/SequenceSet.h index 57b9c2c8e1..a5ee6cd649 100644 --- a/qpid/cpp/src/qpid/framing/SequenceSet.h +++ b/qpid/cpp/src/qpid/framing/SequenceSet.h @@ -23,6 +23,7 @@ #include "SequenceNumber.h" #include "qpid/RangeSet.h" +#include "qpid/CommonImportExport.h" namespace qpid { namespace framing { @@ -41,13 +42,13 @@ class SequenceSet : public RangeSet<SequenceNumber> { void decode(Buffer& buffer); uint32_t encodedSize() const; - bool contains(const SequenceNumber& s) const; - void add(const SequenceNumber& s); - void add(const SequenceNumber& start, const SequenceNumber& finish); // Closed range - void add(const SequenceSet& set); - void remove(const SequenceNumber& s); - void remove(const SequenceNumber& start, const SequenceNumber& finish); // Closed range - void remove(const SequenceSet& set); + QPID_COMMON_EXTERN bool contains(const SequenceNumber& s) const; + QPID_COMMON_EXTERN void add(const SequenceNumber& s); + QPID_COMMON_EXTERN void add(const SequenceNumber& start, const SequenceNumber& finish); // Closed range + QPID_COMMON_EXTERN void add(const SequenceSet& set); + QPID_COMMON_EXTERN void remove(const SequenceNumber& s); + QPID_COMMON_EXTERN void remove(const SequenceNumber& start, const SequenceNumber& finish); // Closed range + QPID_COMMON_EXTERN void remove(const SequenceSet& set); template <class T> void for_each(T& t) const { for (RangeIterator i = rangesBegin(); i != rangesEnd(); i++) @@ -59,7 +60,7 @@ class SequenceSet : public RangeSet<SequenceNumber> { t(i->first(), i->last()); } - friend std::ostream& operator<<(std::ostream&, const SequenceSet&); + friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const SequenceSet&); }; }} // namespace qpid::framing diff --git a/qpid/cpp/src/qpid/framing/StructHelper.h b/qpid/cpp/src/qpid/framing/StructHelper.h index e3dce4f5ec..89f556ad3c 100644 --- a/qpid/cpp/src/qpid/framing/StructHelper.h +++ b/qpid/cpp/src/qpid/framing/StructHelper.h @@ -22,6 +22,7 @@ #define _StructHelper_ #include "qpid/Exception.h" +#include "qpid/CommonImportExport.h" #include "Buffer.h" #include <stdlib.h> // For alloca diff --git a/qpid/cpp/src/qpid/framing/TransferContent.h b/qpid/cpp/src/qpid/framing/TransferContent.h index e3f6666fa4..236a0b6d93 100644 --- a/qpid/cpp/src/qpid/framing/TransferContent.h +++ b/qpid/cpp/src/qpid/framing/TransferContent.h @@ -26,6 +26,7 @@ #include "qpid/Exception.h" #include "qpid/framing/MessageProperties.h" #include "qpid/framing/DeliveryProperties.h" +#include "qpid/CommonImportExport.h" namespace qpid { namespace framing { @@ -36,27 +37,27 @@ class TransferContent : public MethodContent AMQHeaderBody header; std::string data; public: - TransferContent(const std::string& data = std::string(), const std::string& key=std::string()); + QPID_COMMON_EXTERN TransferContent(const std::string& data = std::string(), const std::string& key=std::string()); ///@internal - AMQHeaderBody getHeader() const; + QPID_COMMON_EXTERN AMQHeaderBody getHeader() const; - void setData(const std::string&); - const std::string& getData() const; - std::string& getData(); + QPID_COMMON_EXTERN void setData(const std::string&); + QPID_COMMON_EXTERN const std::string& getData() const; + QPID_COMMON_EXTERN std::string& getData(); - void appendData(const std::string&); + QPID_COMMON_EXTERN void appendData(const std::string&); - bool hasMessageProperties() const; - MessageProperties& getMessageProperties(); - const MessageProperties& getMessageProperties() const; + QPID_COMMON_EXTERN bool hasMessageProperties() const; + QPID_COMMON_EXTERN MessageProperties& getMessageProperties(); + QPID_COMMON_EXTERN const MessageProperties& getMessageProperties() const; - bool hasDeliveryProperties() const; - DeliveryProperties& getDeliveryProperties(); - const DeliveryProperties& getDeliveryProperties() const; + QPID_COMMON_EXTERN bool hasDeliveryProperties() const; + QPID_COMMON_EXTERN DeliveryProperties& getDeliveryProperties(); + QPID_COMMON_EXTERN const DeliveryProperties& getDeliveryProperties() const; ///@internal - void populate(const FrameSet& frameset); + QPID_COMMON_EXTERN void populate(const FrameSet& frameset); }; }} diff --git a/qpid/cpp/src/qpid/framing/Uuid.h b/qpid/cpp/src/qpid/framing/Uuid.h index 2fcbb5a261..fe0c32dc0b 100644 --- a/qpid/cpp/src/qpid/framing/Uuid.h +++ b/qpid/cpp/src/qpid/framing/Uuid.h @@ -19,7 +19,9 @@ * */ +#include "qpid/CommonImportExport.h" #include "qpid/sys/uuid.h" +#include "qpid/sys/IntegerTypes.h" #include <boost/array.hpp> @@ -63,12 +65,12 @@ struct Uuid : public boost::array<uint8_t, 16> { // Default op= and copy ctor are fine. // boost::array gives us ==, < etc. - void encode(framing::Buffer& buf) const; - void decode(framing::Buffer& buf); - uint32_t encodedSize() const { return size(); } + QPID_COMMON_EXTERN void encode(framing::Buffer& buf) const; + QPID_COMMON_EXTERN void decode(framing::Buffer& buf); + QPID_COMMON_EXTERN uint32_t encodedSize() const { return size(); } /** String value in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */ - std::string str() const; + QPID_COMMON_EXTERN std::string str() const; template <class S> void serialize(S& s) { s.raw(begin(), size()); @@ -76,10 +78,10 @@ struct Uuid : public boost::array<uint8_t, 16> { }; /** Print in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */ -std::ostream& operator<<(std::ostream&, Uuid); +QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, Uuid); /** Read from format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */ -std::istream& operator>>(std::istream&, Uuid&); +QPID_COMMON_EXTERN std::istream& operator>>(std::istream&, Uuid&); }} // namespace qpid::framing diff --git a/qpid/cpp/src/qpid/log/Logger.h b/qpid/cpp/src/qpid/log/Logger.h index 539c1c851b..0cbd7685d6 100644 --- a/qpid/cpp/src/qpid/log/Logger.h +++ b/qpid/cpp/src/qpid/log/Logger.h @@ -18,6 +18,7 @@ #include <boost/ptr_container/ptr_vector.hpp> #include <boost/noncopyable.hpp> #include <set> +#include "qpid/CommonImportExport.h" namespace qpid { namespace log { @@ -48,48 +49,48 @@ class Logger : private boost::noncopyable { */ class Output { public: - Output(); - virtual ~Output(); + QPID_COMMON_EXTERN Output(); + QPID_COMMON_EXTERN virtual ~Output(); /** Receives the statemnt of origin and formatted message to log. */ virtual void log(const Statement&, const std::string&) =0; }; - static Logger& instance(); + QPID_COMMON_EXTERN static Logger& instance(); - Logger(); - ~Logger(); + QPID_COMMON_EXTERN Logger(); + QPID_COMMON_EXTERN ~Logger(); /** Select the messages to be logged. */ - void select(const Selector& s); + QPID_COMMON_EXTERN void select(const Selector& s); /** Set the formatting flags, bitwise OR of FormatFlag values. */ - void format(int formatFlags); + QPID_COMMON_EXTERN void format(int formatFlags); /** Set format flags from options object. *@returns computed flags. */ - int format(const Options&); + QPID_COMMON_EXTERN int format(const Options&); /** Configure logger from Options */ - void configure(const Options& o); + QPID_COMMON_EXTERN void configure(const Options& o); /** Add a statement. */ - void add(Statement& s); + QPID_COMMON_EXTERN void add(Statement& s); /** Log a message. */ - void log(const Statement&, const std::string&); + QPID_COMMON_EXTERN void log(const Statement&, const std::string&); /** Add an output destination for messages */ - void output(std::auto_ptr<Output> out); + QPID_COMMON_EXTERN void output(std::auto_ptr<Output> out); /** Set a prefix for all messages */ - void setPrefix(const std::string& prefix); + QPID_COMMON_EXTERN void setPrefix(const std::string& prefix); /** Reset the logger. */ - void clear(); + QPID_COMMON_EXTERN void clear(); /** Get the options used to configure the logger. */ - const Options& getOptions() const { return options; } + QPID_COMMON_EXTERN const Options& getOptions() const { return options; } private: diff --git a/qpid/cpp/src/qpid/log/Options.h b/qpid/cpp/src/qpid/log/Options.h index 8a3c352d14..5e7bd433af 100644 --- a/qpid/cpp/src/qpid/log/Options.h +++ b/qpid/cpp/src/qpid/log/Options.h @@ -19,6 +19,7 @@ * */ #include "qpid/Options.h" +#include "qpid/CommonImportExport.h" #include "SinkOptions.h" #include <iosfwd> #include <memory> @@ -29,11 +30,11 @@ namespace log { /** Logging options for config parser. */ struct Options : public qpid::Options { /** Pass argv[0] for use in syslog output */ - Options(const std::string& argv0_=std::string(), + QPID_COMMON_EXTERN Options(const std::string& argv0_=std::string(), const std::string& name_="Logging options"); - Options(const Options &); + QPID_COMMON_EXTERN Options(const Options &); - Options& operator=(const Options&); + QPID_COMMON_EXTERN Options& operator=(const Options&); std::string argv0; std::string name; diff --git a/qpid/cpp/src/qpid/log/OstreamOutput.h b/qpid/cpp/src/qpid/log/OstreamOutput.h index 8bbfc8c38b..8df38468ad 100644 --- a/qpid/cpp/src/qpid/log/OstreamOutput.h +++ b/qpid/cpp/src/qpid/log/OstreamOutput.h @@ -26,8 +26,8 @@ namespace log { */ class OstreamOutput : public qpid::log::Logger::Output { public: - OstreamOutput(std::ostream& o); - OstreamOutput(const std::string& file); + QPID_COMMON_EXTERN OstreamOutput(std::ostream& o); + QPID_COMMON_EXTERN OstreamOutput(const std::string& file); virtual void log(const Statement&, const std::string& m); diff --git a/qpid/cpp/src/qpid/log/Selector.cpp b/qpid/cpp/src/qpid/log/Selector.cpp index 4d1c5b6e0c..0a629edc3e 100644 --- a/qpid/cpp/src/qpid/log/Selector.cpp +++ b/qpid/cpp/src/qpid/log/Selector.cpp @@ -20,6 +20,7 @@ #include "Options.h" #include <boost/bind.hpp> #include <algorithm> +#include <string.h> namespace qpid { namespace log { diff --git a/qpid/cpp/src/qpid/log/Selector.h b/qpid/cpp/src/qpid/log/Selector.h index 705abfeb5d..070ffd4abf 100644 --- a/qpid/cpp/src/qpid/log/Selector.h +++ b/qpid/cpp/src/qpid/log/Selector.h @@ -20,6 +20,7 @@ */ #include "Statement.h" +#include "qpid/CommonImportExport.h" #include <vector> namespace qpid { @@ -37,7 +38,7 @@ class Selector { Selector() {} /** Set selector from Options */ - Selector(const Options&); + QPID_COMMON_EXTERN Selector(const Options&); /** Equavlient to: Selector s; s.enable(l, s) */ Selector(Level l, const std::string& s=std::string()) { @@ -54,10 +55,10 @@ class Selector { } /** Enable based on a 'level[+]:file' string */ - void enable(const std::string& enableStr); + QPID_COMMON_EXTERN void enable(const std::string& enableStr); /** True if level is enabled for file. */ - bool isEnabled(Level level, const char* function); + QPID_COMMON_EXTERN bool isEnabled(Level level, const char* function); private: std::vector<std::string> substrings[LevelTraits::COUNT]; diff --git a/qpid/cpp/src/qpid/log/Statement.h b/qpid/cpp/src/qpid/log/Statement.h index 3c67b04b20..445f635cdd 100644 --- a/qpid/cpp/src/qpid/log/Statement.h +++ b/qpid/cpp/src/qpid/log/Statement.h @@ -20,7 +20,7 @@ */ #include "qpid/Msg.h" - +#include "qpid/CommonImportExport.h" #include <boost/current_function.hpp> namespace qpid { @@ -63,10 +63,10 @@ struct Statement { const char* function; Level level; - void log(const std::string& message); + QPID_COMMON_EXTERN void log(const std::string& message); struct Initializer { - Initializer(Statement& s); + QPID_COMMON_EXTERN Initializer(Statement& s); Statement& statement; }; }; diff --git a/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp b/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp index 9d51358e2e..985cb32c5c 100644 --- a/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp +++ b/qpid/cpp/src/qpid/log/posix/SinkOptions.cpp @@ -42,10 +42,14 @@ public: struct NameValue { const char* name; int value; }; NameValue nameValue[] = { { "AUTH", LOG_AUTH }, +#ifdef HAVE_LOG_AUTHPRIV { "AUTHPRIV", LOG_AUTHPRIV }, +#endif { "CRON", LOG_CRON }, { "DAEMON", LOG_DAEMON }, +#ifdef HAVE_LOG_FTP { "FTP", LOG_FTP }, +#endif { "KERN", LOG_KERN }, { "LOCAL0", LOG_LOCAL0 }, { "LOCAL1", LOG_LOCAL1 }, @@ -72,7 +76,7 @@ public: int value(const string& name) const { string key(name); - transform(key.begin(), key.end(), key.begin(), ::toupper); + std::transform(key.begin(), key.end(), key.begin(), ::toupper); ByName::const_iterator i = byName.find(key); if (i == byName.end()) throw Exception("Not a valid syslog facility: " + name); diff --git a/qpid/cpp/src/qpid/log/windows/SinkOptions.h b/qpid/cpp/src/qpid/log/windows/SinkOptions.h index d14e9352be..605822fd46 100644 --- a/qpid/cpp/src/qpid/log/windows/SinkOptions.h +++ b/qpid/cpp/src/qpid/log/windows/SinkOptions.h @@ -27,20 +27,20 @@ namespace log { namespace windows { struct SinkOptions : public qpid::log::SinkOptions { - SinkOptions(const std::string& argv0); + QPID_COMMON_EXTERN SinkOptions(const std::string& argv0); virtual ~SinkOptions() {} - virtual qpid::log::SinkOptions& operator=(const qpid::log::SinkOptions& rhs); + QPID_COMMON_EXTERN virtual qpid::log::SinkOptions& operator=(const qpid::log::SinkOptions& rhs); // This allows the caller to indicate that there's no normal outputs // available. For example, when running as a service. In these cases, the // platform's "syslog"-type output should replace the default stderr // unless some other sink has been selected. - virtual void detached(void); + QPID_COMMON_EXTERN virtual void detached(void); // The Logger acting on these options calls setup() to request any // Sinks be set up and fed back to the logger. - virtual void setup(qpid::log::Logger *logger); + QPID_COMMON_EXTERN virtual void setup(qpid::log::Logger *logger); bool logToStderr; bool logToStdout; diff --git a/qpid/cpp/src/qpid/management/Manageable.h b/qpid/cpp/src/qpid/management/Manageable.h index b4d80d8fad..ededa6141e 100644 --- a/qpid/cpp/src/qpid/management/Manageable.h +++ b/qpid/cpp/src/qpid/management/Manageable.h @@ -23,11 +23,12 @@ #include "ManagementObject.h" #include "Args.h" #include <string> +#include "qpid/CommonImportExport.h" namespace qpid { namespace management { -class Manageable +class QPID_COMMON_EXTERN Manageable { public: diff --git a/qpid/cpp/src/qpid/management/ManagementBroker.cpp b/qpid/cpp/src/qpid/management/ManagementBroker.cpp index 0f96e97fb0..19300ef1af 100644 --- a/qpid/cpp/src/qpid/management/ManagementBroker.cpp +++ b/qpid/cpp/src/qpid/management/ManagementBroker.cpp @@ -80,7 +80,7 @@ ManagementBroker::RemoteAgent::~RemoteAgent () } ManagementBroker::ManagementBroker () : - threadPoolSize(1), interval(10), broker(0) + threadPoolSize(1), interval(10), broker(0), startTime(uint64_t(Duration(now()))) { nextObjectId = 1; brokerBank = 1; @@ -346,6 +346,9 @@ void ManagementBroker::periodicProcessing (void) string routingKey; list<pair<ObjectId, ManagementObject*> > deleteList; + uint64_t uptime = uint64_t(Duration(now())) - startTime; + static_cast<_qmf::Broker*>(broker->GetManagementObject())->set_uptime(uptime); + moveNewObjectsLH(); if (clientWasAdded) { @@ -515,6 +518,7 @@ void ManagementBroker::handleMethodRequestLH (Buffer& inBuffer, string replyToKe else try { outBuffer.record(); + Mutex::ScopedUnlock u(userLock); iter->second->doMethod(methodName, inBuffer, outBuffer); } catch(exception& e) { outBuffer.restore(); @@ -844,6 +848,9 @@ void ManagementBroker::handleGetQueryLH (Buffer& inBuffer, string replyToKey, ui Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE); uint32_t outLen; + if (object->getConfigChanged() || object->getInstChanged()) + object->setUpdateTime(); + encodeHeader(outBuffer, 'g', sequence); object->writeProperties(outBuffer); object->writeStatistics(outBuffer, true); @@ -865,6 +872,9 @@ void ManagementBroker::handleGetQueryLH (Buffer& inBuffer, string replyToKey, ui Buffer outBuffer (outputBuffer, MA_BUFFER_SIZE); uint32_t outLen; + if (object->getConfigChanged() || object->getInstChanged()) + object->setUpdateTime(); + encodeHeader(outBuffer, 'g', sequence); object->writeProperties(outBuffer); object->writeStatistics(outBuffer, true); diff --git a/qpid/cpp/src/qpid/management/ManagementBroker.h b/qpid/cpp/src/qpid/management/ManagementBroker.h index f65d6a345e..a57f73be15 100644 --- a/qpid/cpp/src/qpid/management/ManagementBroker.h +++ b/qpid/cpp/src/qpid/management/ManagementBroker.h @@ -182,6 +182,7 @@ private: uint32_t nextRemoteBank; uint32_t nextRequestSequence; bool clientWasAdded; + const uint64_t startTime; std::auto_ptr<IdAllocator> allocator; diff --git a/qpid/cpp/src/qpid/management/ManagementObject.h b/qpid/cpp/src/qpid/management/ManagementObject.h index fbdad347b8..498169318d 100644 --- a/qpid/cpp/src/qpid/management/ManagementObject.h +++ b/qpid/cpp/src/qpid/management/ManagementObject.h @@ -25,6 +25,7 @@ #include "qpid/sys/Time.h" #include "qpid/sys/Mutex.h" #include <qpid/framing/Buffer.h> +#include "qpid/CommonImportExport.h" #include <map> namespace qpid { @@ -41,7 +42,7 @@ private: uint64_t first; public: AgentAttachment() : first(0) {} - void setBanks(uint32_t broker, uint32_t bank); + QPID_COMMON_EXTERN void setBanks(uint32_t broker, uint32_t bank); uint64_t getFirst() const { return first; } }; @@ -53,17 +54,17 @@ protected: uint64_t second; void fromString(const std::string&); public: - ObjectId() : agent(0), first(0), second(0) {} - ObjectId(framing::Buffer& buf) : agent(0) { decode(buf); } - ObjectId(uint8_t flags, uint16_t seq, uint32_t broker, uint32_t bank, uint64_t object); - ObjectId(AgentAttachment* _agent, uint8_t flags, uint16_t seq, uint64_t object); - ObjectId(std::istream&); - ObjectId(const std::string&); - bool operator==(const ObjectId &other) const; - bool operator<(const ObjectId &other) const; - void encode(framing::Buffer& buffer); - void decode(framing::Buffer& buffer); - friend std::ostream& operator<<(std::ostream&, const ObjectId&); + QPID_COMMON_EXTERN ObjectId() : agent(0), first(0), second(0) {} + QPID_COMMON_EXTERN ObjectId(framing::Buffer& buf) : agent(0) { decode(buf); } + QPID_COMMON_EXTERN ObjectId(uint8_t flags, uint16_t seq, uint32_t broker, uint32_t bank, uint64_t object); + QPID_COMMON_EXTERN ObjectId(AgentAttachment* _agent, uint8_t flags, uint16_t seq, uint64_t object); + QPID_COMMON_EXTERN ObjectId(std::istream&); + QPID_COMMON_EXTERN ObjectId(const std::string&); + QPID_COMMON_EXTERN bool operator==(const ObjectId &other) const; + QPID_COMMON_EXTERN bool operator<(const ObjectId &other) const; + QPID_COMMON_EXTERN void encode(framing::Buffer& buffer); + QPID_COMMON_EXTERN void decode(framing::Buffer& buffer); + friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const ObjectId&); }; class ManagementItem { @@ -128,8 +129,8 @@ class ManagementObject : public ManagementItem static int nextThreadIndex; bool forcePublish; - int getThreadIndex(); - void writeTimestamps(qpid::framing::Buffer& buf); + QPID_COMMON_EXTERN int getThreadIndex(); + QPID_COMMON_EXTERN void writeTimestamps(qpid::framing::Buffer& buf); public: typedef void (*writeSchemaCall_t) (qpid::framing::Buffer&); @@ -148,7 +149,7 @@ class ManagementObject : public ManagementItem virtual void doMethod(std::string& methodName, qpid::framing::Buffer& inBuf, qpid::framing::Buffer& outBuf) = 0; - virtual void setReference(ObjectId objectId); + QPID_COMMON_EXTERN virtual void setReference(ObjectId objectId); virtual std::string& getClassName() const = 0; virtual std::string& getPackageName() const = 0; diff --git a/qpid/cpp/src/qpid/replication/ReplicatingEventListener.cpp b/qpid/cpp/src/qpid/replication/ReplicatingEventListener.cpp index 2d8af3b052..60d5fffc0b 100644 --- a/qpid/cpp/src/qpid/replication/ReplicatingEventListener.cpp +++ b/qpid/cpp/src/qpid/replication/ReplicatingEventListener.cpp @@ -21,6 +21,7 @@ #include "ReplicatingEventListener.h" #include "constants.h" #include "qpid/broker/Broker.h" +#include "qpid/broker/DeliverableMessage.h" #include "qpid/broker/QueueEvents.h" #include "qpid/framing/AMQFrame.h" #include "qpid/framing/FrameHandler.h" @@ -57,11 +58,12 @@ void ReplicatingEventListener::deliverDequeueMessage(const QueuedMessage& dequeu { FieldTable headers; headers.setString(REPLICATION_TARGET_QUEUE, dequeued.queue->getName()); - headers.setInt(REPLICATION_EVENT_SEQNO, ++sequence); headers.setInt(REPLICATION_EVENT_TYPE, DEQUEUE); headers.setInt(DEQUEUED_MESSAGE_POSITION, dequeued.position); boost::intrusive_ptr<Message> msg(createMessage(headers)); - queue->deliver(msg); + DeliveryProperties* props = msg->getFrames().getHeaders()->get<DeliveryProperties>(true); + props->setRoutingKey(dequeued.queue->getName()); + route(msg); } void ReplicatingEventListener::deliverEnqueueMessage(const QueuedMessage& enqueued) @@ -69,11 +71,27 @@ void ReplicatingEventListener::deliverEnqueueMessage(const QueuedMessage& enqueu boost::intrusive_ptr<Message> msg(cloneMessage(*(enqueued.queue), enqueued.payload)); FieldTable& headers = msg->getProperties<MessageProperties>()->getApplicationHeaders(); headers.setString(REPLICATION_TARGET_QUEUE, enqueued.queue->getName()); - headers.setInt(REPLICATION_EVENT_SEQNO, ++sequence); headers.setInt(REPLICATION_EVENT_TYPE, ENQUEUE); - queue->deliver(msg); + route(msg); } +void ReplicatingEventListener::route(boost::intrusive_ptr<qpid::broker::Message> msg) +{ + try { + if (exchange) { + DeliverableMessage deliverable(msg); + exchange->route(deliverable, msg->getRoutingKey(), msg->getApplicationHeaders()); + } else if (queue) { + queue->deliver(msg); + } else { + QPID_LOG(error, "Cannot route replication event, neither replication queue nor exchange configured"); + } + } catch (const std::exception& e) { + QPID_LOG(error, "Error enqueing replication event: " << e.what()); + } +} + + boost::intrusive_ptr<Message> ReplicatingEventListener::createMessage(const FieldTable& headers) { boost::intrusive_ptr<Message> msg(new Message()); @@ -129,30 +147,49 @@ Options* ReplicatingEventListener::getOptions() void ReplicatingEventListener::initialize(Plugin::Target& target) { - Broker* broker = dynamic_cast<broker::Broker*>(&target); - if (broker && !options.queue.empty()) { - if (options.createQueue) { - queue = broker->getQueues().declare(options.queue).first; - } else { - queue = broker->getQueues().find(options.queue); - } - if (queue) { - QueueEvents::EventListener callback = boost::bind(&ReplicatingEventListener::handle, this, _1); - broker->getQueueEvents().registerListener(options.name, callback); - QPID_LOG(info, "Registered replicating queue event listener"); - } else { - QPID_LOG(error, "Replication queue named '" << options.queue << "' does not exist; replication plugin disabled."); - } - } + Broker* broker = dynamic_cast<broker::Broker*>(&target); + if (broker) { + broker->addFinalizer(boost::bind(&ReplicatingEventListener::shutdown, this)); + if (!options.exchange.empty()) { + if (!options.queue.empty()) { + QPID_LOG(warning, "Replication queue option ignored as replication exchange has been specified"); + } + try { + exchange = broker->getExchanges().declare(options.exchange, options.exchangeType).first; + } catch (const UnknownExchangeTypeException&) { + QPID_LOG(error, "Replication disabled due to invalid type: " << options.exchangeType); + } + } else if (!options.queue.empty()) { + if (options.createQueue) { + queue = broker->getQueues().declare(options.queue).first; + } else { + queue = broker->getQueues().find(options.queue); + } + if (queue) { + queue->insertSequenceNumbers(REPLICATION_EVENT_SEQNO); + } else { + QPID_LOG(error, "Replication queue named '" << options.queue << "' does not exist; replication plugin disabled."); + } + } + if (queue || exchange) { + QueueEvents::EventListener callback = boost::bind(&ReplicatingEventListener::handle, this, _1); + broker->getQueueEvents().registerListener(options.name, callback); + QPID_LOG(info, "Registered replicating queue event listener"); + } + } } void ReplicatingEventListener::earlyInitialize(Target&) {} +void ReplicatingEventListener::shutdown() { queue.reset(); exchange.reset(); } ReplicatingEventListener::PluginOptions::PluginOptions() : Options("Queue Replication Options"), - name("replicator"), + exchangeType("direct"), + name("replicator"), createQueue(false) { addOptions() + ("replication-exchange-name", optValue(exchange, "EXCHANGE"), "Exchange to which events for other queues are routed") + ("replication-exchange-type", optValue(exchangeType, "direct|topic etc"), "Type of exchange to use") ("replication-queue", optValue(queue, "QUEUE"), "Queue on which events for other queues are recorded") ("replication-listener-name", optValue(name, "NAME"), "name by which to register the replicating event listener") ("create-replication-queue", optValue(createQueue), "if set, the replication will be created if it does not exist"); diff --git a/qpid/cpp/src/qpid/replication/ReplicatingEventListener.h b/qpid/cpp/src/qpid/replication/ReplicatingEventListener.h index 7616c7ac8a..74418d00e6 100644 --- a/qpid/cpp/src/qpid/replication/ReplicatingEventListener.h +++ b/qpid/cpp/src/qpid/replication/ReplicatingEventListener.h @@ -24,6 +24,7 @@ #include "qpid/Plugin.h" #include "qpid/Options.h" +#include "qpid/broker/Exchange.h" #include "qpid/broker/Message.h" #include "qpid/broker/Queue.h" #include "qpid/broker/QueueEvents.h" @@ -50,6 +51,8 @@ class ReplicatingEventListener : public Plugin struct PluginOptions : public Options { std::string queue; + std::string exchange; + std::string exchangeType; std::string name; bool createQueue; @@ -58,10 +61,12 @@ class ReplicatingEventListener : public Plugin PluginOptions options; qpid::broker::Queue::shared_ptr queue; - qpid::framing::SequenceNumber sequence; + qpid::broker::Exchange::shared_ptr exchange; void deliverDequeueMessage(const qpid::broker::QueuedMessage& enqueued); void deliverEnqueueMessage(const qpid::broker::QueuedMessage& enqueued); + void route(boost::intrusive_ptr<qpid::broker::Message>); + void shutdown(); boost::intrusive_ptr<qpid::broker::Message> createMessage(const qpid::framing::FieldTable& headers); boost::intrusive_ptr<qpid::broker::Message> cloneMessage(qpid::broker::Queue& queue, diff --git a/qpid/cpp/src/qpid/replication/ReplicationExchange.cpp b/qpid/cpp/src/qpid/replication/ReplicationExchange.cpp index 639cfb5d2e..29cdf21bc6 100644 --- a/qpid/cpp/src/qpid/replication/ReplicationExchange.cpp +++ b/qpid/cpp/src/qpid/replication/ReplicationExchange.cpp @@ -34,11 +34,13 @@ using namespace qpid::broker; using namespace qpid::framing; using namespace qpid::replication::constants; +const std::string SEQUENCE_VALUE("qpid.replication-event.sequence"); ReplicationExchange::ReplicationExchange(const std::string& name, bool durable, const FieldTable& args, QueueRegistry& qr, Manageable* parent) - : Exchange(name, durable, args, parent), queues(qr), init(false) {} + : Exchange(name, durable, args, parent), queues(qr), sequence(args.getAsInt64(SEQUENCE_VALUE)), init(false) + {} std::string ReplicationExchange::getType() const { return typeName; } @@ -68,31 +70,39 @@ void ReplicationExchange::handleEnqueueEvent(const FieldTable* args, Deliverable { std::string queueName = args->getAsString(REPLICATION_TARGET_QUEUE); Queue::shared_ptr queue = queues.find(queueName); - FieldTable& headers = msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders(); - headers.erase(REPLICATION_TARGET_QUEUE); - headers.erase(REPLICATION_EVENT_SEQNO); - headers.erase(REPLICATION_EVENT_TYPE); - msg.deliverTo(queue); - QPID_LOG(debug, "Enqueued replicated message onto " << queue); + if (queue) { + FieldTable& headers = msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders(); + headers.erase(REPLICATION_TARGET_QUEUE); + headers.erase(REPLICATION_EVENT_SEQNO); + headers.erase(REPLICATION_EVENT_TYPE); + msg.deliverTo(queue); + QPID_LOG(debug, "Enqueued replicated message onto " << queueName); + } else { + QPID_LOG(error, "Cannot enqueue replicated message. Queue " << queueName << " does not exist"); + } } void ReplicationExchange::handleDequeueEvent(const FieldTable* args) { std::string queueName = args->getAsString(REPLICATION_TARGET_QUEUE); Queue::shared_ptr queue = queues.find(queueName); - SequenceNumber position(args->getAsInt(DEQUEUED_MESSAGE_POSITION)); - - QueuedMessage dequeued; - if (queue->acquireMessageAt(position, dequeued)) { - queue->dequeue(0, dequeued); - QPID_LOG(debug, "Processed replicated 'dequeue' event from " << queueName << " at position " << position); + if (queue) { + SequenceNumber position(args->getAsInt(DEQUEUED_MESSAGE_POSITION)); + QueuedMessage dequeued; + if (queue->acquireMessageAt(position, dequeued)) { + queue->dequeue(0, dequeued); + QPID_LOG(debug, "Processed replicated 'dequeue' event from " << queueName << " at position " << position); + } else { + QPID_LOG(warning, "Could not acquire message " << position << " from " << queueName); + } } else { - QPID_LOG(warning, "Could not acquire message " << position << " from " << queueName); + QPID_LOG(error, "Cannot process replicated 'dequeue' event. Queue " << queueName << " does not exist"); } } bool ReplicationExchange::isDuplicate(const FieldTable* args) { + if (!args->get(REPLICATION_EVENT_SEQNO)) return false; SequenceNumber seqno(args->getAsInt(REPLICATION_EVENT_SEQNO)); if (!init) { init = true; @@ -128,6 +138,13 @@ bool ReplicationExchange::isBound(Queue::shared_ptr /*queue*/, const string* con const std::string ReplicationExchange::typeName("replication"); +void ReplicationExchange::encode(Buffer& buffer) const +{ + args.setInt64(std::string(SEQUENCE_VALUE), sequence); + Exchange::encode(buffer); +} + + struct ReplicationExchangePlugin : Plugin { Broker* broker; diff --git a/qpid/cpp/src/qpid/replication/ReplicationExchange.h b/qpid/cpp/src/qpid/replication/ReplicationExchange.h index 897e4a954e..4cc45ed5f5 100644 --- a/qpid/cpp/src/qpid/replication/ReplicationExchange.h +++ b/qpid/cpp/src/qpid/replication/ReplicationExchange.h @@ -22,6 +22,7 @@ * */ #include "qpid/broker/Exchange.h" +#include "qpid/framing/Buffer.h" #include "qpid/framing/SequenceNumber.h" namespace qpid { @@ -58,6 +59,7 @@ class ReplicationExchange : public qpid::broker::Exchange bool isDuplicate(const qpid::framing::FieldTable* args); void handleEnqueueEvent(const qpid::framing::FieldTable* args, qpid::broker::Deliverable& msg); void handleDequeueEvent(const qpid::framing::FieldTable* args); + void encode(framing::Buffer& buffer) const; }; }} // namespace qpid::replication diff --git a/qpid/cpp/src/qpid/sys/AggregateOutput.h b/qpid/cpp/src/qpid/sys/AggregateOutput.h index 1cda4456b4..fcd0d4c2f7 100644 --- a/qpid/cpp/src/qpid/sys/AggregateOutput.h +++ b/qpid/cpp/src/qpid/sys/AggregateOutput.h @@ -24,6 +24,7 @@ #include "Mutex.h" #include "OutputControl.h" #include "OutputTask.h" +#include "qpid/CommonImportExport.h" #include <algorithm> #include <vector> @@ -42,15 +43,15 @@ namespace sys { public: AggregateOutput(OutputControl& c) : next(0), control(c) {}; //this may be called on any thread - void activateOutput(); - void giveReadCredit(int32_t); + QPID_COMMON_EXTERN void activateOutput(); + QPID_COMMON_EXTERN void giveReadCredit(int32_t); //all the following will be called on the same thread - bool doOutput(); - bool hasOutput(); - void addOutputTask(OutputTask* t); - void removeOutputTask(OutputTask* t); - void removeAll(); + QPID_COMMON_EXTERN bool doOutput(); + QPID_COMMON_EXTERN bool hasOutput(); + QPID_COMMON_EXTERN void addOutputTask(OutputTask* t); + QPID_COMMON_EXTERN void removeOutputTask(OutputTask* t); + QPID_COMMON_EXTERN void removeAll(); /** Apply f to each OutputTask* in the tasks list */ template <class F> void eachOutput(F f) { diff --git a/qpid/cpp/src/qpid/sys/AsynchIO.h b/qpid/cpp/src/qpid/sys/AsynchIO.h index ffd4436c2a..fb02183359 100644 --- a/qpid/cpp/src/qpid/sys/AsynchIO.h +++ b/qpid/cpp/src/qpid/sys/AsynchIO.h @@ -22,7 +22,7 @@ */ #include "qpid/sys/IntegerTypes.h" - +#include "qpid/CommonImportExport.h" #include <boost/function.hpp> #include <boost/shared_ptr.hpp> @@ -45,9 +45,9 @@ private: AsynchAcceptorPrivate* impl; public: - AsynchAcceptor(const Socket& s, Callback callback); - ~AsynchAcceptor(); - void start(boost::shared_ptr<Poller> poller); + QPID_COMMON_EXTERN AsynchAcceptor(const Socket& s, Callback callback); + QPID_COMMON_EXTERN ~AsynchAcceptor(); + QPID_COMMON_EXTERN void start(boost::shared_ptr<Poller> poller); }; /* @@ -65,7 +65,7 @@ public: // create a correctly typed object. The platform code also manages // deletes. To correctly manage heaps when needed, the allocate and // delete should both be done from the same class/library. - static AsynchConnector* create(const Socket& s, + QPID_COMMON_EXTERN static AsynchConnector* create(const Socket& s, boost::shared_ptr<Poller> poller, std::string hostname, uint16_t port, @@ -121,7 +121,7 @@ public: // create a correctly typed object. The platform code also manages // deletes. To correctly manage heaps when needed, the allocate and // delete should both be done from the same class/library. - static AsynchIO* create(const Socket& s, + QPID_COMMON_EXTERN static AsynchIO* create(const Socket& s, ReadCallback rCb, EofCallback eofCb, DisconnectCallback disCb, diff --git a/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp b/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp index 3bc05e4bf9..6b7e7b5145 100644 --- a/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp +++ b/qpid/cpp/src/qpid/sys/AsynchIOHandler.cpp @@ -84,10 +84,11 @@ void AsynchIOHandler::giveReadCredit(int32_t credit) { // Check whether we started in the don't about credit state if (readCredit.boolCompareAndSwap(InfiniteCredit, credit)) return; - else if (readCredit.fetchAndAdd(credit) != 0) - return; - // Lock and retest credit to make sure we don't race with decreasing credit + // TODO In theory should be able to use an atomic operation before taking the lock + // but in practice there seems to be an unexplained race in that case ScopedLock<Mutex> l(creditLock); + if (readCredit.fetchAndAdd(credit) != 0) + return; assert(readCredit.get() >= 0); if (readCredit.get() != 0) aio->startReading(); @@ -141,9 +142,10 @@ bool AsynchIOHandler::readbuff(AsynchIO& , AsynchIO::BufferBase* buff) { } // Check here for read credit if (readCredit.get() != InfiniteCredit) { + // TODO In theory should be able to use an atomic operation before taking the lock + // but in practice there seems to be an unexplained race in that case + ScopedLock<Mutex> l(creditLock); if (--readCredit == 0) { - // Lock and retest credit to make sure we don't race with increasing credit - ScopedLock<Mutex> l(creditLock); assert(readCredit.get() >= 0); if (readCredit.get() == 0) { aio->stopReading(); diff --git a/qpid/cpp/src/qpid/sys/AsynchIOHandler.h b/qpid/cpp/src/qpid/sys/AsynchIOHandler.h index fa020fbce4..9f1d043b62 100644 --- a/qpid/cpp/src/qpid/sys/AsynchIOHandler.h +++ b/qpid/cpp/src/qpid/sys/AsynchIOHandler.h @@ -25,6 +25,7 @@ #include "ConnectionCodec.h" #include "AtomicValue.h" #include "Mutex.h" +#include "qpid/CommonImportExport.h" namespace qpid { @@ -52,26 +53,26 @@ class AsynchIOHandler : public OutputControl { void write(const framing::ProtocolInitiation&); public: - AsynchIOHandler(std::string id, ConnectionCodec::Factory* f); - ~AsynchIOHandler(); - void init(AsynchIO* a, int numBuffs); + QPID_COMMON_EXTERN AsynchIOHandler(std::string id, ConnectionCodec::Factory* f); + QPID_COMMON_EXTERN ~AsynchIOHandler(); + QPID_COMMON_EXTERN void init(AsynchIO* a, int numBuffs); - void setClient() { isClient = true; } + QPID_COMMON_EXTERN void setClient() { isClient = true; } // Output side - void close(); - void activateOutput(); - void giveReadCredit(int32_t credit); + QPID_COMMON_EXTERN void close(); + QPID_COMMON_EXTERN void activateOutput(); + QPID_COMMON_EXTERN void giveReadCredit(int32_t credit); // Input side - bool readbuff(AsynchIO& aio, AsynchIOBufferBase* buff); - void eof(AsynchIO& aio); - void disconnect(AsynchIO& aio); + QPID_COMMON_EXTERN bool readbuff(AsynchIO& aio, AsynchIOBufferBase* buff); + QPID_COMMON_EXTERN void eof(AsynchIO& aio); + QPID_COMMON_EXTERN void disconnect(AsynchIO& aio); // Notifications - void nobuffs(AsynchIO& aio); - void idle(AsynchIO& aio); - void closedSocket(AsynchIO& aio, const Socket& s); + QPID_COMMON_EXTERN void nobuffs(AsynchIO& aio); + QPID_COMMON_EXTERN void idle(AsynchIO& aio); + QPID_COMMON_EXTERN void closedSocket(AsynchIO& aio, const Socket& s); }; }} // namespace qpid::sys diff --git a/qpid/cpp/src/qpid/sys/Codec.h b/qpid/cpp/src/qpid/sys/Codec.h index f9645f554e..ace721fbcc 100644 --- a/qpid/cpp/src/qpid/sys/Codec.h +++ b/qpid/cpp/src/qpid/sys/Codec.h @@ -38,11 +38,11 @@ class Codec * @return may be less than size if there was incomplete * data at the end of the buffer. */ - virtual size_t decode(const char* buffer, size_t size) = 0; + virtual std::size_t decode(const char* buffer, std::size_t size) = 0; /** Encode into buffer, return number of bytes encoded */ - virtual size_t encode(const char* buffer, size_t size) = 0; + virtual std::size_t encode(const char* buffer, std::size_t size) = 0; /** Return true if we have data to encode */ virtual bool canEncode() = 0; diff --git a/qpid/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h b/qpid/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h index df6de89982..32809d86a1 100644 --- a/qpid/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h +++ b/qpid/cpp/src/qpid/sys/ConnectionOutputHandlerPtr.h @@ -30,7 +30,7 @@ namespace sys { /** * A ConnectionOutputHandler that delegates to another * ConnectionOutputHandler. Allows the "real" ConnectionOutputHandler - * to be changed modified without updating all the pointers/references + * to be changed without updating all the pointers/references * using the ConnectionOutputHandlerPtr */ class ConnectionOutputHandlerPtr : public ConnectionOutputHandler diff --git a/qpid/cpp/src/qpid/sys/CopyOnWriteArray.h b/qpid/cpp/src/qpid/sys/CopyOnWriteArray.h index a09ee9d441..577a475afd 100644 --- a/qpid/cpp/src/qpid/sys/CopyOnWriteArray.h +++ b/qpid/cpp/src/qpid/sys/CopyOnWriteArray.h @@ -80,7 +80,7 @@ public: bool add_unless(T& t, F f) { Mutex::ScopedLock l(lock); - if (array && find_if(array->begin(), array->end(), f) != array->end()) { + if (array && std::find_if(array->begin(), array->end(), f) != array->end()) { return false; } else { ArrayPtr copy(array ? new std::vector<T>(*array) : new std::vector<T>()); diff --git a/qpid/cpp/src/qpid/sys/DispatchHandle.cpp b/qpid/cpp/src/qpid/sys/DispatchHandle.cpp index cbdee7eda6..cd7dec7fa6 100644 --- a/qpid/cpp/src/qpid/sys/DispatchHandle.cpp +++ b/qpid/cpp/src/qpid/sys/DispatchHandle.cpp @@ -21,6 +21,8 @@ #include "DispatchHandle.h" +#include <algorithm> + #include <boost/cast.hpp> #include <assert.h> @@ -29,7 +31,6 @@ namespace qpid { namespace sys { DispatchHandle::~DispatchHandle() { - stopWatch(); } void DispatchHandle::startWatch(Poller::shared_ptr poller0) { @@ -37,13 +38,21 @@ void DispatchHandle::startWatch(Poller::shared_ptr poller0) { bool w = writableCallback; ScopedLock<Mutex> lock(stateLock); - assert(state == IDLE); + assert(state == IDLE || state == DELAYED_IDLE); // If no callbacks set then do nothing (that is what we were asked to do!) // TODO: Maybe this should be an assert instead if (!r && !w) { - state = INACTIVE; - return; + switch (state) { + case IDLE: + state = INACTIVE; + return; + case DELAYED_IDLE: + state = DELAYED_INACTIVE; + return; + default: + assert(state == IDLE || state == DELAYED_IDLE); + } } Poller::Direction d = r ? @@ -53,9 +62,20 @@ void DispatchHandle::startWatch(Poller::shared_ptr poller0) { poller = poller0; poller->addFd(*this, d); - state = r ? - (w ? ACTIVE_RW : ACTIVE_R) : - ACTIVE_W; + switch (state) { + case IDLE: + state = r ? + (w ? ACTIVE_RW : ACTIVE_R) : + ACTIVE_W; + return; + case DELAYED_IDLE: + state = r ? + (w ? DELAYED_RW : DELAYED_R) : + DELAYED_W; + return; + default: + assert(state == IDLE || state == DELAYED_IDLE); + } } void DispatchHandle::rewatch() { @@ -93,6 +113,8 @@ void DispatchHandle::rewatch() { case ACTIVE_RW: // Don't need to do anything already waiting for readable/writable break; + case ACTIVE_DELETE: + assert(state != ACTIVE_DELETE); } } @@ -130,6 +152,8 @@ void DispatchHandle::rewatchRead() { poller->modFd(*this, Poller::INOUT); state = ACTIVE_RW; break; + case ACTIVE_DELETE: + assert(state != ACTIVE_DELETE); } } @@ -167,6 +191,8 @@ void DispatchHandle::rewatchWrite() { case ACTIVE_RW: // Nothing to do: already waiting for writable break; + case ACTIVE_DELETE: + assert(state != ACTIVE_DELETE); } } @@ -203,6 +229,8 @@ void DispatchHandle::unwatchRead() { case ACTIVE_W: case INACTIVE: break; + case ACTIVE_DELETE: + assert(state != ACTIVE_DELETE); } } @@ -239,6 +267,8 @@ void DispatchHandle::unwatchWrite() { case ACTIVE_R: case INACTIVE: break; + case ACTIVE_DELETE: + assert(state != ACTIVE_DELETE); } } @@ -261,6 +291,8 @@ void DispatchHandle::unwatch() { poller->modFd(*this, Poller::NONE); state = INACTIVE; break; + case ACTIVE_DELETE: + assert(state != ACTIVE_DELETE); } } @@ -280,47 +312,72 @@ void DispatchHandle::stopWatch() { default: state = IDLE; break; + case ACTIVE_DELETE: + assert(state != ACTIVE_DELETE); } assert(poller); poller->delFd(*this); poller.reset(); } +// If we are already in the IDLE state we can't do the callback as we might +// race to delete and callback at the same time +// TODO: might be able to fix this by adding a new state, but would make +// the state machine even more complex void DispatchHandle::call(Callback iCb) { assert(iCb); ScopedLock<Mutex> lock(stateLock); - interruptedCallbacks.push(iCb); - - (void) poller->interrupt(*this); + switch (state) { + case IDLE: + case ACTIVE_DELETE: + assert(false); + return; + default: + interruptedCallbacks.push(iCb); + assert(poller); + (void) poller->interrupt(*this); + } } // The slightly strange switch structure // is to ensure that the lock is released before // we do the delete void DispatchHandle::doDelete() { - // Ensure that we're no longer watching anything - stopWatch(); - - // If we're in the middle of a callback defer the delete { ScopedLock<Mutex> lock(stateLock); + // Ensure that we're no longer watching anything switch (state) { + case DELAYED_R: + case DELAYED_W: + case DELAYED_RW: + case DELAYED_INACTIVE: + assert(poller); + poller->delFd(*this); + poller.reset(); + // Fallthrough case DELAYED_IDLE: - case DELAYED_DELETE: state = DELAYED_DELETE; + // Fallthrough + case DELAYED_DELETE: + case ACTIVE_DELETE: return; case IDLE: break; default: - // Can only get out of stopWatch() in DELAYED_IDLE/DELAYED_DELETE/IDLE states - assert(false); + state = ACTIVE_DELETE; + assert(poller); + (void) poller->interrupt(*this); + poller->delFd(*this); + return; } } - // If we're not then do it right away + // If we're IDLE we can do this right away delete this; } void DispatchHandle::processEvent(Poller::EventType type) { + CallbackQueue callbacks; + // Note that we are now doing the callbacks { ScopedLock<Mutex> lock(stateLock); @@ -336,6 +393,16 @@ void DispatchHandle::processEvent(Poller::EventType type) { case ACTIVE_RW: state = DELAYED_RW; break; + case ACTIVE_DELETE: + // Need to make sure we clean up any pending callbacks in this case + std::swap(callbacks, interruptedCallbacks); + goto saybyebye; + // Can get here in idle if we are stopped in a different thread + // just after we return with this handle in Poller::wait + case IDLE: + // Can get here in INACTIVE if a non connection thread unwatches + // whilst we were stuck in the above lock + case INACTIVE: // Can only get here in a DELAYED_* state in the rare case // that we're already here for reading and we get activated for // writing and we can write (it might be possible the other way @@ -348,9 +415,9 @@ void DispatchHandle::processEvent(Poller::EventType type) { case DELAYED_IDLE: case DELAYED_DELETE: return; - default: - assert(false); } + + std::swap(callbacks, interruptedCallbacks); } // Do callbacks - whilst we are doing the callbacks we are prevented from processing @@ -378,8 +445,8 @@ void DispatchHandle::processEvent(Poller::EventType type) { break; case Poller::INTERRUPTED: { - ScopedLock<Mutex> lock(stateLock); - assert(interruptedCallbacks.size() > 0); + // We could only be interrupted if we also had a callback to do + assert(callbacks.size() > 0); // We'll actually do the interrupt below } break; @@ -387,16 +454,18 @@ void DispatchHandle::processEvent(Poller::EventType type) { assert(false); } - { - ScopedLock<Mutex> lock(stateLock); - // If we've got a pending interrupt do it now - while (interruptedCallbacks.size() > 0) { - Callback cb = interruptedCallbacks.front(); + // If we have any callbacks do them now - + // (because we use a copy from before the previous callbacks we won't + // do anything yet that was just added) + while (callbacks.size() > 0) { + Callback cb = callbacks.front(); assert(cb); cb(*this); - interruptedCallbacks.pop(); + callbacks.pop(); } + { + ScopedLock<Mutex> lock(stateLock); // If any of the callbacks re-enabled reading/writing then actually // do it now switch (state) { @@ -425,7 +494,9 @@ void DispatchHandle::processEvent(Poller::EventType type) { case DELAYED_DELETE: break; } - } + } + +saybyebye: delete this; } diff --git a/qpid/cpp/src/qpid/sys/DispatchHandle.h b/qpid/cpp/src/qpid/sys/DispatchHandle.h index ffcbd80f7e..bc9f98775e 100644 --- a/qpid/cpp/src/qpid/sys/DispatchHandle.h +++ b/qpid/cpp/src/qpid/sys/DispatchHandle.h @@ -24,7 +24,7 @@ #include "Poller.h" #include "Mutex.h" - +#include "qpid/CommonImportExport.h" #include <boost/function.hpp> #include <queue> @@ -65,6 +65,7 @@ private: Mutex stateLock; enum { IDLE, INACTIVE, ACTIVE_R, ACTIVE_W, ACTIVE_RW, + ACTIVE_DELETE, DELAYED_IDLE, DELAYED_INACTIVE, DELAYED_R, DELAYED_W, DELAYED_RW, DELAYED_DELETE } state; @@ -82,7 +83,7 @@ public: *@param wCb Callback called when the handle is writable. *@param dCb Callback called when the handle is disconnected. */ - DispatchHandle(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb) : + QPID_COMMON_EXTERN DispatchHandle(const IOHandle& h, Callback rCb, Callback wCb, Callback dCb) : PollerHandle(h), readableCallback(rCb), writableCallback(wCb), @@ -90,42 +91,42 @@ public: state(IDLE) {} - ~DispatchHandle(); + QPID_COMMON_EXTERN ~DispatchHandle(); /** Add this DispatchHandle to the poller to be watched. */ - void startWatch(Poller::shared_ptr poller); + QPID_COMMON_EXTERN void startWatch(Poller::shared_ptr poller); /** Resume watching for all non-0 callbacks. */ - void rewatch(); + QPID_COMMON_EXTERN void rewatch(); /** Resume watching for read only. */ - void rewatchRead(); + QPID_COMMON_EXTERN void rewatchRead(); /** Resume watching for write only. */ - void rewatchWrite(); + QPID_COMMON_EXTERN void rewatchWrite(); /** Stop watching temporarily. The DispatchHandle remains associated with the poller and can be re-activated using rewatch. */ - void unwatch(); + QPID_COMMON_EXTERN void unwatch(); /** Stop watching for read */ - void unwatchRead(); + QPID_COMMON_EXTERN void unwatchRead(); /** Stop watching for write */ - void unwatchWrite(); + QPID_COMMON_EXTERN void unwatchWrite(); /** Stop watching permanently. Disassociates from the poller. */ - void stopWatch(); + QPID_COMMON_EXTERN void stopWatch(); /** Interrupt watching this handle and make a serialised callback that respects the * same exclusivity guarantees as the other callbacks */ - void call(Callback iCb); + QPID_COMMON_EXTERN void call(Callback iCb); protected: /** Override to get extra processing done when the DispatchHandle is deleted. */ - void doDelete(); + QPID_COMMON_EXTERN void doDelete(); private: - void processEvent(Poller::EventType dir); + QPID_COMMON_EXTERN void processEvent(Poller::EventType dir); }; class DispatchHandleRef { diff --git a/qpid/cpp/src/qpid/sys/Dispatcher.h b/qpid/cpp/src/qpid/sys/Dispatcher.h index f7c9e8d731..2f3ed10901 100644 --- a/qpid/cpp/src/qpid/sys/Dispatcher.h +++ b/qpid/cpp/src/qpid/sys/Dispatcher.h @@ -24,6 +24,7 @@ #include "Poller.h" #include "Runnable.h" +#include "qpid/CommonImportExport.h" namespace qpid { namespace sys { @@ -32,10 +33,10 @@ class Dispatcher : public Runnable { const Poller::shared_ptr poller; public: - Dispatcher(Poller::shared_ptr poller); - ~Dispatcher(); + QPID_COMMON_EXTERN Dispatcher(Poller::shared_ptr poller); + QPID_COMMON_EXTERN ~Dispatcher(); - void run(); + QPID_COMMON_EXTERN void run(); }; }} diff --git a/qpid/cpp/src/qpid/sys/IOHandle.h b/qpid/cpp/src/qpid/sys/IOHandle.h index 0bf2abbafa..656e5e1efd 100644 --- a/qpid/cpp/src/qpid/sys/IOHandle.h +++ b/qpid/cpp/src/qpid/sys/IOHandle.h @@ -22,6 +22,8 @@ * */ +#include "qpid/CommonImportExport.h" + namespace qpid { namespace sys { @@ -50,8 +52,8 @@ class IOHandle { protected: IOHandlePrivate* const impl; - IOHandle(IOHandlePrivate*); - virtual ~IOHandle(); + IOHandle(IOHandlePrivate*); + QPID_COMMON_EXTERN virtual ~IOHandle(); }; }} diff --git a/qpid/cpp/src/qpid/sys/PollableCondition.h b/qpid/cpp/src/qpid/sys/PollableCondition.h index 56d38f90da..f49fb22cb4 100644 --- a/qpid/cpp/src/qpid/sys/PollableCondition.h +++ b/qpid/cpp/src/qpid/sys/PollableCondition.h @@ -22,7 +22,58 @@ * */ -// Currently only has a posix implementation, add #ifdefs for other platforms as needed. -#include "posix/PollableCondition.h" +#include "qpid/sys/Poller.h" +#include "qpid/CommonImportExport.h" +#include <boost/function.hpp> +#include <boost/shared_ptr.hpp> + + +namespace qpid { +namespace sys { + +class PollableConditionPrivate; + +class PollableCondition { +public: + typedef boost::function1<void, PollableCondition&> Callback; + + QPID_COMMON_EXTERN PollableCondition(const Callback& cb, + const boost::shared_ptr<sys::Poller>& poller); + + QPID_COMMON_EXTERN ~PollableCondition(); + + /** + * Set the condition. Triggers callback to Callback from Poller. + * When callback is made, condition is suspended. Call rearm() to + * resume reacting to the condition. + */ + QPID_COMMON_EXTERN void set(); + + /** + * Get the current state of the condition, then clear it. + * + * @return The state of the condition before it was cleared. + */ + QPID_COMMON_EXTERN bool clear(); + + /** + * Temporarily suspend the ability for the poller to react to the + * condition. It can be rearm()ed later. + */ + QPID_COMMON_EXTERN void disarm(); + + /** + * Reset the ability for the poller to react to the condition. + */ + QPID_COMMON_EXTERN void rearm(); + + private: + PollableConditionPrivate *impl; + + Callback callback; + boost::shared_ptr<sys::Poller> poller; +}; + +}} // namespace qpid::sys #endif /*!QPID_SYS_POLLABLECONDITION_H*/ diff --git a/qpid/cpp/src/qpid/sys/PollableQueue.h b/qpid/cpp/src/qpid/sys/PollableQueue.h index b5ff98c2c7..f8acf0a5f6 100644 --- a/qpid/cpp/src/qpid/sys/PollableQueue.h +++ b/qpid/cpp/src/qpid/sys/PollableQueue.h @@ -23,8 +23,6 @@ */ #include "qpid/sys/PollableCondition.h" -#include "qpid/sys/Dispatcher.h" -#include "qpid/sys/DispatchHandle.h" #include "qpid/sys/Monitor.h" #include "qpid/sys/Thread.h" #include <boost/function.hpp> @@ -38,9 +36,10 @@ namespace sys { class Poller; /** - * A queue that can be polled by sys::Poller. Any thread can push to - * the queue, on wakeup the poller thread processes all items on the - * queue by passing them to a callback in a batch. + * A queue whose item processing is dispatched by sys::Poller. + * Any thread can push to the queue; items pushed trigger an event the Poller + * recognizes. When a Poller I/O thread dispatches the event, a + * user-specified callback is invoked with all items on the queue. */ template <class T> class PollableQueue { @@ -50,12 +49,21 @@ class PollableQueue { /** * Callback to process a batch of items from the queue. - * @param values to process, any items remaining after call are put back on the queue. + * + * @param values Queue of values to process. Any items remaining + * on return from Callback are put back on the queue. */ - typedef boost::function<void (Queue& values)> Callback; + typedef boost::function<void (Queue&)> Callback; - /** When the queue is selected by the poller, values are passed to callback cb. */ - PollableQueue(const Callback& cb, const boost::shared_ptr<sys::Poller>& poller); + /** + * Constructor; sets necessary parameters. + * + * @param cb Callback that will be called to process items on the + * queue. Will be called from a Poller I/O thread. + * @param poller Poller to use for dispatching queue events. + */ + PollableQueue(const Callback& cb, + const boost::shared_ptr<sys::Poller>& poller); ~PollableQueue(); @@ -85,14 +93,12 @@ class PollableQueue { typedef sys::Monitor::ScopedLock ScopedLock; typedef sys::Monitor::ScopedUnlock ScopedUnlock; - void dispatch(sys::DispatchHandle&); + void dispatch(PollableCondition& cond); void process(); mutable sys::Monitor lock; Callback callback; - boost::shared_ptr<sys::Poller> poller; PollableCondition condition; - DispatchHandleRef handle; Queue queue, batch; Thread dispatcher; bool stopped; @@ -100,11 +106,10 @@ class PollableQueue { template <class T> PollableQueue<T>::PollableQueue( const Callback& cb, const boost::shared_ptr<sys::Poller>& p) - : callback(cb), poller(p), - handle(condition, boost::bind(&PollableQueue<T>::dispatch, this, _1), 0, 0), stopped(true) + : callback(cb), + condition(boost::bind(&PollableQueue<T>::dispatch, this, _1), p), + stopped(true) { - handle.startWatch(poller); - handle.unwatch(); } template <class T> void PollableQueue<T>::start() { @@ -112,11 +117,10 @@ template <class T> void PollableQueue<T>::start() { if (!stopped) return; stopped = false; if (!queue.empty()) condition.set(); - handle.rewatch(); + condition.rearm(); } template <class T> PollableQueue<T>::~PollableQueue() { - handle.stopWatch(); } template <class T> void PollableQueue<T>::push(const T& t) { @@ -125,15 +129,15 @@ template <class T> void PollableQueue<T>::push(const T& t) { queue.push_back(t); } -template <class T> void PollableQueue<T>::dispatch(sys::DispatchHandle& h) { +template <class T> void PollableQueue<T>::dispatch(PollableCondition& cond) { ScopedLock l(lock); assert(dispatcher.id() == 0); dispatcher = Thread::current(); process(); dispatcher = Thread(); - if (queue.empty()) condition.clear(); + if (queue.empty()) cond.clear(); if (stopped) lock.notifyAll(); - else h.rewatch(); + else cond.rearm(); } template <class T> void PollableQueue<T>::process() { @@ -159,7 +163,7 @@ template <class T> void PollableQueue<T>::shutdown() { template <class T> void PollableQueue<T>::stop() { ScopedLock l(lock); if (stopped) return; - handle.unwatch(); + condition.disarm(); stopped = true; // Avoid deadlock if stop is called from the dispatch thread while (dispatcher.id() && dispatcher.id() != Thread::current().id()) diff --git a/qpid/cpp/src/qpid/sys/Poller.h b/qpid/cpp/src/qpid/sys/Poller.h index 8e9f67fefd..825ad8bfed 100644 --- a/qpid/cpp/src/qpid/sys/Poller.h +++ b/qpid/cpp/src/qpid/sys/Poller.h @@ -24,7 +24,7 @@ #include "Time.h" #include "Runnable.h" - +#include "qpid/CommonImportExport.h" #include <boost/shared_ptr.hpp> namespace qpid { @@ -74,10 +74,10 @@ public: void process(); }; - Poller(); - ~Poller(); + QPID_COMMON_EXTERN Poller(); + QPID_COMMON_EXTERN ~Poller(); /** Note: this function is async-signal safe */ - void shutdown(); + QPID_COMMON_EXTERN void shutdown(); // Interrupt waiting for a specific poller handle // returns true if we could interrupt the handle @@ -86,18 +86,19 @@ public: // with the handle and the INTERRUPTED event type // if it returns false then the handle is not being monitored by the poller // - This can either be because it has just received an event which has been - // reported and has not been reenabled since. Or because it was removed - // from the monitoring set - bool interrupt(PollerHandle& handle); + // reported and has not been reenabled since. + // - Because it was removed from the monitoring set + // - Or because it is already being interrupted + QPID_COMMON_EXTERN bool interrupt(PollerHandle& handle); // Poller run loop - void run(); + QPID_COMMON_EXTERN void run(); - void addFd(PollerHandle& handle, Direction dir); - void delFd(PollerHandle& handle); - void modFd(PollerHandle& handle, Direction dir); - void rearmFd(PollerHandle& handle); - Event wait(Duration timeout = TIME_INFINITE); + QPID_COMMON_EXTERN void addFd(PollerHandle& handle, Direction dir); + QPID_COMMON_EXTERN void delFd(PollerHandle& handle); + QPID_COMMON_EXTERN void modFd(PollerHandle& handle, Direction dir); + QPID_COMMON_EXTERN void rearmFd(PollerHandle& handle); + QPID_COMMON_EXTERN Event wait(Duration timeout = TIME_INFINITE); }; /** @@ -110,11 +111,11 @@ class PollerHandle { friend struct Poller::Event; PollerHandlePrivate* const impl; - virtual void processEvent(Poller::EventType) {}; + QPID_COMMON_EXTERN virtual void processEvent(Poller::EventType) {}; public: - PollerHandle(const IOHandle& h); - virtual ~PollerHandle(); + QPID_COMMON_EXTERN PollerHandle(const IOHandle& h); + QPID_COMMON_EXTERN virtual ~PollerHandle(); }; inline void Poller::Event::process() { diff --git a/qpid/cpp/src/qpid/sys/Runnable.h b/qpid/cpp/src/qpid/sys/Runnable.h index fb3927c612..4bf43c93d1 100644 --- a/qpid/cpp/src/qpid/sys/Runnable.h +++ b/qpid/cpp/src/qpid/sys/Runnable.h @@ -22,6 +22,7 @@ */ #include <boost/function.hpp> +#include "qpid/CommonImportExport.h" namespace qpid { namespace sys { @@ -35,7 +36,7 @@ class Runnable /** Type to represent a runnable as a Functor */ typedef boost::function0<void> Functor; - virtual ~Runnable(); + QPID_COMMON_EXTERN virtual ~Runnable(); /** Derived classes override run(). */ virtual void run() = 0; diff --git a/qpid/cpp/src/qpid/sys/Shlib.h b/qpid/cpp/src/qpid/sys/Shlib.h index a6d94b42d4..7f66cfec14 100644 --- a/qpid/cpp/src/qpid/sys/Shlib.h +++ b/qpid/cpp/src/qpid/sys/Shlib.h @@ -21,7 +21,8 @@ * under the License. * */ - + +#include "qpid/CommonImportExport.h" #include <boost/noncopyable.hpp> #include <iostream> @@ -40,10 +41,10 @@ class Shlib { Shlib(const std::string& libname) { load(libname.c_str()); } /** Unload shared library. */ - void unload(); + QPID_COMMON_EXTERN void unload(); /** Look up symbol. */ - void* getSymbol(const char* symbol); + QPID_COMMON_EXTERN void* getSymbol(const char* symbol); /** Look up symbol in shared library, cast it to the desired * pointer type, void* by default. @@ -57,7 +58,7 @@ class Shlib { private: void* handle; - void load(const char* libname); + QPID_COMMON_EXTERN void load(const char* libname); }; /** A shared library handle that unloads the shlib in it's dtor */ @@ -66,7 +67,7 @@ class AutoShlib : public Shlib { /** Load shared library */ AutoShlib(const std::string& libname) : Shlib(libname) {} /** Calls unload() */ - ~AutoShlib() throw(); + QPID_COMMON_EXTERN ~AutoShlib() throw(); }; diff --git a/qpid/cpp/src/qpid/sys/Socket.h b/qpid/cpp/src/qpid/sys/Socket.h index ae48b8104d..e6555f5774 100644 --- a/qpid/cpp/src/qpid/sys/Socket.h +++ b/qpid/cpp/src/qpid/sys/Socket.h @@ -24,11 +24,9 @@ #include "IOHandle.h" #include "qpid/sys/IntegerTypes.h" - +#include "qpid/CommonImportExport.h" #include <string> -struct sockaddr; - namespace qpid { namespace sys { @@ -38,7 +36,7 @@ class Socket : public IOHandle { public: /** Create a socket wrapper for descriptor. */ - Socket(); + QPID_COMMON_EXTERN Socket(); /** Create an initialized TCP socket */ void createTcp() const; @@ -49,21 +47,21 @@ public: /** Set socket non blocking */ void setNonblocking() const; - void connect(const std::string& host, uint16_t port) const; + QPID_COMMON_EXTERN void connect(const std::string& host, uint16_t port) const; - void close() const; + QPID_COMMON_EXTERN void close() const; /** Bind to a port and start listening. *@param port 0 means choose an available port. *@param backlog maximum number of pending connections. *@return The bound port. */ - int listen(uint16_t port = 0, int backlog = 10) const; + QPID_COMMON_EXTERN int listen(uint16_t port = 0, int backlog = 10) const; /** Returns the "socket name" ie the address bound to * the near end of the socket */ - std::string getSockname() const; + QPID_COMMON_EXTERN std::string getSockname() const; /** Returns the "peer name" ie the address bound to * the remote end of the socket @@ -74,14 +72,14 @@ public: * Returns an address (host and port) for the remote end of the * socket */ - std::string getPeerAddress() const; + QPID_COMMON_EXTERN std::string getPeerAddress() const; /** * Returns an address (host and port) for the local end of the * socket */ std::string getLocalAddress() const; - uint16_t getLocalPort() const; + QPID_COMMON_EXTERN uint16_t getLocalPort() const; uint16_t getRemotePort() const; /** @@ -93,13 +91,13 @@ public: /** Accept a connection from a socket that is already listening * and has an incoming connection */ - Socket* accept(struct sockaddr *addr, socklen_t *addrlen) const; + QPID_COMMON_EXTERN Socket* accept() const; // TODO The following are raw operations, maybe they need better wrapping? - int read(void *buf, size_t count) const; - int write(const void *buf, size_t count) const; + QPID_COMMON_EXTERN int read(void *buf, size_t count) const; + QPID_COMMON_EXTERN int write(const void *buf, size_t count) const; - void setTcpNoDelay(bool nodelay) const; + QPID_COMMON_EXTERN void setTcpNoDelay(bool nodelay) const; private: Socket(IOHandlePrivate*); diff --git a/qpid/cpp/src/qpid/sys/StrError.h b/qpid/cpp/src/qpid/sys/StrError.h index 3843f2abe1..69cc7e714c 100644 --- a/qpid/cpp/src/qpid/sys/StrError.h +++ b/qpid/cpp/src/qpid/sys/StrError.h @@ -23,12 +23,13 @@ */ #include <string> +#include "qpid/CommonImportExport.h" namespace qpid { namespace sys { /** Get the error message for a system number err, e.g. errno. */ -std::string strError(int err); +QPID_COMMON_EXTERN std::string strError(int err); }} // namespace qpid diff --git a/qpid/cpp/src/qpid/sys/SystemInfo.h b/qpid/cpp/src/qpid/sys/SystemInfo.h index d43fe34b04..6e97022b36 100644 --- a/qpid/cpp/src/qpid/sys/SystemInfo.h +++ b/qpid/cpp/src/qpid/sys/SystemInfo.h @@ -23,6 +23,7 @@ #include "qpid/sys/IntegerTypes.h" #include "qpid/Address.h" +#include "qpid/CommonImportExport.h" namespace qpid { namespace sys { @@ -36,15 +37,15 @@ namespace SystemInfo { * Estimate available concurrency, e.g. number of CPU cores. * -1 means estimate not available on this platform. */ - long concurrency(); + QPID_COMMON_EXTERN long concurrency(); /** * Get the local host name and set it in the specified TcpAddress. * Returns false if it can't be obtained and sets errno to any error value. */ - bool getLocalHostname (TcpAddress &address); + QPID_COMMON_EXTERN bool getLocalHostname (TcpAddress &address); - void getLocalIpAddresses (uint16_t port, std::vector<Address> &addrList); + QPID_COMMON_EXTERN void getLocalIpAddresses (uint16_t port, std::vector<Address> &addrList); /** * Retrieve system identifiers and versions. This is information that can @@ -57,7 +58,7 @@ namespace SystemInfo { * @param version Receives the OS release version (kernel, build, sp, etc.) * @param machine Receives the hardware type. */ - void getSystemId (std::string &osName, + QPID_COMMON_EXTERN void getSystemId (std::string &osName, std::string &nodeName, std::string &release, std::string &version, @@ -66,12 +67,17 @@ namespace SystemInfo { /** * Get the process ID of the current process. */ - uint32_t getProcessId(); + QPID_COMMON_EXTERN uint32_t getProcessId(); /** * Get the process ID of the parent of the current process. */ - uint32_t getParentProcessId(); + QPID_COMMON_EXTERN uint32_t getParentProcessId(); + + /** + * Get the name of the current process (i.e. the name of the executable) + */ + QPID_COMMON_EXTERN std::string getProcessName(); }}} // namespace qpid::sys::SystemInfo diff --git a/qpid/cpp/src/qpid/sys/Thread.h b/qpid/cpp/src/qpid/sys/Thread.h index e2b904aa1a..b532d4d80a 100644 --- a/qpid/cpp/src/qpid/sys/Thread.h +++ b/qpid/cpp/src/qpid/sys/Thread.h @@ -22,11 +22,14 @@ * */ #include <boost/shared_ptr.hpp> +#include "qpid/CommonImportExport.h" #ifdef _WIN32 # define QPID_TSS __declspec(thread) #elif defined (__GNUC__) # define QPID_TSS __thread +#elif defined (__SUNPRO_CC) +# define QPID_TSS __thread #else # error "Dont know how to define QPID_TSS for this platform" #endif @@ -42,15 +45,15 @@ class Thread boost::shared_ptr<ThreadPrivate> impl; public: - Thread(); - explicit Thread(qpid::sys::Runnable*); - explicit Thread(qpid::sys::Runnable&); + QPID_COMMON_EXTERN Thread(); + QPID_COMMON_EXTERN explicit Thread(qpid::sys::Runnable*); + QPID_COMMON_EXTERN explicit Thread(qpid::sys::Runnable&); - void join(); + QPID_COMMON_EXTERN void join(); - unsigned long id(); + QPID_COMMON_EXTERN unsigned long id(); - static Thread current(); + QPID_COMMON_EXTERN static Thread current(); /** ID of current thread for logging. * Workaround for broken Thread::current() in APR diff --git a/qpid/cpp/src/qpid/sys/Time.h b/qpid/cpp/src/qpid/sys/Time.h index d39be95434..b7173406ca 100644 --- a/qpid/cpp/src/qpid/sys/Time.h +++ b/qpid/cpp/src/qpid/sys/Time.h @@ -33,6 +33,8 @@ # include "posix/Time.h" #endif +#include "qpid/CommonImportExport.h" + #include <limits> #include <iosfwd> @@ -86,23 +88,23 @@ class AbsTime { TimePrivate timepoint; public: - inline AbsTime() {} - AbsTime(const AbsTime& time0, const Duration& duration); + QPID_COMMON_EXTERN inline AbsTime() {} + QPID_COMMON_EXTERN AbsTime(const AbsTime& time0, const Duration& duration); // Default assignment operation fine // Default copy constructor fine - static AbsTime now(); - static AbsTime FarFuture(); + QPID_COMMON_EXTERN static AbsTime now(); + QPID_COMMON_EXTERN static AbsTime FarFuture(); const TimePrivate& getPrivate(void) const { return timepoint; } bool operator==(const AbsTime& t) const { return t.timepoint == timepoint; } template <class S> void serialize(S& s) { s(timepoint); } friend bool operator<(const AbsTime& a, const AbsTime& b); friend bool operator>(const AbsTime& a, const AbsTime& b); - friend std::ostream& operator << (std::ostream&, const AbsTime&); + QPID_COMMON_EXTERN friend std::ostream& operator << (std::ostream&, const AbsTime&); }; -std::ostream& operator << (std::ostream&, const AbsTime&); +QPID_COMMON_EXTERN std::ostream& operator << (std::ostream&, const AbsTime&); /** * @class Duration @@ -120,9 +122,9 @@ class Duration { friend class AbsTime; public: - inline Duration(int64_t time0); - explicit Duration(const AbsTime& time0); - explicit Duration(const AbsTime& start, const AbsTime& finish); + QPID_COMMON_EXTERN inline Duration(int64_t time0); + QPID_COMMON_EXTERN explicit Duration(const AbsTime& time0); + QPID_COMMON_EXTERN explicit Duration(const AbsTime& start, const AbsTime& finish); inline operator int64_t() const; }; @@ -158,10 +160,10 @@ const Duration TIME_INFINITE = std::numeric_limits<int64_t>::max(); const AbsTime FAR_FUTURE = AbsTime::FarFuture(); /** Portable sleep for a number of seconds */ -void sleep(int secs); +QPID_COMMON_EXTERN void sleep(int secs); /** Portable sleep for a number of microseconds */ -void usleep(uint64_t usecs); +QPID_COMMON_EXTERN void usleep(uint64_t usecs); }} diff --git a/qpid/cpp/src/qpid/sys/Timer.h b/qpid/cpp/src/qpid/sys/Timer.h index 2561e41034..dab2f55edb 100644 --- a/qpid/cpp/src/qpid/sys/Timer.h +++ b/qpid/cpp/src/qpid/sys/Timer.h @@ -25,7 +25,7 @@ #include "qpid/sys/Thread.h" #include "qpid/sys/Runnable.h" #include "qpid/RefCounted.h" - +#include "qpid/CommonImportExport.h" #include <memory> #include <queue> @@ -49,15 +49,15 @@ class TimerTask : public RefCounted { void fireTask(); public: - TimerTask(Duration period); - TimerTask(AbsTime fireTime); - virtual ~TimerTask(); + QPID_COMMON_EXTERN TimerTask(Duration period); + QPID_COMMON_EXTERN TimerTask(AbsTime fireTime); + QPID_COMMON_EXTERN virtual ~TimerTask(); - void setupNextFire(); - void restart(); - void delayTill(AbsTime fireTime); - void cancel(); - bool isCancelled() const; + QPID_COMMON_EXTERN void setupNextFire(); + QPID_COMMON_EXTERN void restart(); + QPID_COMMON_EXTERN void delayTill(AbsTime fireTime); + QPID_COMMON_EXTERN void cancel(); + QPID_COMMON_EXTERN bool isCancelled() const; protected: // Must be overridden with callback @@ -78,12 +78,12 @@ class Timer : private Runnable { void run(); public: - Timer(); - ~Timer(); + QPID_COMMON_EXTERN Timer(); + QPID_COMMON_EXTERN ~Timer(); - void add(boost::intrusive_ptr<TimerTask> task); - void start(); - void stop(); + QPID_COMMON_EXTERN void add(boost::intrusive_ptr<TimerTask> task); + QPID_COMMON_EXTERN void start(); + QPID_COMMON_EXTERN void stop(); }; diff --git a/qpid/cpp/src/qpid/sys/alloca.h b/qpid/cpp/src/qpid/sys/alloca.h new file mode 100644 index 0000000000..e989670e4f --- /dev/null +++ b/qpid/cpp/src/qpid/sys/alloca.h @@ -0,0 +1,39 @@ +#ifndef QPID_SYS_ALLOCA_H +#define QPID_SYS_ALLOCA_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. + * + */ + +#if (defined(_WINDOWS) || defined (WIN32)) && defined(_MSC_VER) +#include <malloc.h> +#ifdef alloc +# undef alloc +#endif +#define alloc _alloc +#ifdef alloca +# undef alloca +#endif +#define alloca _alloca +#endif +#if !defined _WINDOWS && !defined WIN32 +#include <alloca.h> +#endif + +#endif /*!QPID_SYS_ALLOCA_H*/ diff --git a/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp b/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp index 10705e12da..42b5d8b1aa 100644 --- a/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp +++ b/qpid/cpp/src/qpid/sys/epoll/EpollPoller.cpp @@ -54,17 +54,20 @@ class PollerHandlePrivate { INACTIVE, HUNGUP, MONITORED_HUNGUP, + INTERRUPTED, DELETED }; int fd; ::__uint32_t events; + PollerHandle* pollerHandle; FDStat stat; Mutex lock; - PollerHandlePrivate(int f) : + PollerHandlePrivate(int f, PollerHandle* p) : fd(f), events(0), + pollerHandle(p), stat(ABSENT) { } @@ -101,6 +104,14 @@ class PollerHandlePrivate { stat = HUNGUP; } + bool isInterrupted() const { + return stat == INTERRUPTED; + } + + void setInterrupted() { + stat = INTERRUPTED; + } + bool isDeleted() const { return stat == DELETED; } @@ -111,7 +122,7 @@ class PollerHandlePrivate { }; PollerHandle::PollerHandle(const IOHandle& h) : - impl(new PollerHandlePrivate(toFd(h.impl))) + impl(new PollerHandlePrivate(toFd(h.impl), this)) {} PollerHandle::~PollerHandle() { @@ -120,6 +131,10 @@ PollerHandle::~PollerHandle() { if (impl->isDeleted()) { return; } + if (impl->isInterrupted()) { + impl->setDeleted(); + return; + } if (impl->isActive()) { impl->setDeleted(); } @@ -243,23 +258,21 @@ class PollerPrivate { ::close(epollFd); } - void interrupt(bool all=false) { + void interrupt() { ::epoll_event epe; - if (all) { - // Not EPOLLONESHOT, so we eventually get all threads - epe.events = ::EPOLLIN; - epe.data.u64 = 0; // Keep valgrind happy - } else { - // Use EPOLLONESHOT so we only wake a single thread - epe.events = ::EPOLLIN | ::EPOLLONESHOT; - epe.data.u64 = 0; // Keep valgrind happy - epe.data.ptr = &static_cast<PollerHandle&>(interruptHandle); - } + // Use EPOLLONESHOT so we only wake a single thread + epe.events = ::EPOLLIN | ::EPOLLONESHOT; + epe.data.u64 = 0; // Keep valgrind happy + epe.data.ptr = &static_cast<PollerHandle&>(interruptHandle); QPID_POSIX_CHECK(::epoll_ctl(epollFd, EPOLL_CTL_MOD, alwaysReadableFd, &epe)); } void interruptAll() { - interrupt(true); + ::epoll_event epe; + // Not EPOLLONESHOT, so we eventually get all threads + epe.events = ::EPOLLIN; + epe.data.u64 = 0; // Keep valgrind happy + QPID_POSIX_CHECK(::epoll_ctl(epollFd, EPOLL_CTL_MOD, alwaysReadableFd, &epe)); } }; @@ -281,7 +294,7 @@ void Poller::addFd(PollerHandle& handle, Direction dir) { epe.events = eh.events | PollerPrivate::directionToEpollEvent(dir); } epe.data.u64 = 0; // Keep valgrind happy - epe.data.ptr = &handle; + epe.data.ptr = &eh; QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, op, eh.fd, &epe)); @@ -312,7 +325,7 @@ void Poller::modFd(PollerHandle& handle, Direction dir) { ::epoll_event epe; epe.events = PollerPrivate::directionToEpollEvent(dir) | ::EPOLLONESHOT; epe.data.u64 = 0; // Keep valgrind happy - epe.data.ptr = &handle; + epe.data.ptr = &eh; QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd, &epe)); @@ -329,7 +342,7 @@ void Poller::rearmFd(PollerHandle& handle) { ::epoll_event epe; epe.events = eh.events; epe.data.u64 = 0; // Keep valgrind happy - epe.data.ptr = &handle; + epe.data.ptr = &eh; QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd, &epe)); @@ -355,15 +368,14 @@ bool Poller::interrupt(PollerHandle& handle) { { PollerHandlePrivate& eh = *handle.impl; ScopedLock<Mutex> l(eh.lock); - if (eh.isInactive()) { + if (!eh.isActive()) { return false; } ::epoll_event epe; epe.events = 0; epe.data.u64 = 0; // Keep valgrind happy - epe.data.ptr = &eh; QPID_POSIX_CHECK(::epoll_ctl(impl->epollFd, EPOLL_CTL_MOD, eh.fd, &epe)); - eh.setInactive(); + eh.setInterrupted(); } PollerPrivate::InterruptHandle& ih = impl->interruptHandle; @@ -422,37 +434,54 @@ Poller::Event Poller::wait(Duration timeout) { #else int rc = ::epoll_pwait(impl->epollFd, &epe, 1, timeoutMs, &impl->sigMask); #endif - // Check for shutdown - if (impl->isShutdown) { - PollerHandleDeletionManager.markAllUnusedInThisThread(); - return Event(0, SHUTDOWN); - } if (rc ==-1 && errno != EINTR) { QPID_POSIX_CHECK(rc); } else if (rc > 0) { assert(rc == 1); - PollerHandle* handle = static_cast<PollerHandle*>(epe.data.ptr); + void* dataPtr = epe.data.ptr; + + // Check if this is an interrupt + PollerPrivate::InterruptHandle& interruptHandle = impl->interruptHandle; + if (dataPtr == &interruptHandle) { + PollerHandle* wrappedHandle = 0; + { + ScopedLock<Mutex> l(interruptHandle.impl->lock); + if (interruptHandle.impl->isActive()) { + wrappedHandle = interruptHandle.getHandle(); + // If there is an interrupt queued behind this one we need to arm it + // We do it this way so that another thread can pick it up + if (interruptHandle.queuedHandles()) { + impl->interrupt(); + interruptHandle.impl->setActive(); + } else { + interruptHandle.impl->setInactive(); + } + } + } + if (wrappedHandle) { + ScopedLock<Mutex> l(wrappedHandle->impl->lock); + if (!wrappedHandle->impl->isDeleted()) { + wrappedHandle->impl->setInactive(); + return Event(wrappedHandle, INTERRUPTED); + } + PollerHandleDeletionManager.markForDeletion(wrappedHandle->impl); + } + continue; + } + + // Check for shutdown + if (impl->isShutdown) { + PollerHandleDeletionManager.markAllUnusedInThisThread(); + return Event(0, SHUTDOWN); + } - PollerHandlePrivate& eh = *handle->impl; + PollerHandlePrivate& eh = *static_cast<PollerHandlePrivate*>(dataPtr); ScopedLock<Mutex> l(eh.lock); // the handle could have gone inactive since we left the epoll_wait if (eh.isActive()) { - - // Check if this is an interrupt - if (handle == &impl->interruptHandle) { - PollerHandle* wrappedHandle = impl->interruptHandle.getHandle(); - // If there is an interrupt queued behind this one we need to arm it - // We do it this way so that another thread can pick it up - if (impl->interruptHandle.queuedHandles()) { - impl->interrupt(); - eh.setActive(); - } else { - eh.setInactive(); - } - return Event(wrappedHandle, INTERRUPTED); - } + PollerHandle* handle = eh.pollerHandle; // If the connection has been hungup we could still be readable // (just not writable), allow us to readable until we get here again diff --git a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp index a356a72650..a914dc817a 100644 --- a/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp +++ b/qpid/cpp/src/qpid/sys/posix/AsynchIO.cpp @@ -123,7 +123,7 @@ void AsynchAcceptorPrivate::readable(DispatchHandle& h) { // TODO: Currently we ignore the peers address, perhaps we should // log it or use it for connection acceptance. try { - s = socket.accept(0, 0); + s = socket.accept(); if (s) { acceptedCallback(*s); } else { @@ -474,7 +474,7 @@ void AsynchIO::readable(DispatchHandle& h) { break; } else { // Report error then just treat as a socket disconnect - QPID_LOG(error, "Error reading socket: " << qpid::sys::strError(rc) << "(" << rc << ")" ); + QPID_LOG(error, "Error reading socket: " << qpid::sys::strError(errno) << "(" << errno << ")" ); eofCallback(*this); h.unwatchRead(); break; diff --git a/qpid/cpp/src/qpid/sys/posix/PollableCondition.cpp b/qpid/cpp/src/qpid/sys/posix/PollableCondition.cpp index 0c55fd3c0d..0991e5fd76 100644 --- a/qpid/cpp/src/qpid/sys/posix/PollableCondition.cpp +++ b/qpid/cpp/src/qpid/sys/posix/PollableCondition.cpp @@ -22,17 +22,46 @@ * */ -#include "PollableCondition.h" +#include "qpid/sys/PollableCondition.h" +#include "qpid/sys/DispatchHandle.h" +#include "qpid/sys/IOHandle.h" #include "qpid/sys/posix/PrivatePosix.h" #include "qpid/Exception.h" +#include <boost/bind.hpp> + #include <unistd.h> #include <fcntl.h> namespace qpid { namespace sys { -PollableCondition::PollableCondition() : IOHandle(new sys::IOHandlePrivate) { +class PollableConditionPrivate : public sys::IOHandle { + friend class PollableCondition; + +private: + PollableConditionPrivate(const sys::PollableCondition::Callback& cb, + sys::PollableCondition& parent, + const boost::shared_ptr<sys::Poller>& poller); + ~PollableConditionPrivate(); + + void dispatch(sys::DispatchHandle& h); + void rewatch(); + void unwatch(); + +private: + PollableCondition::Callback cb; + PollableCondition& parent; + boost::shared_ptr<sys::Poller> poller; + int writeFd; + std::auto_ptr<DispatchHandleRef> handle; +}; + +PollableConditionPrivate::PollableConditionPrivate(const sys::PollableCondition::Callback& cb, + sys::PollableCondition& parent, + const boost::shared_ptr<sys::Poller>& poller) + : IOHandle(new sys::IOHandlePrivate), cb(cb), parent(parent) +{ int fds[2]; if (::pipe(fds) == -1) throw ErrnoException(QPID_MSG("Can't create PollableCondition")); @@ -42,22 +71,71 @@ PollableCondition::PollableCondition() : IOHandle(new sys::IOHandlePrivate) { throw ErrnoException(QPID_MSG("Can't create PollableCondition")); if (::fcntl(writeFd, F_SETFL, O_NONBLOCK) == -1) throw ErrnoException(QPID_MSG("Can't create PollableCondition")); + handle.reset (new DispatchHandleRef(*this, + boost::bind(&sys::PollableConditionPrivate::dispatch, this, _1), + 0, 0)); + handle->startWatch(poller); + handle->unwatch(); +} + +PollableConditionPrivate::~PollableConditionPrivate() +{ + handle->stopWatch(); + close(writeFd); +} + +void PollableConditionPrivate::dispatch(sys::DispatchHandle& /*h*/) +{ + cb(parent); +} + +void PollableConditionPrivate::rewatch() +{ + handle->rewatch(); +} + +void PollableConditionPrivate::unwatch() +{ + handle->unwatch(); +} + + /* PollableCondition */ + +PollableCondition::PollableCondition(const Callback& cb, + const boost::shared_ptr<sys::Poller>& poller) + : impl(new PollableConditionPrivate(cb, *this, poller)) +{ +} + +PollableCondition::~PollableCondition() +{ + delete impl; +} + +void PollableCondition::set() { + static const char dummy=0; + ssize_t n = ::write(impl->writeFd, &dummy, 1); + if (n == -1 && errno != EAGAIN) + throw ErrnoException("Error setting PollableCondition"); } bool PollableCondition::clear() { char buf[256]; ssize_t n; bool wasSet = false; - while ((n = ::read(impl->fd, buf, sizeof(buf))) > 0) + while ((n = ::read(impl->impl->fd, buf, sizeof(buf))) > 0) wasSet = true; - if (n == -1 && errno != EAGAIN) throw ErrnoException(QPID_MSG("Error clearing PollableCondition")); + if (n == -1 && errno != EAGAIN) + throw ErrnoException(QPID_MSG("Error clearing PollableCondition")); return wasSet; } -void PollableCondition::set() { - static const char dummy=0; - ssize_t n = ::write(writeFd, &dummy, 1); - if (n == -1 && errno != EAGAIN) throw ErrnoException("Error setting PollableCondition"); +void PollableCondition::disarm() { + impl->unwatch(); +} + +void PollableCondition::rearm() { + impl->rewatch(); } @@ -71,22 +149,35 @@ void PollableCondition::set() { namespace qpid { namespace sys { -PollableCondition::PollableCondition() : IOHandle(new sys::IOHandlePrivate) { +PollableConditionPrivate::PollableConditionPrivate(const PollableCondition::Callback& cb, + sys::PollableCondition& parent, + const boost::shared_ptr<sys::Poller>& poller) + : cb(cb), parent(parent), poller(poller), + IOHandle(new sys::IOHandlePrivate) { impl->fd = ::eventfd(0, 0); if (impl->fd < 0) throw ErrnoException("conditionfd() failed"); } +void PollableCondition::set() { + static const uint64_t value=1; + ssize_t n = ::write(impl->impl->fd, + reinterpret_cast<const void*>(&value), 8); + if (n != 8) throw ErrnoException("write failed on conditionfd"); +} + bool PollableCondition::clear() { char buf[8]; - ssize_t n = ::read(impl->fd, buf, 8); + ssize_t n = ::read(impl->impl->fd, buf, 8); if (n != 8) throw ErrnoException("read failed on conditionfd"); return *reinterpret_cast<uint64_t*>(buf); } -void PollableCondition::set() { - static const uint64_t value=1; - ssize_t n = ::write(impl->fd, reinterpret_cast<const void*>(&value), 8); - if (n != 8) throw ErrnoException("write failed on conditionfd"); +void PollableCondition::disarm() { + // ???? +} + +void PollableCondition::rearm() { + // ???? } #endif diff --git a/qpid/cpp/src/qpid/sys/posix/Socket.cpp b/qpid/cpp/src/qpid/sys/posix/Socket.cpp index 415d5293ef..ab0c28c48c 100644 --- a/qpid/cpp/src/qpid/sys/posix/Socket.cpp +++ b/qpid/cpp/src/qpid/sys/posix/Socket.cpp @@ -108,7 +108,7 @@ void Socket::createTcp() const { int& socket = impl->fd; if (socket != -1) Socket::close(); - int s = ::socket (PF_INET, SOCK_STREAM, 0); + int s = ::socket (AF_INET, SOCK_STREAM, 0); if (s < 0) throw QPID_POSIX_ERROR(errno); socket = s; } @@ -138,25 +138,30 @@ const char* h_errstr(int e) { } } -void Socket::connect(const std::string& host, uint16_t port) const +void Socket::connect(const std::string& host, uint16_t p) const { - std::stringstream namestream; - namestream << host << ":" << port; - connectname = namestream.str(); + std::stringstream portstream; + portstream << p; + std::string port = portstream.str(); + connectname = host + ":" + port; const int& socket = impl->fd; - struct sockaddr_in name; - name.sin_family = AF_INET; - name.sin_port = htons(port); - // TODO: Be good to make this work for IPv6 as well as IPv4 - // Use more modern lookup functions - struct hostent* hp = gethostbyname ( host.c_str() ); - if (hp == 0) - throw Exception(QPID_MSG("Cannot resolve " << host << ": " << h_errstr(h_errno))); - ::memcpy(&name.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length); - if ((::connect(socket, (struct sockaddr*)(&name), sizeof(name)) < 0) && - (errno != EINPROGRESS)) + + ::addrinfo *res; + ::addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; // In order to allow AF_INET6 we'd have to change createTcp() as well + hints.ai_socktype = SOCK_STREAM; + int n = ::getaddrinfo(host.c_str(), port.c_str(), &hints, &res); + if (n != 0) + throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n))); + // TODO the correct thing to do here is loop on failure until you've used all the returned addresses + if ((::connect(socket, res->ai_addr, res->ai_addrlen) < 0) && + (errno != EINPROGRESS)) { + ::freeaddrinfo(res); throw qpid::Exception(QPID_MSG(strError(errno) << ": " << host << ":" << port)); + } + ::freeaddrinfo(res); } void @@ -189,9 +194,9 @@ int Socket::listen(uint16_t port, int backlog) const return ntohs(name.sin_port); } -Socket* Socket::accept(struct sockaddr *addr, socklen_t *addrlen) const +Socket* Socket::accept() const { - int afd = ::accept(impl->fd, addr, addrlen); + int afd = ::accept(impl->fd, 0, 0); if ( afd >= 0) return new Socket(new IOHandlePrivate(afd)); else if (errno == EAGAIN) @@ -238,7 +243,7 @@ uint16_t Socket::getLocalPort() const uint16_t Socket::getRemotePort() const { - return atoi(getService(impl->fd, true).c_str()); + return std::atoi(getService(impl->fd, true).c_str()); } int Socket::getError() const diff --git a/qpid/cpp/src/qpid/sys/posix/SystemInfo.cpp b/qpid/cpp/src/qpid/sys/posix/SystemInfo.cpp index 938d4861c4..5d9eda605d 100755 --- a/qpid/cpp/src/qpid/sys/posix/SystemInfo.cpp +++ b/qpid/cpp/src/qpid/sys/posix/SystemInfo.cpp @@ -27,6 +27,9 @@ #include <arpa/inet.h> #include <stdio.h> #include <unistd.h> +#include <iostream> +#include <fstream> +#include <sstream> #ifndef HOST_NAME_MAX # define HOST_NAME_MAX 256 @@ -104,6 +107,27 @@ uint32_t SystemInfo::getParentProcessId() return (uint32_t) ::getppid(); } +string SystemInfo::getProcessName() +{ + uint32_t pid = getProcessId(); + string value; + + stringstream pathStream; + pathStream << "/proc/" << pid << "/status"; + ifstream input(pathStream.str().c_str()); + if (input.good()) { + while (!input.eof()) { + string key; + input >> key; + if (key == "Name:") { + input >> value; + break; + } + } + input.close(); + } + return value; +} }} // namespace qpid::sys diff --git a/qpid/cpp/src/qpid/sys/solaris/ECFPoller.cpp b/qpid/cpp/src/qpid/sys/solaris/ECFPoller.cpp index 783f84576b..f12012cbb0 100644 --- a/qpid/cpp/src/qpid/sys/solaris/ECFPoller.cpp +++ b/qpid/cpp/src/qpid/sys/solaris/ECFPoller.cpp @@ -30,9 +30,11 @@ #include <port.h> #include <poll.h> #include <errno.h> +#include <pthread.h> +#include <signal.h> #include <assert.h> -#include <vector> +#include <queue> #include <exception> @@ -43,11 +45,11 @@ namespace qpid { namespace sys { // Deletion manager to handle deferring deletion of PollerHandles to when they definitely aren't being used -DeletionManager<PollerHandle> PollerHandleDeletionManager; +DeletionManager<PollerHandlePrivate> PollerHandleDeletionManager; // Instantiate (and define) class static for DeletionManager template <> -DeletionManager<PollerHandle>::AllThreadsStatuses DeletionManager<PollerHandle>::allThreadsStatuses(0); +DeletionManager<PollerHandlePrivate>::AllThreadsStatuses DeletionManager<PollerHandlePrivate>::allThreadsStatuses(0); class PollerHandlePrivate { friend class Poller; @@ -58,7 +60,8 @@ class PollerHandlePrivate { MONITORED, INACTIVE, HUNGUP, - MONITORED_HUNGUP + MONITORED_HUNGUP, + DELETED }; int fd; @@ -104,6 +107,14 @@ class PollerHandlePrivate { assert(stat == MONITORED); stat = HUNGUP; } + + bool isDeleted() const { + return stat == DELETED; + } + + void setDeleted() { + stat = DELETED; + } }; PollerHandle::PollerHandle(const IOHandle& h) : @@ -111,11 +122,16 @@ PollerHandle::PollerHandle(const IOHandle& h) : {} PollerHandle::~PollerHandle() { - delete impl; -} - -void PollerHandle::deferDelete() { - PollerHandleDeletionManager.markForDeletion(this); + { + ScopedLock<Mutex> l(impl->lock); + if (impl->isDeleted()) { + return; + } + if (impl->isActive()) { + impl->setDeleted(); + } + } + PollerHandleDeletionManager.markForDeletion(impl); } /** @@ -125,35 +141,82 @@ void PollerHandle::deferDelete() { class PollerPrivate { friend class Poller; - const int portId; + class InterruptHandle: public PollerHandle { + std::queue<PollerHandle*> handles; + + void processEvent(Poller::EventType) { + PollerHandle* handle = handles.front(); + handles.pop(); + assert(handle); + + //Synthesise event + Poller::Event event(handle, Poller::INTERRUPTED); + + //Process synthesised event + event.process(); + } + public: + InterruptHandle() : PollerHandle(DummyIOHandle) {} + + void addHandle(PollerHandle& h) { + handles.push(&h); + } + + PollerHandle *getHandle() { + PollerHandle* handle = handles.front(); + handles.pop(); + return handle; + } + + bool queuedHandles() { + return handles.size() > 0; + } + }; + + const int portId; + bool isShutdown; + InterruptHandle interruptHandle; + static uint32_t directionToPollEvent(Poller::Direction dir) { switch (dir) { - case Poller::INPUT: return POLLIN; - case Poller::OUTPUT: return POLLOUT; - case Poller::INOUT: return POLLIN | POLLOUT; - default: return 0; + case Poller::INPUT: return POLLIN; + case Poller::OUTPUT: return POLLOUT; + case Poller::INOUT: return POLLIN | POLLOUT; + default: return 0; } } static Poller::EventType pollToDirection(uint32_t events) { uint32_t e = events & (POLLIN | POLLOUT); switch (e) { - case POLLIN: return Poller::READABLE; - case POLLOUT: return Poller::WRITABLE; - case POLLIN | POLLOUT: return Poller::READ_WRITABLE; - default: - return (events & (POLLHUP | POLLERR)) ? - Poller::DISCONNECTED : Poller::INVALID; + case POLLIN: return Poller::READABLE; + case POLLOUT: return Poller::WRITABLE; + case POLLIN | POLLOUT: return Poller::READ_WRITABLE; + default: + return (events & (POLLHUP | POLLERR)) ? + Poller::DISCONNECTED : Poller::INVALID; } } - + PollerPrivate() : - portId(::port_create()) { + portId(::port_create()), + isShutdown(false) { + QPID_POSIX_CHECK(portId); + QPID_LOG(trace, "port_create returned port Id: " << portId); } ~PollerPrivate() { } + + void interrupt() { + //Send an Alarm to the port + //We need to send a nonzero event mask, using POLLHUP, + //nevertheless the wait method will only look for a PORT_ALERT_SET + QPID_LOG(trace, "Sending a port_alert to " << portId); + QPID_POSIX_CHECK(::port_alert(portId, PORT_ALERT_SET, POLLHUP, + &static_cast<PollerHandle&>(interruptHandle))); + } }; void Poller::addFd(PollerHandle& handle, Direction dir) { @@ -177,7 +240,6 @@ void Poller::addFd(PollerHandle& handle, Direction dir) { QPID_LOG(trace, "Poller::addFd(handle=" << &handle << "[" << typeid(&handle).name() << "], fd=" << eh.fd << ")"); - //assert(dynamic_cast<DispatchHandle*>(&handle)); } void Poller::delFd(PollerHandle& handle) { @@ -223,17 +285,56 @@ void Poller::rearmFd(PollerHandle& handle) { } void Poller::shutdown() { - //Send an Alarm to the port - //We need to send a nonzero event mask, using POLLHUP, but - //The wait method will only look for a PORT_ALERT_SET - QPID_POSIX_CHECK(::port_alert(impl->portId, PORT_ALERT_SET, POLLHUP, NULL)); - QPID_LOG(trace, "Poller::shutdown"); + //Allow sloppy code to shut us down more than once + if (impl->isShutdown) + return; + + impl->isShutdown = true; + impl->interrupt(); +} + +bool Poller::interrupt(PollerHandle& handle) { + PollerPrivate::InterruptHandle& ih = impl->interruptHandle; + PollerHandlePrivate& eh = *static_cast<PollerHandle&>(ih).impl; + ScopedLock<Mutex> l(eh.lock); + ih.addHandle(handle); + impl->interrupt(); + eh.setActive(); + return true; +} + +void Poller::run() { + // Make sure we can't be interrupted by signals at a bad time + ::sigset_t ss; + ::sigfillset(&ss); + ::pthread_sigmask(SIG_SETMASK, &ss, 0); + + do { + Event event = wait(); + + // If can read/write then dispatch appropriate callbacks + if (event.handle) { + event.process(); + } else { + // Handle shutdown + switch (event.type) { + case SHUTDOWN: + return; + default: + // This should be impossible + assert(false); + } + } + } while (true); } Poller::Event Poller::wait(Duration timeout) { timespec_t tout; timespec_t* ptout = NULL; port_event_t pe; + + AbsTime targetTimeout = (timeout == TIME_INFINITE) ? FAR_FUTURE : + AbsTime(now(), timeout); if (timeout != TIME_INFINITE) { tout.tv_sec = 0; @@ -243,12 +344,21 @@ Poller::Event Poller::wait(Duration timeout) { do { PollerHandleDeletionManager.markAllUnusedInThisThread(); - QPID_LOG(trace, "About to enter port_get. Thread " - << pthread_self() + QPID_LOG(trace, "About to enter port_get on " << impl->portId + << ". Thread " << pthread_self() << ", timeout=" << timeout); - + + int rc = ::port_get(impl->portId, &pe, ptout); + QPID_LOG(trace, "port_get on " << impl->portId + << " returned " << rc); + + if (impl->isShutdown) { + PollerHandleDeletionManager.markAllUnusedInThisThread(); + return Event(0, SHUTDOWN); + } + if (rc < 0) { switch (errno) { case EINTR: @@ -259,33 +369,61 @@ Poller::Event Poller::wait(Duration timeout) { QPID_POSIX_CHECK(rc); } } else { - //We use alert mode to notify the shutdown of the Poller - if (pe.portev_source == PORT_SOURCE_ALERT) { - return Event(0, SHUTDOWN); - } - if (pe.portev_source == PORT_SOURCE_FD) { - PollerHandle *handle = static_cast<PollerHandle*>(pe.portev_user); - PollerHandlePrivate& eh = *handle->impl; - ScopedLock<Mutex> l(eh.lock); - QPID_LOG(trace, "About to send handle: " << handle); + PollerHandle* handle = static_cast<PollerHandle*>(pe.portev_user); + PollerHandlePrivate& eh = *handle->impl; + ScopedLock<Mutex> l(eh.lock); + + if (eh.isActive()) { + QPID_LOG(trace, "Handle is active"); + //We use alert mode to notify interrupts + if (pe.portev_source == PORT_SOURCE_ALERT && + handle == &impl->interruptHandle) { + QPID_LOG(trace, "Interrupt notified"); + + PollerHandle* wrappedHandle = impl->interruptHandle.getHandle(); + + if (impl->interruptHandle.queuedHandles()) { + impl->interrupt(); + eh.setActive(); + } else { + eh.setInactive(); + } + return Event(wrappedHandle, INTERRUPTED); + } - if (eh.isActive()) { - if (pe.portev_events & POLLHUP) { - if (eh.isHungup()) { - return Event(handle, DISCONNECTED); + if (pe.portev_source == PORT_SOURCE_FD) { + QPID_LOG(trace, "About to send handle: " << handle); + if (pe.portev_events & POLLHUP) { + if (eh.isHungup()) { + return Event(handle, DISCONNECTED); + } + eh.setHungup(); + } else { + eh.setInactive(); } - eh.setHungup(); - } else { - eh.setInactive(); - } - QPID_LOG(trace, "Sending event (thread: " - << pthread_self() << ") for handle " << handle - << ", direction= " - << PollerPrivate::pollToDirection(pe.portev_events)); - return Event(handle, PollerPrivate::pollToDirection(pe.portev_events)); + QPID_LOG(trace, "Sending event (thread: " + << pthread_self() << ") for handle " << handle + << ", direction= " + << PollerPrivate::pollToDirection(pe.portev_events)); + return Event(handle, PollerPrivate::pollToDirection(pe.portev_events)); + } + } else if (eh.isDeleted()) { + //Remove the handle from the poller + int rc = ::port_dissociate(impl->portId, PORT_SOURCE_FD, + (uintptr_t) eh.fd); + if (rc == -1 && errno != EBADFD) { + QPID_POSIX_CHECK(rc); } } } + + if (timeout == TIME_INFINITE) { + continue; + } + if (rc == 0 && now() > targetTimeout) { + PollerHandleDeletionManager.markAllUnusedInThisThread(); + return Event(0, TIMEOUT); + } } while (true); } diff --git a/qpid/cpp/src/qpid/sys/solaris/SystemInfo.cpp b/qpid/cpp/src/qpid/sys/solaris/SystemInfo.cpp new file mode 100755 index 0000000000..0075a89021 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/solaris/SystemInfo.cpp @@ -0,0 +1,123 @@ +/* + * 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/SystemInfo.h" + +#define BSD_COMP +#include <sys/ioctl.h> +#include <netdb.h> +#undef BDS_COMP + + +#include <unistd.h> +#include <net/if.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <errno.h> +#include <limits.h> +#include <procfs.h> +#include <fcntl.h> +#include <sys/types.h> + +using namespace std; + +namespace qpid { +namespace sys { + +long SystemInfo::concurrency() { + return sysconf(_SC_NPROCESSORS_ONLN); +} + +bool SystemInfo::getLocalHostname(TcpAddress &address) { + char name[MAXHOSTNAMELEN]; + if (::gethostname(name, sizeof(name)) != 0) + return false; + address.host = name; + return true; +} + +static const string LOCALHOST("127.0.0.1"); + +void SystemInfo::getLocalIpAddresses(uint16_t port, + std::vector<Address> &addrList) { + int s = socket(PF_INET, SOCK_STREAM, 0); + for (int i=1;;i++) { + struct lifreq ifr; + ifr.lifr_index = i; + if (::ioctl(s, SIOCGIFADDR, &ifr) < 0) { + break; + } + struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.lifr_addr; + std::string addr(inet_ntoa(sin->sin_addr)); + if (addr != LOCALHOST) + addrList.push_back(TcpAddress(addr, port)); + } + if (addrList.empty()) { + addrList.push_back(TcpAddress(LOCALHOST, port)); + } + close (s); +} + +void SystemInfo::getSystemId(std::string &osName, + std::string &nodeName, + std::string &release, + std::string &version, + std::string &machine) { + struct utsname _uname; + if (uname (&_uname) == 0) { + osName = _uname.sysname; + nodeName = _uname.nodename; + release = _uname.release; + version = _uname.version; + machine = _uname.machine; + } +} + +uint32_t SystemInfo::getProcessId() +{ + return (uint32_t) ::getpid(); +} + +uint32_t SystemInfo::getParentProcessId() +{ + return (uint32_t) ::getppid(); +} + +string SystemInfo::getProcessName() +{ + psinfo processInfo; + char procfile[PATH_MAX]; + int fd; + string value; + + snprintf(procfile, PATH_MAX, "/proc/%d/psinfo", getProcessId()); + if ((fd = open(procfile, O_RDONLY)) >= 0) { + if (read(fd, (void *) &processInfo, sizeof(processInfo)) == sizeof(processInfo)) { + value = processInfo.pr_fname; + } + } + return value; +} + +}} // namespace qpid::sys diff --git a/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp b/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp index 9be75af47d..624683ae7d 100644 --- a/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp +++ b/qpid/cpp/src/qpid/sys/ssl/SslIo.cpp @@ -90,7 +90,7 @@ void SslAcceptor::readable(DispatchHandle& h) { // TODO: Currently we ignore the peers address, perhaps we should // log it or use it for connection acceptance. try { - s = socket.accept(0, 0); + s = socket.accept(); if (s) { acceptedCallback(*s); } else { diff --git a/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp b/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp index 597fbe57db..dc816b403b 100644 --- a/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp +++ b/qpid/cpp/src/qpid/sys/ssl/SslSocket.cpp @@ -201,9 +201,9 @@ int SslSocket::listen(uint16_t port, int backlog, const std::string& certName, b return ntohs(name.sin_port); } -SslSocket* SslSocket::accept(struct sockaddr *addr, socklen_t *addrlen) const +SslSocket* SslSocket::accept() const { - int afd = ::accept(impl->fd, addr, addrlen); + int afd = ::accept(impl->fd, 0, 0); if ( afd >= 0) { return new SslSocket(new IOHandlePrivate(afd), prototype); } else if (errno == EAGAIN) { diff --git a/qpid/cpp/src/qpid/sys/ssl/SslSocket.h b/qpid/cpp/src/qpid/sys/ssl/SslSocket.h index a82e9133e8..7434667b78 100644 --- a/qpid/cpp/src/qpid/sys/ssl/SslSocket.h +++ b/qpid/cpp/src/qpid/sys/ssl/SslSocket.h @@ -64,7 +64,7 @@ public: * Accept a connection from a socket that is already listening * and has an incoming connection */ - SslSocket* accept(struct sockaddr *addr, socklen_t *addrlen) const; + SslSocket* accept() const; // TODO The following are raw operations, maybe they need better wrapping? int read(void *buf, size_t count) const; diff --git a/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp b/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp index 37d87947a2..0a3c36452c 100644 --- a/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp +++ b/qpid/cpp/src/qpid/sys/windows/AsynchIO.cpp @@ -690,10 +690,9 @@ void AsynchIO::writeComplete(AsynchWriteResult *result) { } } - // If there are no writes outstanding, the priority is to write any - // remaining buffers first (either queued or via idle), then close the - // socket if that's queued. - // opsInProgress handled in completion() + // If there are no writes outstanding, check for more writes to initiate + // (either queued or via idle). The opsInProgress count is handled in + // completion() if (!writeInProgress) { bool writing = false; { @@ -706,11 +705,8 @@ void AsynchIO::writeComplete(AsynchWriteResult *result) { writing = true; } } - if (!writing) { - if (queuedClose) - close(); - else - notifyIdle(); + if (!writing && !queuedClose) { + notifyIdle(); } } return; @@ -757,9 +753,11 @@ void AsynchIO::completion(AsynchIoResult *result) { } working = false; } - // Lock released; ok to delete if all is done. - if (opsInProgress == 0 && queuedDelete) - delete this; + // Lock released; ok to close if ops are done and close requested. + // Layer above will call back to queueForDeletion() + if (opsInProgress == 0 && queuedClose) { + close(); + } } } // namespace windows diff --git a/qpid/cpp/src/qpid/sys/windows/IntegerTypes.h b/qpid/cpp/src/qpid/sys/windows/IntegerTypes.h index 80168fab88..47b1d16a76 100755 --- a/qpid/cpp/src/qpid/sys/windows/IntegerTypes.h +++ b/qpid/cpp/src/qpid/sys/windows/IntegerTypes.h @@ -32,8 +32,6 @@ typedef __int64 int64_t; // Visual Studio doesn't define other common types, so set them up here too. typedef int pid_t; -typedef int socklen_t; -typedef unsigned int size_t; typedef int ssize_t; typedef unsigned int uint; diff --git a/qpid/cpp/src/qpid/sys/windows/PollableCondition.cpp b/qpid/cpp/src/qpid/sys/windows/PollableCondition.cpp new file mode 100644 index 0000000000..ed0f7c3917 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/windows/PollableCondition.cpp @@ -0,0 +1,125 @@ +#ifndef QPID_SYS_WINDOWS_POLLABLECONDITION_CPP +#define QPID_SYS_WINDOWS_POLLABLECONDITION_CPP + +/* + * + * 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/PollableCondition.h" +#include "qpid/sys/IOHandle.h" +#include "AsynchIoResult.h" +#include "IoHandlePrivate.h" + +#include <boost/bind.hpp> +#include <windows.h> + +namespace qpid { +namespace sys { + +// PollableConditionPrivate will reuse the IocpPoller's ability to queue +// a completion to the IOCP and have it dispatched to the completer callback +// noted in the IOHandlePrivate when the request is queued. The +// AsynchCallbackRequest object is not really used - we already have the +// desired callback for the user of PollableCondition. +class PollableConditionPrivate : private IOHandle { + friend class PollableCondition; + +private: + PollableConditionPrivate(const sys::PollableCondition::Callback& cb, + sys::PollableCondition& parent, + const boost::shared_ptr<sys::Poller>& poller); + ~PollableConditionPrivate(); + + void poke(); + void dispatch(AsynchIoResult *result); + +private: + PollableCondition::Callback cb; + PollableCondition& parent; + boost::shared_ptr<sys::Poller> poller; + LONG isSet; + LONG armed; +}; + +PollableConditionPrivate::PollableConditionPrivate(const sys::PollableCondition::Callback& cb, + sys::PollableCondition& parent, + const boost::shared_ptr<sys::Poller>& poller) + : IOHandle(new sys::IOHandlePrivate(INVALID_SOCKET, + boost::bind(&PollableConditionPrivate::dispatch, this, _1))), + cb(cb), parent(parent), poller(poller), isSet(0), armed(0) +{ +} + +PollableConditionPrivate::~PollableConditionPrivate() +{ +} + +void PollableConditionPrivate::poke() +{ + if (!armed) + return; + + // addFd will queue a completion for the IOCP; when it's handled, a + // poller thread will call back to dispatch() below. + PollerHandle ph(*this); + poller->addFd(ph, Poller::INPUT); +} + +void PollableConditionPrivate::dispatch(AsynchIoResult *result) +{ + delete result; // Poller::addFd() allocates this + cb(parent); +} + + /* PollableCondition */ + +PollableCondition::PollableCondition(const Callback& cb, + const boost::shared_ptr<sys::Poller>& poller) + : impl(new PollableConditionPrivate(cb, *this, poller)) +{ +} + +PollableCondition::~PollableCondition() +{ + delete impl; +} + +void PollableCondition::set() { + // Add one to the set count and poke it to provoke a callback + ::InterlockedIncrement(&impl->isSet); + impl->poke(); +} + +bool PollableCondition::clear() { + return (0 != ::InterlockedExchange(&impl->isSet, 0)); +} + +void PollableCondition::disarm() { + ::InterlockedExchange(&impl->armed, 0); +} + +void PollableCondition::rearm() { + if (0 == ::InterlockedExchange(&impl->armed, 1) && impl->isSet) + impl->poke(); +} + +}} // namespace qpid::sys + +#endif /*!QPID_SYS_WINDOWS_POLLABLECONDITION_CPP*/ diff --git a/qpid/cpp/src/qpid/sys/windows/Socket.cpp b/qpid/cpp/src/qpid/sys/windows/Socket.cpp index a9959bf43e..93059d03ef 100755 --- a/qpid/cpp/src/qpid/sys/windows/Socket.cpp +++ b/qpid/cpp/src/qpid/sys/windows/Socket.cpp @@ -262,9 +262,9 @@ int Socket::listen(uint16_t port, int backlog) const return ntohs(name.sin_port); } -Socket* Socket::accept(struct sockaddr *addr, socklen_t *addrlen) const +Socket* Socket::accept() const { - SOCKET afd = ::accept(impl->fd, addr, addrlen); + SOCKET afd = ::accept(impl->fd, 0, 0); if (afd != INVALID_SOCKET) return new Socket(new IOHandlePrivate(afd)); else if (WSAGetLastError() == EAGAIN) diff --git a/qpid/cpp/src/qpid/sys/windows/SystemInfo.cpp b/qpid/cpp/src/qpid/sys/windows/SystemInfo.cpp index b887cac58b..3e2fcb1517 100755 --- a/qpid/cpp/src/qpid/sys/windows/SystemInfo.cpp +++ b/qpid/cpp/src/qpid/sys/windows/SystemInfo.cpp @@ -29,6 +29,7 @@ #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h> +#include <tlhelp32.h> #ifndef HOST_NAME_MAX # define HOST_NAME_MAX 256 @@ -157,4 +158,41 @@ void SystemInfo::getSystemId (std::string &osName, } } +uint32_t SystemInfo::getProcessId() +{ + return static_cast<uint32_t>(::GetCurrentProcessId()); +} + +uint32_t SystemInfo::getParentProcessId() +{ + // Only want info for the current process, so ask for something specific. + // The module info won't be used here but it keeps the snapshot limited to + // the current process so a search through all processes is not needed. + HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); + if (snap == INVALID_HANDLE_VALUE) + return 0; + PROCESSENTRY32 entry; + entry.dwSize = sizeof(entry); + if (!Process32First(snap, &entry)) + entry.th32ParentProcessID = 0; + CloseHandle(snap); + return static_cast<uint32_t>(entry.th32ParentProcessID); +} + +std::string SystemInfo::getProcessName() +{ + // Only want info for the current process, so ask for something specific. + // The module info won't be used here but it keeps the snapshot limited to + // the current process so a search through all processes is not needed. + HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); + if (snap == INVALID_HANDLE_VALUE) + return 0; + PROCESSENTRY32 entry; + entry.dwSize = sizeof(entry); + if (!Process32First(snap, &entry)) + entry.szExeFile[0] = '\0'; + CloseHandle(snap); + return std::string(entry.szExeFile); +} + }} // namespace qpid::sys diff --git a/qpid/cpp/src/qpid/sys/windows/uuid.h b/qpid/cpp/src/qpid/sys/windows/uuid.h index a44ef2e9a3..7d003c3739 100644 --- a/qpid/cpp/src/qpid/sys/windows/uuid.h +++ b/qpid/cpp/src/qpid/sys/windows/uuid.h @@ -23,6 +23,7 @@ */ #include <Rpc.h> +#include "qpid/CommonImportExport.h" #ifdef uuid_t /* Done in rpcdce.h */ # undef uuid_t @@ -31,11 +32,11 @@ namespace qpid { namespace sys { const size_t UuidSize = 16; }} typedef uint8_t uuid_t[qpid::sys::UuidSize]; -void uuid_clear (uuid_t uu); -void uuid_copy (uuid_t dst, const uuid_t src); -void uuid_generate (uuid_t out); -int uuid_is_null (const uuid_t uu); // Returns 1 if null, else 0 -int uuid_parse (const char *in, uuid_t uu); // Returns 0 on success, else -1 -void uuid_unparse (const uuid_t uu, char *out); +QPID_COMMON_EXTERN void uuid_clear (uuid_t uu); +QPID_COMMON_EXTERN void uuid_copy (uuid_t dst, const uuid_t src); +QPID_COMMON_EXTERN void uuid_generate (uuid_t out); +QPID_COMMON_EXTERN int uuid_is_null (const uuid_t uu); // Returns 1 if null, else 0 +QPID_COMMON_EXTERN int uuid_parse (const char *in, uuid_t uu); // Returns 0 on success, else -1 +QPID_COMMON_EXTERN void uuid_unparse (const uuid_t uu, char *out); #endif /*!_sys_windows_uuid_h*/ diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.cpp b/qpid/cpp/src/qpid/xml/XmlExchange.cpp index 5197b239d0..4e9de49ad5 100644 --- a/qpid/cpp/src/qpid/xml/XmlExchange.cpp +++ b/qpid/cpp/src/qpid/xml/XmlExchange.cpp @@ -33,6 +33,9 @@ #include "qpid/Plugin.h" #include <xercesc/framework/MemBufInputSource.hpp> + +#include <xqilla/ast/XQGlobalVariable.hpp> + #include <xqilla/context/ItemFactory.hpp> #include <xqilla/xqilla-simple.hpp> @@ -62,17 +65,6 @@ XmlExchange::XmlExchange(const std::string& _name, bool _durable, mgmtExchange->set_type (typeName); } -/* - * Use the name of the query as the binding key. - * - * The first time a given name is used in a binding, the query body - * must be provided.After that, no query body should be present. - * - * To modify an installed query, the user must first unbind the - * existing query, then replace it by binding again with the same - * name. - * - */ // #### TODO: The Binding should take the query text // #### only. Consider encapsulating the entire block, including @@ -94,6 +86,21 @@ bool XmlExchange::bind(Queue::shared_ptr queue, const string& routingKey, const bindings.add(binding); QPID_LOG(trace, "Bound successfully with query: " << queryText ); + binding->parse_message_content = false; + + if (query->getQueryBody()->getStaticAnalysis().areContextFlagsUsed()) { + binding->parse_message_content = true; + } + else { + GlobalVariables &vars = const_cast<GlobalVariables&>(query->getVariables()); + for(GlobalVariables::iterator it = vars.begin(); it != vars.end(); ++it) { + if ((*it)->getStaticAnalysis().areContextFlagsUsed()) { + binding->parse_message_content = true; + break; + } + } + } + if (mgmtExchange != 0) { mgmtExchange->inc_bindingCount(); ((_qmf::Queue*) queue->GetManagementObject())->inc_bindingCount(); @@ -126,59 +133,74 @@ bool XmlExchange::unbind(Queue::shared_ptr queue, const string& routingKey, cons } } -bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args) +bool XmlExchange::matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args, bool parse_message_content) { - // ### TODO: Need istream for frameset - // Hack alert - the following code does not work for really large messages - string msgContent; try { - msg.getMessage().getFrames().getContent(msgContent); - - QPID_LOG(trace, "matches: query is [" << UTF8(query->getQueryText()) << "]"); - QPID_LOG(trace, "matches: message content is [" << msgContent << "]"); - - boost::scoped_ptr<DynamicContext> context(query->createDynamicContext()); - if (!context.get()) { - throw InternalErrorException(QPID_MSG("Query context looks munged ...")); - } - - XERCES_CPP_NAMESPACE::MemBufInputSource xml((const XMLByte*) msgContent.c_str(), - msgContent.length(), "input" ); - Sequence seq(context->parseDocument(xml)); - - if (args) { - FieldTable::ValueMap::const_iterator v = args->begin(); - for(; v != args->end(); ++v) { - // ### TODO: Do types properly - if (v->second->convertsTo<std::string>()) { - QPID_LOG(trace, "XmlExchange, external variable: " << v->first << " = " << v->second->getData().getString().c_str()); - Item::Ptr value = context->getItemFactory()->createString(X(v->second->getData().getString().c_str()), context.get()); - context->setExternalVariable(X(v->first.c_str()), value); - } - } - } - - if(!seq.isEmpty() && seq.first()->isNode()) { - context->setContextItem(seq.first()); - context->setContextPosition(1); - context->setContextSize(1); - } - Result result = query->execute(context.get()); - return result->getEffectiveBooleanValue(context.get(), 0); + QPID_LOG(trace, "matches: query is [" << UTF8(query->getQueryText()) << "]"); + + boost::scoped_ptr<DynamicContext> context(query->createDynamicContext()); + if (!context.get()) { + throw InternalErrorException(QPID_MSG("Query context looks munged ...")); + } + + if (parse_message_content) { + + msg.getMessage().getFrames().getContent(msgContent); + + QPID_LOG(trace, "matches: message content is [" << msgContent << "]"); + + XERCES_CPP_NAMESPACE::MemBufInputSource xml((const XMLByte*) msgContent.c_str(), + msgContent.length(), "input" ); + + // This will parse the document using either Xerces or FastXDM, depending + // on your XQilla configuration. FastXDM can be as much as 10x faster. + + Sequence seq(context->parseDocument(xml)); + + if(!seq.isEmpty() && seq.first()->isNode()) { + context->setContextItem(seq.first()); + context->setContextPosition(1); + context->setContextSize(1); + } + } + + if (args) { + FieldTable::ValueMap::const_iterator v = args->begin(); + for(; v != args->end(); ++v) { + // ### TODO: Do types properly + if (v->second->convertsTo<std::string>()) { + QPID_LOG(trace, "XmlExchange, external variable: " << v->first << " = " << v->second->getData().getString().c_str()); + Item::Ptr value = context->getItemFactory()->createString(X(v->second->getData().getString().c_str()), context.get()); + context->setExternalVariable(X(v->first.c_str()), value); + } + } + } + + Result result = query->execute(context.get()); + return result->getEffectiveBooleanValue(context.get(), 0); } catch (XQException& e) { - QPID_LOG(warning, "Could not parse XML content (or message headers):" << msgContent); - return 0; + QPID_LOG(warning, "Could not parse XML content (or message headers):" << msgContent); } catch (...) { - QPID_LOG(warning, "Unexpected error routing message: " << msgContent); - return 0; + QPID_LOG(warning, "Unexpected error routing message: " << msgContent); } return 0; } +// Future optimization: If any query in a binding for a given routing key requires +// message content, parse the message once, and use that parsed form for all bindings. +// +// Future optimization: XQilla does not currently do document projection for data +// accessed via the context item. If there is a single query for a given routing key, +// and it accesses document data, this could be a big win. +// +// Document projection often is not a win if you have multiple queries on the same data. +// 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) { PreRoute pr(msg, this); @@ -192,7 +214,7 @@ void XmlExchange::route(Deliverable& msg, const string& routingKey, const FieldT int count(0); for (std::vector<XmlBinding::shared_ptr>::const_iterator i = p->begin(); i != p->end(); i++) { - if ((*i)->xquery && matches((*i)->xquery, msg, args)) { // Overly defensive? There should always be a query ... + if (matches((*i)->xquery, msg, args, (*i)->parse_message_content)) { msg.deliverTo((*i)->queue); count++; QPID_LOG(trace, "Delivered to queue" ); diff --git a/qpid/cpp/src/qpid/xml/XmlExchange.h b/qpid/cpp/src/qpid/xml/XmlExchange.h index 066a26489d..7bec480bde 100644 --- a/qpid/cpp/src/qpid/xml/XmlExchange.h +++ b/qpid/cpp/src/qpid/xml/XmlExchange.h @@ -46,9 +46,10 @@ class XmlExchange : public virtual Exchange { typedef qpid::sys::CopyOnWriteArray<XmlBinding::shared_ptr> vector; boost::shared_ptr<XQQuery> xquery; + bool parse_message_content; XmlBinding(const std::string& key, const Queue::shared_ptr queue, Exchange* parent, Query query): - Binding(key, queue, parent), xquery(query) {} + Binding(key, queue, parent), xquery(query), parse_message_content(true) {} }; @@ -58,7 +59,7 @@ class XmlExchange : public virtual Exchange { XQilla xqilla; qpid::sys::RWlock lock; - bool matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args); + bool matches(Query& query, Deliverable& msg, const qpid::framing::FieldTable* args, bool parse_message_content); public: static const std::string typeName; |