diff options
Diffstat (limited to 'cpp/src/qpid')
244 files changed, 3460 insertions, 7393 deletions
diff --git a/cpp/src/qpid/Address.cpp b/cpp/src/qpid/Address.cpp index bed3d592df..e2b2dfbcdf 100644 --- a/cpp/src/qpid/Address.cpp +++ b/cpp/src/qpid/Address.cpp @@ -28,13 +28,7 @@ namespace qpid { const string Address::TCP("tcp"); ostream& operator<<(ostream& os, const Address& a) { - // If the host is an IPv6 literal we need to print "[]" around it - // (we detect IPv6 literals because they contain ":" which is otherwise illegal) - if (a.host.find(':') != string::npos) { - return os << a.protocol << ":[" << a.host << "]:" << a.port; - } else { - return os << a.protocol << ":" << a.host << ":" << a.port; - } + return os << a.protocol << ":" << a.host << ":" << a.port; } bool operator==(const Address& x, const Address& y) { diff --git a/cpp/src/qpid/BufferRef.h b/cpp/src/qpid/BufferRef.h deleted file mode 100644 index bfe1f9ebaa..0000000000 --- a/cpp/src/qpid/BufferRef.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef QPID_BUFFERREF_H -#define QPID_BUFFERREF_H - -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -#include "qpid/RefCounted.h" -#include <boost/intrusive_ptr.hpp> - -namespace qpid { - -/** Template for mutable or const buffer references */ -template <class T> class BufferRefT { - public: - BufferRefT() : begin_(0), end_(0) {} - - BufferRefT(boost::intrusive_ptr<RefCounted> c, T* begin, T* end) : - counter(c), begin_(begin), end_(end) {} - - template <class U> BufferRefT(const BufferRefT<U>& other) : - counter(other.counter), begin_(other.begin_), end_(other.end_) {} - - T* begin() const { return begin_; } - T* end() const { return end_; } - - /** Return a sub-buffer of the current buffer */ - BufferRefT sub_buffer(T* begin, T* end) { - assert(begin_ <= begin && begin <= end_); - assert(begin_ <= end && end <= end_); - assert(begin <= end); - return BufferRefT(counter, begin, end); - } - - private: - boost::intrusive_ptr<RefCounted> counter; - T* begin_; - T* end_; -}; - -/** - * Reference to a mutable ref-counted buffer. - */ -typedef BufferRefT<char> BufferRef; - -/** - * Reference to a const ref-counted buffer. - */ -typedef BufferRefT<const char> ConstBufferRef; - -} // namespace qpid - -#endif /*!QPID_BUFFERREF_H*/ diff --git a/cpp/src/qpid/Exception.cpp b/cpp/src/qpid/Exception.cpp index a6696f06e1..16a3a13d17 100644 --- a/cpp/src/qpid/Exception.cpp +++ b/cpp/src/qpid/Exception.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -21,25 +21,13 @@ #include "qpid/log/Statement.h" #include "qpid/Exception.h" -#include "qpid/DisableExceptionLogging.h" #include <typeinfo> #include <assert.h> #include <string.h> namespace qpid { -// Note on static initialization order: if an exception is constructed -// in a static constructor before disableExceptionLogging has been -// initialized, the worst that can happen is we lose an exception log -// message. Since we shouldn't be throwing a lot of exceptions during -// static construction this seems safe. -static bool disableExceptionLogging = false; - -DisableExceptionLogging::DisableExceptionLogging() { disableExceptionLogging = true; } -DisableExceptionLogging::~DisableExceptionLogging() { disableExceptionLogging = false; } - Exception::Exception(const std::string& msg) throw() : message(msg) { - if (disableExceptionLogging) return; QPID_LOG_IF(debug, !msg.empty(), "Exception constructed: " << message); } diff --git a/cpp/src/qpid/Modules.cpp b/cpp/src/qpid/Modules.cpp index 727e05d212..8f58df6ed1 100644 --- a/cpp/src/qpid/Modules.cpp +++ b/cpp/src/qpid/Modules.cpp @@ -64,6 +64,7 @@ void tryShlib(const char* libname_, bool noThrow) { if (!isShlibName(libname)) libname += suffix(); try { sys::Shlib shlib(libname); + QPID_LOG (info, "Loaded Module: " << libname); } catch (const std::exception& /*e*/) { if (!noThrow) @@ -81,7 +82,7 @@ void loadModuleDir (std::string dirname, bool isDefault) return; throw Exception ("Directory not found: " + dirname); } - if (!fs::is_directory(dirPath)) + if (!fs::is_directory(dirPath)) { throw Exception ("Invalid value for module-dir: " + dirname + " is not a directory"); } diff --git a/cpp/src/qpid/Options.cpp b/cpp/src/qpid/Options.cpp index 4b13e349f5..499fb71bc3 100644 --- a/cpp/src/qpid/Options.cpp +++ b/cpp/src/qpid/Options.cpp @@ -30,6 +30,23 @@ namespace qpid { using namespace std; +/* + * --------------------------------------------- + * Explanation for Boost 103200 conditional code + * --------------------------------------------- + * + * Please see large comment in Options.h . + * + */ + +#if ( BOOST_VERSION == 103200 ) +std::vector<std::string> Options::long_names; +std::vector<std::string> Options::short_names; +#endif + + + + namespace { struct EnvOptMapper { @@ -52,11 +69,49 @@ struct EnvOptMapper { static const std::string prefix("QPID_"); if (envVar.substr(0, prefix.size()) == prefix) { string env = envVar.substr(prefix.size()); +#if (BOOST_VERSION >= 103300) typedef const std::vector< boost::shared_ptr<po::option_description> > OptDescs; OptDescs::const_iterator i = find_if(opts.options().begin(), opts.options().end(), boost::bind(matchStr, env, _1)); if (i != opts.options().end()) return (*i)->long_name(); +#else + /* + * For Boost version 103200 and below. + * + * In Boost version 103200, the options_description::options member, + * used above, is private. So what I will do here is use the + * count() funtion, which returns a 1 or 0 indicating presence or + * absence of the environment variable. + * + * If it is present, I will return its name. Env vars do not have + * short and long forms, so the name is synonymous with the long + * name. (This would not work for command line args.) + * And if it's absent -- an empty string. + */ + + + /* + * The env vars come in unaltered, i.e. QPID_FOO, but the + * options are stored normalized as "qpid-foo". Change the + * local variable "env" so it can be found by "opts". + */ + for (std::string::iterator i = env.begin(); i != env.end(); ++i) + { + *i = (*i == '_') + ? '-' + : ::tolower(*i); + } + + if ( opts.count(env.c_str()) > 0 ) + { + return env.c_str(); + } + else + { + return string(); + } +#endif } return string(); } @@ -111,6 +166,10 @@ std::string prettyArg(const std::string& name, const std::string& value) { Options::Options(const string& name) : po::options_description(name) + +#if ( BOOST_VERSION == 103200 ) + , m_less_easy(this, this) +#endif { } @@ -127,6 +186,7 @@ void Options::parse(int argc, char const* const* argv, const std::string& config parsing="command line options"; if (argc > 0 && argv != 0) { if (allowUnknown) { +#if (BOOST_VERSION >= 103300) // This hideous workaround is required because boost 1.33 has a bug // that causes 'allow_unregistered' to not work. po::command_line_parser clp = po::command_line_parser(argc, const_cast<char**>(argv)). @@ -140,6 +200,113 @@ void Options::parse(int argc, char const* const* argv, const std::string& config filtopts.options.push_back (*i); po::store(filtopts, vm); +#elif ( BOOST_VERSION == 103200 ) + + /* + * "Tokenize" the argv to get rid of equals signs. + */ + vector<string> tokenized_argv; + vector<string>::iterator iter; + + for ( int i = 0; i < argc; ++ i ) + { + string s = argv[i]; + size_t equals_pos = s.find_first_of ( '=' ); + + if ( string::npos == equals_pos ) // There's no equals sign. This is a token. + { + tokenized_argv.push_back(s); + } + else + { + // Two tokens -- before and after the equals position. + tokenized_argv.push_back ( s.substr(0, equals_pos) ); + tokenized_argv.push_back ( s.substr(equals_pos+1) ); + } + } + + + /* + * Now "filter" the tokenized argv, to get rid of all + * unrecognized options. Because Boost 103200 has no + * facility for dealing gracefully with "unregistered" + * options. + */ + vector<string> filtered_argv; + vector<string>::iterator the_end = tokenized_argv.end(); + + // The program-name gets in for free... + iter = tokenized_argv.begin(); + filtered_argv.push_back ( * iter ); + ++ iter; + + // ...but all other args get checked. + while ( iter < the_end ) + { + /* + * If this is an argument that is registered, + * copy it to filtered_argv and also copy all + * of its arguments. + */ + if ( is_registered_option ( * iter ) ) + { + // Store this recognized arg. + filtered_argv.push_back ( * iter ); + ++ iter; + + // Copy all values for the above arg. + // Args are tokens that do not start with a minus. + while ( (iter < the_end) && ((* iter)[0] != '-') ) + { + filtered_argv.push_back ( * iter ); + ++ iter; + } + } + else + { + // Skip this unrecognized arg. + ++ iter; + + // Copy all values for the above arg. + // Values are tokens that do not start with a minus. + while ( (iter < the_end) && ( '-' != (*iter)[0] ) ) + { + ++ iter; + } + } + } + + // Make an array of temporary C strings, because + // the interface I can use wants it that way. + int new_argc = filtered_argv.size(); + char ** new_argv = new char * [ new_argc ]; + int i = 0; + + // cout << "NEW ARGV: |"; + for ( iter = filtered_argv.begin(); + iter < filtered_argv.end(); + ++ iter, ++ i + ) + { + new_argv[i] = strdup( (* iter).c_str() ); + // cout << " " << new_argv[i] ; + } + // cout << "|\n"; + + + // Use the array of C strings. + po::basic_parsed_options<char> bpo = po::parse_command_line(new_argc, const_cast<char**>(new_argv), *this); + po::store(bpo, vm); + + + // Now free the temporary C strings. + for ( i = 0; i < new_argc; ++ i ) + { + free ( new_argv[i] ); + } + delete[] new_argv; + +#endif } else po::store(po::parse_command_line(argc, const_cast<char**>(argv), *this), vm); @@ -196,5 +363,107 @@ CommonOptions::CommonOptions(const string& name, const string& configfile) } + + +#if ( BOOST_VERSION == 103200 ) +options_description_less_easy_init& +options_description_less_easy_init::operator()(char const * name, + char const * description) +{ + // Snoop on the arguments.... + owner->register_names ( name ); + // ... then call parent function explicitly. + po::options_description_easy_init::operator() ( name, description ); + return * this; +} + + +options_description_less_easy_init& +options_description_less_easy_init::operator()(char const * name, + const po::value_semantic* s) +{ + // Snoop on the arguments.... + owner->register_names ( name ); + // ... then call parent function explicitly. + po::options_description_easy_init::operator() ( name, s ); + return * this; +} + + +options_description_less_easy_init& +options_description_less_easy_init::operator()(const char* name, + const po::value_semantic* s, + const char* description) +{ + // Snoop on the arguments.... + owner->register_names ( name ); + // ... then call parent function explicitly. + po::options_description_easy_init::operator() ( name, s, description ); + return * this; +} + + + + + +void +Options::register_names ( std::string s ) +{ + + std::string::size_type comma_pos = s.find_first_of ( ',' ); + + if ( std::string::npos == comma_pos ) + { + // There is no short-name. + long_names.push_back ( s ); + } + else + { + std::string long_name = s.substr(0, comma_pos), + short_name = s.substr(comma_pos+1); + long_names .push_back ( long_name ); + short_names.push_back ( short_name ); + } + + /* + * There is no way to tell when the adding of new options is finished, + * so I re-sort after each one. + */ + std::sort ( long_names .begin(), long_names .end() ); + std::sort ( short_names.begin(), short_names.end() ); +} + + + + + +bool +Options::is_registered_option ( std::string s ) +{ + std::string without_dashes = s.substr ( s.find_first_not_of ( '-' ) ); + std::vector<std::string>::iterator i; + + // Look among the long names. + i = std::find ( long_names.begin(), + long_names.end(), + without_dashes + ); + if ( i != long_names.end() ) + return true; + + // Look among the short names. + i = std::find ( short_names.begin(), + short_names.end(), + without_dashes + ); + if ( i != short_names.end() ) + return true; + + + return false; +} +#endif + + } // namespace qpid diff --git a/cpp/src/qpid/RefCounted.h b/cpp/src/qpid/RefCounted.h index f9e0107103..e7a9bf31c1 100644 --- a/cpp/src/qpid/RefCounted.h +++ b/cpp/src/qpid/RefCounted.h @@ -53,10 +53,8 @@ protected: // intrusive_ptr support. namespace boost { -template <typename T> -inline void intrusive_ptr_add_ref(const T* p) { p->qpid::RefCounted::addRef(); } -template <typename T> -inline void intrusive_ptr_release(const T* p) { p->qpid::RefCounted::release(); } +inline void intrusive_ptr_add_ref(const qpid::RefCounted* p) { p->addRef(); } +inline void intrusive_ptr_release(const qpid::RefCounted* p) { p->release(); } } diff --git a/cpp/src/qpid/RefCountedBuffer.cpp b/cpp/src/qpid/RefCountedBuffer.cpp index a82e1a02ab..9b8f1ebd5e 100644 --- a/cpp/src/qpid/RefCountedBuffer.cpp +++ b/cpp/src/qpid/RefCountedBuffer.cpp @@ -20,27 +20,34 @@ */ #include "qpid/RefCountedBuffer.h" -#include <stdlib.h> #include <new> namespace qpid { -void RefCountedBuffer::released() const { +RefCountedBuffer::RefCountedBuffer() : count(0) {} + +void RefCountedBuffer::destroy() const { this->~RefCountedBuffer(); - ::free (reinterpret_cast<void *>(const_cast<RefCountedBuffer *>(this))); + ::delete[] reinterpret_cast<const char*>(this); +} + +char* RefCountedBuffer::addr() const { + return const_cast<char*>(reinterpret_cast<const char*>(this)+sizeof(RefCountedBuffer)); } -BufferRef RefCountedBuffer::create(size_t n) { - void* store=::malloc (n + sizeof(RefCountedBuffer)); - if (NULL == store) - throw std::bad_alloc(); +RefCountedBuffer::pointer RefCountedBuffer::create(size_t n) { + char* store=::new char[n+sizeof(RefCountedBuffer)]; new(store) RefCountedBuffer; - char* start = reinterpret_cast<char *>(store) + sizeof(RefCountedBuffer); - return BufferRef( - boost::intrusive_ptr<RefCounted>(reinterpret_cast<RefCountedBuffer*>(store)), - start, start+n); + return pointer(reinterpret_cast<RefCountedBuffer*>(store)); } +RefCountedBuffer::pointer::pointer() {} +RefCountedBuffer::pointer::pointer(RefCountedBuffer* x) : p(x) {} +RefCountedBuffer::pointer::pointer(const pointer& x) : p(x.p) {} +RefCountedBuffer::pointer::~pointer() {} +RefCountedBuffer::pointer& RefCountedBuffer::pointer::operator=(const RefCountedBuffer::pointer& x) { p = x.p; return *this; } + +char* RefCountedBuffer::pointer::cp() const { return p ? p->get() : 0; } } // namespace qpid diff --git a/cpp/src/qpid/RefCountedBuffer.h b/cpp/src/qpid/RefCountedBuffer.h index f0ea86130b..75a23862be 100644 --- a/cpp/src/qpid/RefCountedBuffer.h +++ b/cpp/src/qpid/RefCountedBuffer.h @@ -22,23 +22,68 @@ * */ -#include <qpid/RefCounted.h> -#include <qpid/BufferRef.h> +#include <boost/utility.hpp> +#include <boost/detail/atomic_count.hpp> +#include <boost/intrusive_ptr.hpp> namespace qpid { /** - * Reference-counted byte buffer. No alignment guarantees. + * Reference-counted byte buffer. + * No alignment guarantees. */ -class RefCountedBuffer : public RefCounted { - public: +class RefCountedBuffer : boost::noncopyable { + mutable boost::detail::atomic_count count; + RefCountedBuffer(); + void destroy() const; + char* addr() const; + +public: + /** Smart char pointer to a reference counted buffer */ + class pointer { + boost::intrusive_ptr<RefCountedBuffer> p; + char* cp() const; + pointer(RefCountedBuffer* x); + friend class RefCountedBuffer; + + public: + pointer(); + pointer(const pointer&); + ~pointer(); + pointer& operator=(const pointer&); + + char* get() { return cp(); } + operator char*() { return cp(); } + char& operator*() { return *cp(); } + char& operator[](size_t i) { return cp()[i]; } + + const char* get() const { return cp(); } + operator const char*() const { return cp(); } + const char& operator*() const { return *cp(); } + const char& operator[](size_t i) const { return cp()[i]; } + }; + /** Create a reference counted buffer of size n */ - static BufferRef create(size_t n); + static pointer create(size_t n); + + /** Get a pointer to the start of the buffer. */ + char* get() { return addr(); } + const char* get() const { return addr(); } + char& operator[](size_t i) { return get()[i]; } + const char& operator[](size_t i) const { return get()[i]; } - protected: - void released() const; + void addRef() const { ++count; } + void release() const { if (--count==0) destroy(); } + long refCount() { return count; } }; } // namespace qpid +// intrusive_ptr support. +namespace boost { +inline void intrusive_ptr_add_ref(const qpid::RefCountedBuffer* p) { p->addRef(); } +inline void intrusive_ptr_release(const qpid::RefCountedBuffer* p) { p->release(); } +} + + #endif /*!QPID_REFCOUNTEDBUFFER_H*/ diff --git a/cpp/src/qpid/Sasl.h b/cpp/src/qpid/Sasl.h index 4d579fa051..9a9d61b037 100644 --- a/cpp/src/qpid/Sasl.h +++ b/cpp/src/qpid/Sasl.h @@ -47,8 +47,8 @@ class Sasl * client supports. * @param externalSecuritySettings security related details from the underlying transport */ - virtual bool start(const std::string& mechanisms, std::string& response, - const qpid::sys::SecuritySettings* externalSecuritySettings = 0) = 0; + virtual std::string start(const std::string& mechanisms, + const qpid::sys::SecuritySettings* externalSecuritySettings = 0) = 0; virtual std::string step(const std::string& challenge) = 0; virtual std::string getMechanism() = 0; virtual std::string getUserId() = 0; diff --git a/cpp/src/qpid/SaslFactory.cpp b/cpp/src/qpid/SaslFactory.cpp index a8d1f94c1e..055883abee 100644 --- a/cpp/src/qpid/SaslFactory.cpp +++ b/cpp/src/qpid/SaslFactory.cpp @@ -112,7 +112,7 @@ class CyrusSasl : public Sasl public: CyrusSasl(const std::string & username, const std::string & password, const std::string & serviceName, const std::string & hostName, int minSsf, int maxSsf, bool allowInteraction); ~CyrusSasl(); - bool start(const std::string& mechanisms, std::string& response, const SecuritySettings* externalSettings); + std::string start(const std::string& mechanisms, const SecuritySettings* externalSettings); std::string step(const std::string& challenge); std::string getMechanism(); std::string getUserId(); @@ -182,17 +182,16 @@ CyrusSasl::CyrusSasl(const std::string & username, const std::string & password, callbacks[i].id = SASL_CB_AUTHNAME; callbacks[i].proc = (CallbackProc*) &getUserFromSettings; callbacks[i++].context = &settings; - - callbacks[i].id = SASL_CB_PASS; - if (settings.password.empty()) { - callbacks[i].proc = 0; - callbacks[i++].context = 0; - } else { - callbacks[i].proc = (CallbackProc*) &getPasswordFromSettings; - callbacks[i++].context = &settings; - } } + callbacks[i].id = SASL_CB_PASS; + if (settings.password.empty()) { + callbacks[i].proc = 0; + callbacks[i++].context = 0; + } else { + callbacks[i].proc = (CallbackProc*) &getPasswordFromSettings; + callbacks[i++].context = &settings; + } callbacks[i].id = SASL_CB_LIST_END; callbacks[i].proc = 0; @@ -210,7 +209,7 @@ namespace { const std::string SSL("ssl"); } -bool CyrusSasl::start(const std::string& mechanisms, std::string& response, const SecuritySettings* externalSettings) +std::string CyrusSasl::start(const std::string& mechanisms, const SecuritySettings* externalSettings) { QPID_LOG(debug, "CyrusSasl::start(" << mechanisms << ")"); int result = sasl_client_new(settings.service.c_str(), @@ -283,12 +282,7 @@ bool CyrusSasl::start(const std::string& mechanisms, std::string& response, cons mechanism = std::string(chosenMechanism); QPID_LOG(debug, "CyrusSasl::start(" << mechanisms << "): selected " << mechanism << " response: '" << std::string(out, outlen) << "'"); - if (out) { - response = std::string(out, outlen); - return true; - } else { - return false; - } + return std::string(out, outlen); } std::string CyrusSasl::step(const std::string& challenge) diff --git a/cpp/src/qpid/Url.cpp b/cpp/src/qpid/Url.cpp index f699b60c17..ab796f4642 100644 --- a/cpp/src/qpid/Url.cpp +++ b/cpp/src/qpid/Url.cpp @@ -156,12 +156,11 @@ class UrlParser { return false; } - // A liberal interpretation of http://www.ietf.org/rfc/rfc3986.txt. - // Works for DNS names and and ipv4 and ipv6 literals + // TODO aconway 2008-11-20: this does not fully implement + // http://www.ietf.org/rfc/rfc3986.txt. Works for DNS names and + // ipv4 literals but won't handle ipv6. // bool host(string& h) { - if (ip6literal(h)) return true; - const char* start=i; while (unreserved() || pctEncoded()) ; @@ -170,22 +169,6 @@ class UrlParser { return true; } - // This is a bit too liberal for IPv6 literal addresses, but probably good enough - bool ip6literal(string& h) { - if (literal("[")) { - const char* start = i; - while (hexDigit() || literal(":") || literal(".")) - ; - const char* end = i; - if ( end-start < 2 ) return false; // Smallest valid address is "::" - if (literal("]")) { - h.assign(start, end); - return true; - } - } - return false; - } - bool unreserved() { return (::isalnum(*i) || ::strchr("-._~", *i)) && advance(); } bool pctEncoded() { return literal("%") && hexDigit() && hexDigit(); } diff --git a/cpp/src/qpid/acl/Acl.cpp b/cpp/src/qpid/acl/Acl.cpp index 4b3dda7962..67603015d7 100644 --- a/cpp/src/qpid/acl/Acl.cpp +++ b/cpp/src/qpid/acl/Acl.cpp @@ -180,10 +180,7 @@ Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(fals { case _qmf::Acl::METHOD_RELOADACLFILE : readAclFile(text); - if (text.empty()) - status = Manageable::STATUS_OK; - else - status = Manageable::STATUS_USER; + status = Manageable::STATUS_USER; break; } diff --git a/cpp/src/qpid/acl/AclPlugin.cpp b/cpp/src/qpid/acl/AclPlugin.cpp index d611797c49..e4d721ea44 100644 --- a/cpp/src/qpid/acl/AclPlugin.cpp +++ b/cpp/src/qpid/acl/AclPlugin.cpp @@ -69,7 +69,7 @@ struct AclPlugin : public Plugin { } acl = new Acl(values, b); - b.setAcl(acl.get()); + b.setAcl(acl.get()); b.addFinalizer(boost::bind(&AclPlugin::shutdown, this)); } diff --git a/cpp/src/qpid/agent/ManagementAgentImpl.cpp b/cpp/src/qpid/agent/ManagementAgentImpl.cpp index f183ff8e0c..593d403a11 100644 --- a/cpp/src/qpid/agent/ManagementAgentImpl.cpp +++ b/cpp/src/qpid/agent/ManagementAgentImpl.cpp @@ -305,47 +305,43 @@ void ManagementAgentImpl::raiseEvent(const ManagementEvent& event, severity_t se "emerg", "alert", "crit", "error", "warn", "note", "info", "debug" }; - string content; + sys::Mutex::ScopedLock lock(agentLock); + Buffer outBuffer(eventBuffer, MA_BUFFER_SIZE); + uint8_t sev = (severity == SEV_DEFAULT) ? event.getSeverity() : (uint8_t) severity; stringstream key; - Variant::Map headers; - { - sys::Mutex::ScopedLock lock(agentLock); - Buffer outBuffer(eventBuffer, MA_BUFFER_SIZE); - uint8_t sev = (severity == SEV_DEFAULT) ? event.getSeverity() : (uint8_t) severity; - - // key << "console.event." << assignedBrokerBank << "." << assignedAgentBank << "." << - // event.getPackageName() << "." << event.getEventName(); - key << "agent.ind.event." << keyifyNameStr(event.getPackageName()) - << "." << keyifyNameStr(event.getEventName()) - << "." << severityStr[sev] - << "." << vendorNameKey - << "." << productNameKey - << "." << instanceNameKey; - - Variant::Map map_; - Variant::Map schemaId; - Variant::Map values; - - map_["_schema_id"] = mapEncodeSchemaId(event.getPackageName(), - event.getEventName(), - event.getMd5Sum(), - ManagementItem::CLASS_KIND_EVENT); - event.mapEncode(values); - map_["_values"] = values; - map_["_timestamp"] = uint64_t(Duration(EPOCH, now())); - map_["_severity"] = sev; + // key << "console.event." << assignedBrokerBank << "." << assignedAgentBank << "." << + // event.getPackageName() << "." << event.getEventName(); + key << "agent.ind.event." << keyifyNameStr(event.getPackageName()) + << "." << keyifyNameStr(event.getEventName()) + << "." << severityStr[sev] + << "." << vendorNameKey + << "." << productNameKey + << "." << instanceNameKey; - headers["method"] = "indication"; - headers["qmf.opcode"] = "_data_indication"; - headers["qmf.content"] = "_event"; - headers["qmf.agent"] = name_address; + Variant::Map map_; + Variant::Map schemaId; + Variant::Map values; + Variant::Map headers; + string content; - Variant::List list; - list.push_back(map_); - ListCodec::encode(list, content); - } + map_["_schema_id"] = mapEncodeSchemaId(event.getPackageName(), + event.getEventName(), + event.getMd5Sum(), + ManagementItem::CLASS_KIND_EVENT); + event.mapEncode(values); + map_["_values"] = values; + map_["_timestamp"] = uint64_t(Duration(EPOCH, now())); + map_["_severity"] = sev; + headers["method"] = "indication"; + headers["qmf.opcode"] = "_data_indication"; + headers["qmf.content"] = "_event"; + headers["qmf.agent"] = name_address; + + Variant::List list; + list.push_back(map_); + ListCodec::encode(list, content); connThreadBody.sendBuffer(content, "", headers, topicExchange, key.str(), "amqp/list"); } @@ -525,12 +521,9 @@ void ManagementAgentImpl::sendException(const string& rte, const string& rtk, co void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequence, const string& rte, const string& rtk) { + sys::Mutex::ScopedLock lock(agentLock); string packageName; SchemaClassKey key; - uint32_t outLen(0); - char localBuffer[MA_BUFFER_SIZE]; - Buffer outBuffer(localBuffer, MA_BUFFER_SIZE); - bool found(false); inBuffer.getShortString(packageName); inBuffer.getShortString(key.name); @@ -538,30 +531,26 @@ void ManagementAgentImpl::handleSchemaRequest(Buffer& inBuffer, uint32_t sequenc QPID_LOG(trace, "RCVD SchemaRequest: package=" << packageName << " class=" << key.name); - { - sys::Mutex::ScopedLock lock(agentLock); - PackageMap::iterator pIter = packages.find(packageName); - if (pIter != packages.end()) { - ClassMap& cMap = pIter->second; - ClassMap::iterator cIter = cMap.find(key); - if (cIter != cMap.end()) { - SchemaClass& schema = cIter->second; - string body; - - encodeHeader(outBuffer, 's', sequence); - schema.writeSchemaCall(body); - outBuffer.putRawData(body); - outLen = MA_BUFFER_SIZE - outBuffer.available(); - outBuffer.reset(); - found = true; - } + PackageMap::iterator pIter = packages.find(packageName); + if (pIter != packages.end()) { + ClassMap& cMap = pIter->second; + ClassMap::iterator cIter = cMap.find(key); + if (cIter != cMap.end()) { + SchemaClass& schema = cIter->second; + Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); + uint32_t outLen; + string body; + + encodeHeader(outBuffer, 's', sequence); + schema.writeSchemaCall(body); + outBuffer.putRawData(body); + outLen = MA_BUFFER_SIZE - outBuffer.available(); + outBuffer.reset(); + connThreadBody.sendBuffer(outBuffer, outLen, rte, rtk); + + QPID_LOG(trace, "SENT SchemaInd: package=" << packageName << " class=" << key.name); } } - - if (found) { - connThreadBody.sendBuffer(outBuffer, outLen, rte, rtk); - QPID_LOG(trace, "SENT SchemaInd: package=" << packageName << " class=" << key.name); - } } void ManagementAgentImpl::handleConsoleAddedIndication() @@ -980,6 +969,18 @@ ManagementAgentImpl::PackageMap::iterator ManagementAgentImpl::findOrAddPackage( pair<PackageMap::iterator, bool> result = packages.insert(pair<string, ClassMap>(name, ClassMap())); + if (connected) { + // Publish a package-indication message + Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); + uint32_t outLen; + + encodeHeader(outBuffer, 'p'); + encodePackageIndication(outBuffer, result.first); + outLen = MA_BUFFER_SIZE - outBuffer.available(); + outBuffer.reset(); + connThreadBody.sendBuffer(outBuffer, outLen, "qpid.management", "schema.package"); + } + return result.first; } @@ -1037,146 +1038,131 @@ void ManagementAgentImpl::encodeClassIndication(Buffer& buf, QPID_LOG(trace, "SENT ClassInd: package=" << (*pIter).first << " class=" << key.name); } -struct MessageItem { - string content; - Variant::Map headers; - string key; - MessageItem(const Variant::Map& h, const string& k) : headers(h), key(k) {} -}; - void ManagementAgentImpl::periodicProcessing() { string addr_key_base = "agent.ind.data."; + sys::Mutex::ScopedLock lock(agentLock); list<ObjectId> deleteList; - list<boost::shared_ptr<MessageItem> > message_list; + + if (!connected) + return; sendHeartbeat(); - { - sys::Mutex::ScopedLock lock(agentLock); + moveNewObjectsLH(); - if (!connected) - return; + // + // Clear the been-here flag on all objects in the map. + // + for (ObjectMap::iterator iter = managementObjects.begin(); + iter != managementObjects.end(); + iter++) { + ManagementObject* object = iter->second.get(); + object->setFlags(0); + if (publishAllData) { + object->setForcePublish(true); + } + } + + publishAllData = false; - moveNewObjectsLH(); + // + // Process the entire object map. + // + uint32_t v2Objs = 0; + + for (ObjectMap::iterator baseIter = managementObjects.begin(); + baseIter != managementObjects.end(); + baseIter++) { + ManagementObject* baseObject = baseIter->second.get(); // - // Clear the been-here flag on all objects in the map. + // Skip until we find a base object requiring a sent message. // - for (ObjectMap::iterator iter = managementObjects.begin(); + if (baseObject->getFlags() == 1 || + (!baseObject->getConfigChanged() && + !baseObject->getInstChanged() && + !baseObject->getForcePublish() && + !baseObject->isDeleted())) + continue; + + std::string packageName = baseObject->getPackageName(); + std::string className = baseObject->getClassName(); + + Variant::List list_; + string content; + std::stringstream addr_key; + Variant::Map headers; + + addr_key << addr_key_base; + addr_key << keyifyNameStr(packageName) + << "." << keyifyNameStr(className) + << "." << vendorNameKey + << "." << productNameKey + << "." << instanceNameKey; + + headers["method"] = "indication"; + headers["qmf.opcode"] = "_data_indication"; + headers["qmf.content"] = "_data"; + headers["qmf.agent"] = name_address; + + for (ObjectMap::iterator iter = baseIter; iter != managementObjects.end(); iter++) { ManagementObject* object = iter->second.get(); - object->setFlags(0); - if (publishAllData) { - object->setForcePublish(true); - } - } - - publishAllData = false; - - // - // Process the entire object map. - // - uint32_t v2Objs = 0; - - for (ObjectMap::iterator baseIter = managementObjects.begin(); - baseIter != managementObjects.end(); - baseIter++) { - ManagementObject* baseObject = baseIter->second.get(); - - // - // Skip until we find a base object requiring a sent message. - // - if (baseObject->getFlags() == 1 || - (!baseObject->getConfigChanged() && - !baseObject->getInstChanged() && - !baseObject->getForcePublish() && - !baseObject->isDeleted())) - continue; - - std::string packageName = baseObject->getPackageName(); - std::string className = baseObject->getClassName(); - - Variant::List list_; - std::stringstream addr_key; - Variant::Map headers; - - addr_key << addr_key_base; - addr_key << keyifyNameStr(packageName) - << "." << keyifyNameStr(className) - << "." << vendorNameKey - << "." << productNameKey - << "." << instanceNameKey; - - headers["method"] = "indication"; - headers["qmf.opcode"] = "_data_indication"; - headers["qmf.content"] = "_data"; - headers["qmf.agent"] = name_address; - - for (ObjectMap::iterator iter = baseIter; - iter != managementObjects.end(); - iter++) { - ManagementObject* object = iter->second.get(); - bool send_stats, send_props; - if (baseObject->isSameClass(*object) && object->getFlags() == 0) { - object->setFlags(1); - if (object->getConfigChanged() || object->getInstChanged()) - object->setUpdateTime(); - - send_props = (object->getConfigChanged() || object->getForcePublish() || object->isDeleted()); - send_stats = (object->hasInst() && (object->getInstChanged() || object->getForcePublish())); - - if (send_stats || send_props) { - Variant::Map map_; - Variant::Map values; - Variant::Map oid; - - object->getObjectId().mapEncode(oid); - map_["_object_id"] = oid; - map_["_schema_id"] = mapEncodeSchemaId(object->getPackageName(), - object->getClassName(), - object->getMd5Sum()); - object->writeTimestamps(map_); - object->mapEncodeValues(values, send_props, send_stats); - map_["_values"] = values; - list_.push_back(map_); + bool send_stats, send_props; + if (baseObject->isSameClass(*object) && object->getFlags() == 0) { + object->setFlags(1); + if (object->getConfigChanged() || object->getInstChanged()) + object->setUpdateTime(); - if (++v2Objs >= maxV2ReplyObjs) { - v2Objs = 0; - boost::shared_ptr<MessageItem> item(new MessageItem(headers, addr_key.str())); - ListCodec::encode(list_, item->content); - message_list.push_back(item); - list_.clear(); - } + send_props = (object->getConfigChanged() || object->getForcePublish() || object->isDeleted()); + send_stats = (object->hasInst() && (object->getInstChanged() || object->getForcePublish())); + + if (send_stats || send_props) { + Variant::Map map_; + Variant::Map values; + Variant::Map oid; + + object->getObjectId().mapEncode(oid); + map_["_object_id"] = oid; + map_["_schema_id"] = mapEncodeSchemaId(object->getPackageName(), + object->getClassName(), + object->getMd5Sum()); + object->writeTimestamps(map_); + object->mapEncodeValues(values, send_props, send_stats); + map_["_values"] = values; + list_.push_back(map_); + + if (++v2Objs >= maxV2ReplyObjs) { + v2Objs = 0; + ListCodec::encode(list_, content); + + connThreadBody.sendBuffer(content, "", headers, topicExchange, addr_key.str(), "amqp/list"); + list_.clear(); + content.clear(); + QPID_LOG(trace, "SENT DataIndication"); } - - if (object->isDeleted()) - deleteList.push_back(iter->first); - object->setForcePublish(false); } - } - if (!list_.empty()) { - boost::shared_ptr<MessageItem> item(new MessageItem(headers, addr_key.str())); - ListCodec::encode(list_, item->content); - message_list.push_back(item); + if (object->isDeleted()) + deleteList.push_back(iter->first); + object->setForcePublish(false); } } - // Delete flagged objects - for (list<ObjectId>::reverse_iterator iter = deleteList.rbegin(); - iter != deleteList.rend(); - iter++) - managementObjects.erase(*iter); + if (!list_.empty()) { + ListCodec::encode(list_, content); + connThreadBody.sendBuffer(content, "", headers, topicExchange, addr_key.str(), "amqp/list"); + QPID_LOG(trace, "SENT DataIndication"); + } } - while (!message_list.empty()) { - boost::shared_ptr<MessageItem> item(message_list.front()); - message_list.pop_front(); - connThreadBody.sendBuffer(item->content, "", item->headers, topicExchange, item->key, "amqp/list"); - QPID_LOG(trace, "SENT DataIndication"); - } + // Delete flagged objects + for (list<ObjectId>::reverse_iterator iter = deleteList.rbegin(); + iter != deleteList.rend(); + iter++) + managementObjects.erase(*iter); } @@ -1378,26 +1364,13 @@ bool ManagementAgentImpl::ConnectionThread::isSleeping() const void ManagementAgentImpl::PublishThread::run() { - uint16_t totalSleep; - uint16_t sleepTime; + uint16_t totalSleep; while (!shutdown) { agent.periodicProcessing(); totalSleep = 0; - - // - // Calculate a sleep time that is no greater than 5 seconds and - // no less than 1 second. - // - sleepTime = agent.getInterval(); - if (sleepTime > 5) - sleepTime = 5; - else if (sleepTime == 0) - sleepTime = 1; - - while (totalSleep < agent.getInterval() && !shutdown) { - ::sleep(sleepTime); - totalSleep += sleepTime; + while (totalSleep++ < agent.getInterval() && !shutdown) { + ::sleep(1); } } } diff --git a/cpp/src/qpid/agent/ManagementAgentImpl.h b/cpp/src/qpid/agent/ManagementAgentImpl.h index 53f3c13a91..bf340777d1 100644 --- a/cpp/src/qpid/agent/ManagementAgentImpl.h +++ b/cpp/src/qpid/agent/ManagementAgentImpl.h @@ -62,8 +62,8 @@ class ManagementAgentImpl : public ManagementAgent, public client::MessageListen uint16_t intervalSeconds = 10, bool useExternalThread = false, const std::string& storeFile = "", - const std::string& uid = "", - const std::string& pwd = "", + const std::string& uid = "guest", + const std::string& pwd = "guest", const std::string& mech = "PLAIN", const std::string& proto = "tcp"); void init(const management::ConnectionSettings& settings, diff --git a/cpp/src/qpid/amqp_0_10/Codecs.cpp b/cpp/src/qpid/amqp_0_10/Codecs.cpp index b976a5d09b..0fbe2a60b9 100644 --- a/cpp/src/qpid/amqp_0_10/Codecs.cpp +++ b/cpp/src/qpid/amqp_0_10/Codecs.cpp @@ -127,10 +127,10 @@ Variant toVariant(boost::shared_ptr<FieldValue> in) switch (in->getType()) { //Fixed Width types: case 0x01: out.setEncoding(amqp0_10_binary); - case 0x02: out = in->getIntegerValue<int8_t>(); break; - case 0x03: out = in->getIntegerValue<uint8_t>(); break; + case 0x02: out = in->getIntegerValue<int8_t, 1>(); break; + case 0x03: out = in->getIntegerValue<uint8_t, 1>(); break; case 0x04: break; //TODO: iso-8859-15 char - case 0x08: out = static_cast<bool>(in->getIntegerValue<uint8_t>()); break; + case 0x08: out = static_cast<bool>(in->getIntegerValue<uint8_t, 1>()); break; case 0x10: out.setEncoding(amqp0_10_binary); case 0x11: out = in->getIntegerValue<int16_t, 2>(); break; case 0x12: out = in->getIntegerValue<uint16_t, 2>(); break; diff --git a/cpp/src/qpid/amqp_0_10/SessionHandler.cpp b/cpp/src/qpid/amqp_0_10/SessionHandler.cpp index 578598a146..b113d49a73 100644 --- a/cpp/src/qpid/amqp_0_10/SessionHandler.cpp +++ b/cpp/src/qpid/amqp_0_10/SessionHandler.cpp @@ -130,6 +130,9 @@ void SessionHandler::handleException(const qpid::SessionException& e) } namespace { +bool isControl(const AMQFrame& f) { + return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_CONTROL; +} bool isCommand(const AMQFrame& f) { return f.getMethod() && f.getMethod()->type() == framing::SEGMENT_TYPE_COMMAND; } @@ -188,10 +191,9 @@ void SessionHandler::detach(const std::string& name) { void SessionHandler::detached(const std::string& name, uint8_t code) { CHECK_NAME(name, "session.detached"); awaitingDetached = false; - if (code != session::DETACH_CODE_NORMAL) { - sendReady = receiveReady = false; + if (code != session::DETACH_CODE_NORMAL) channelException(convert(code), "session.detached from peer."); - } else { + else { handleDetach(); } } diff --git a/cpp/src/qpid/amqp_0_10/SessionHandler.h b/cpp/src/qpid/amqp_0_10/SessionHandler.h index 8b072fa05c..a87a1a155f 100644 --- a/cpp/src/qpid/amqp_0_10/SessionHandler.h +++ b/cpp/src/qpid/amqp_0_10/SessionHandler.h @@ -41,8 +41,8 @@ namespace amqp_0_10 { * to a session state. */ -class QPID_COMMON_CLASS_EXTERN SessionHandler : public framing::AMQP_AllOperations::SessionHandler, - public framing::FrameHandler::InOutHandler +class SessionHandler : public framing::AMQP_AllOperations::SessionHandler, + public framing::FrameHandler::InOutHandler { public: QPID_COMMON_EXTERN SessionHandler(framing::FrameHandler* out=0, uint16_t channel=0); @@ -66,7 +66,7 @@ class QPID_COMMON_CLASS_EXTERN SessionHandler : public framing::AMQP_AllOperatio QPID_COMMON_EXTERN void handleException(const qpid::SessionException& e); /** True if the handler is ready to send and receive */ - QPID_COMMON_EXTERN bool ready() const; + bool ready() const; // Protocol methods QPID_COMMON_EXTERN void attach(const std::string& name, bool force); diff --git a/cpp/src/qpid/broker/AsyncCompletion.h b/cpp/src/qpid/broker/AsyncCompletion.h deleted file mode 100644 index fef994438f..0000000000 --- a/cpp/src/qpid/broker/AsyncCompletion.h +++ /dev/null @@ -1,201 +0,0 @@ -#ifndef _AsyncCompletion_ -#define _AsyncCompletion_ - -/* - * - * 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 <boost/intrusive_ptr.hpp> - -#include "qpid/broker/BrokerImportExport.h" -#include "qpid/sys/AtomicValue.h" -#include "qpid/sys/Mutex.h" -#include "qpid/sys/Monitor.h" - -namespace qpid { -namespace broker { - -/** - * Class to implement asynchronous notification of completion. - * - * Use-case: An "initiator" needs to wait for a set of "completers" to - * finish a unit of work before an action can occur. This object - * tracks the progress of the set of completers, and allows the action - * to occur once all completers have signalled that they are done. - * - * The initiator and completers may be running in separate threads. - * - * The initiating thread is the thread that initiates the action, - * i.e. the connection read thread. - * - * A completing thread is any thread that contributes to completion, - * e.g. a store thread that does an async write. - * There may be zero or more completers. - * - * When the work is complete, a callback is invoked. The callback - * may be invoked in the Initiator thread, or one of the Completer - * threads. The callback is passed a flag indicating whether or not - * the callback is running under the context of the Initiator thread. - * - * Use model: - * 1) Initiator thread invokes begin() - * 2) After begin() has been invoked, zero or more Completers invoke - * startCompleter(). Completers may be running in the same or - * different thread as the Initiator, as long as they guarantee that - * startCompleter() is invoked at least once before the Initiator invokes end(). - * 3) Completers may invoke finishCompleter() at any time, even after the - * initiator has invoked end(). finishCompleter() may be called from any - * thread. - * 4) startCompleter()/finishCompleter() calls "nest": for each call to - * startCompleter(), a corresponding call to finishCompleter() must be made. - * Once the last finishCompleter() is called, the Completer must no longer - * reference the completion object. - * 5) The Initiator invokes end() at the point where it has finished - * dispatching work to the Completers, and is prepared for the callback - * handler to be invoked. Note: if there are no outstanding Completers - * pending when the Initiator invokes end(), the callback will be invoked - * directly, and the sync parameter will be set true. This indicates to the - * Initiator that the callback is executing in the context of the end() call, - * and the Initiator is free to optimize the handling of the completion, - * assuming no need for synchronization with Completer threads. - */ - -class AsyncCompletion -{ - public: - - /** Supplied by the Initiator to the end() method, allows for a callback - * when all outstanding completers are done. If the callback cannot be - * made during the end() call, the clone() method must supply a copy of - * this callback object that persists after end() returns. The cloned - * callback object will be used by the last completer thread, and - * released when the callback returns. - */ - class Callback : public RefCounted - { - public: - virtual void completed(bool) = 0; - virtual boost::intrusive_ptr<Callback> clone() = 0; - }; - - private: - mutable qpid::sys::AtomicValue<uint32_t> completionsNeeded; - mutable qpid::sys::Monitor callbackLock; - bool inCallback, active; - - void invokeCallback(bool sync) { - qpid::sys::Mutex::ScopedLock l(callbackLock); - if (active) { - if (callback.get()) { - inCallback = true; - { - qpid::sys::Mutex::ScopedUnlock ul(callbackLock); - callback->completed(sync); - } - inCallback = false; - callback = boost::intrusive_ptr<Callback>(); - callbackLock.notifyAll(); - } - active = false; - } - } - - protected: - /** Invoked when all completers have signalled that they have completed - * (via calls to finishCompleter()). bool == true if called via end() - */ - boost::intrusive_ptr<Callback> callback; - - public: - AsyncCompletion() : completionsNeeded(0), inCallback(false), active(true) {}; - virtual ~AsyncCompletion() { cancel(); } - - - /** True when all outstanding operations have compeleted - */ - bool isDone() - { - return !active; - } - - /** Called to signal the start of an asynchronous operation. The operation - * is considered pending until finishCompleter() is called. - * E.g. called when initiating an async store operation. - */ - void startCompleter() { ++completionsNeeded; } - - /** Called by completer to signal that it has finished the operation started - * when startCompleter() was invoked. - * e.g. called when async write complete. - */ - void finishCompleter() - { - if (--completionsNeeded == 0) { - invokeCallback(false); - } - } - - /** called by initiator before any calls to startCompleter can be done. - */ - void begin() - { - ++completionsNeeded; - } - - /** called by initiator after all potential completers have called - * startCompleter(). - */ - void end(Callback& cb) - { - assert(completionsNeeded.get() > 0); // ensure begin() has been called! - // the following only "decrements" the count if it is 1. This means - // there are no more outstanding completers and we are done. - if (completionsNeeded.boolCompareAndSwap(1, 0)) { - // done! Complete immediately - cb.completed(true); - return; - } - - // the compare-and-swap did not succeed. This means there are - // outstanding completers pending (count > 1). Get a persistent - // Callback object to use when the last completer is done. - // Decrement after setting up the callback ensures that pending - // completers cannot touch the callback until it is ready. - callback = cb.clone(); - if (--completionsNeeded == 0) { - // note that a completer may have completed during the - // callback setup or decrement: - invokeCallback(true); - } - } - - /** may be called by Initiator to cancel the callback. Will wait for - * callback to complete if in progress. - */ - virtual void cancel() { - qpid::sys::Mutex::ScopedLock l(callbackLock); - while (inCallback) callbackLock.wait(); - callback = boost::intrusive_ptr<Callback>(); - active = false; - } -}; - -}} // qpid::broker:: -#endif /*!_AsyncCompletion_*/ diff --git a/cpp/src/qpid/broker/Bridge.cpp b/cpp/src/qpid/broker/Bridge.cpp index c709606c17..7fbbf4e2c4 100644 --- a/cpp/src/qpid/broker/Bridge.cpp +++ b/cpp/src/qpid/broker/Bridge.cpp @@ -164,12 +164,6 @@ void Bridge::destroy() listener(this); } -bool Bridge::isSessionReady() const -{ - SessionHandler& sessionHandler = conn->getChannel(id); - return sessionHandler.ready(); -} - void Bridge::setPersistenceId(uint64_t pId) const { persistenceId = pId; diff --git a/cpp/src/qpid/broker/Bridge.h b/cpp/src/qpid/broker/Bridge.h index 8b4559a871..a846254c57 100644 --- a/cpp/src/qpid/broker/Bridge.h +++ b/cpp/src/qpid/broker/Bridge.h @@ -59,8 +59,6 @@ public: void destroy(); bool isDurable() { return args.i_durable; } - bool isSessionReady() const; - management::ManagementObject* GetManagementObject() const; management::Manageable::status_t ManagementMethod(uint32_t methodId, management::Args& args, diff --git a/cpp/src/qpid/broker/Broker.cpp b/cpp/src/qpid/broker/Broker.cpp index ec3cf9d340..3c692fc368 100644 --- a/cpp/src/qpid/broker/Broker.cpp +++ b/cpp/src/qpid/broker/Broker.cpp @@ -20,7 +20,6 @@ */ #include "qpid/broker/Broker.h" -#include "qpid/broker/ConnectionState.h" #include "qpid/broker/DirectExchange.h" #include "qpid/broker/FanOutExchange.h" #include "qpid/broker/HeadersExchange.h" @@ -32,26 +31,12 @@ #include "qpid/broker/TopicExchange.h" #include "qpid/broker/Link.h" #include "qpid/broker/ExpiryPolicy.h" -#include "qpid/broker/QueueFlowLimit.h" -#include "qpid/broker/MessageGroupManager.h" #include "qmf/org/apache/qpid/broker/Package.h" -#include "qmf/org/apache/qpid/broker/ArgsBrokerCreate.h" -#include "qmf/org/apache/qpid/broker/ArgsBrokerDelete.h" -#include "qmf/org/apache/qpid/broker/ArgsBrokerQuery.h" #include "qmf/org/apache/qpid/broker/ArgsBrokerEcho.h" #include "qmf/org/apache/qpid/broker/ArgsBrokerGetLogLevel.h" #include "qmf/org/apache/qpid/broker/ArgsBrokerQueueMoveMessages.h" #include "qmf/org/apache/qpid/broker/ArgsBrokerSetLogLevel.h" -#include "qmf/org/apache/qpid/broker/ArgsBrokerSetTimestampConfig.h" -#include "qmf/org/apache/qpid/broker/ArgsBrokerGetTimestampConfig.h" -#include "qmf/org/apache/qpid/broker/EventExchangeDeclare.h" -#include "qmf/org/apache/qpid/broker/EventExchangeDelete.h" -#include "qmf/org/apache/qpid/broker/EventQueueDeclare.h" -#include "qmf/org/apache/qpid/broker/EventQueueDelete.h" -#include "qmf/org/apache/qpid/broker/EventBind.h" -#include "qmf/org/apache/qpid/broker/EventUnbind.h" -#include "qpid/amqp_0_10/Codecs.h" #include "qpid/management/ManagementDirectExchange.h" #include "qpid/management/ManagementTopicExchange.h" #include "qpid/log/Logger.h" @@ -59,9 +44,7 @@ #include "qpid/log/Statement.h" #include "qpid/log/posix/SinkOptions.h" #include "qpid/framing/AMQFrame.h" -#include "qpid/framing/FieldTable.h" #include "qpid/framing/ProtocolInitiation.h" -#include "qpid/framing/reply_exceptions.h" #include "qpid/framing/Uuid.h" #include "qpid/sys/ProtocolFactory.h" #include "qpid/sys/Poller.h" @@ -93,10 +76,7 @@ using qpid::management::ManagementAgent; using qpid::management::ManagementObject; using qpid::management::Manageable; using qpid::management::Args; -using qpid::management::getManagementExecutionContext; -using qpid::types::Variant; using std::string; -using std::make_pair; namespace _qmf = qmf::org::apache::qpid::broker; @@ -123,12 +103,7 @@ Broker::Options::Options(const std::string& name) : maxSessionRate(0), asyncQueueEvents(false), // Must be false in a cluster. qmf2Support(true), - qmf1Support(true), - queueFlowStopRatio(80), - queueFlowResumeRatio(70), - queueThresholdEventRatio(80), - defaultMsgGroup("qpid.no-group"), - timestampRcvMsgs(false) // set the 0.10 timestamp delivery property + qmf1Support(true) { int c = sys::SystemInfo::concurrency(); workerThreads=c+1; @@ -159,14 +134,9 @@ Broker::Options::Options(const std::string& name) : ("tcp-nodelay", optValue(tcpNoDelay), "Set TCP_NODELAY on TCP connections") ("require-encryption", optValue(requireEncrypted), "Only accept connections that are encrypted") ("known-hosts-url", optValue(knownHosts, "URL or 'none'"), "URL to send as 'known-hosts' to clients ('none' implies empty list)") - ("sasl-config", optValue(saslConfigPath, "DIR"), "gets sasl config info from nonstandard location") + ("sasl-config", optValue(saslConfigPath, "FILE"), "gets sasl config from nonstandard location") ("max-session-rate", optValue(maxSessionRate, "MESSAGES/S"), "Sets the maximum message rate per session (0=unlimited)") - ("async-queue-events", optValue(asyncQueueEvents, "yes|no"), "Set Queue Events async, used for services like replication") - ("default-flow-stop-threshold", optValue(queueFlowStopRatio, "PERCENT"), "Percent of queue's maximum capacity at which flow control is activated.") - ("default-flow-resume-threshold", optValue(queueFlowResumeRatio, "PERCENT"), "Percent of queue's maximum capacity at which flow control is de-activated.") - ("default-event-threshold-ratio", optValue(queueThresholdEventRatio, "%age of limit"), "The ratio of any specified queue limit at which an event will be raised") - ("default-message-group", optValue(defaultMsgGroup, "GROUP-IDENTIFER"), "Group identifier to assign to messages delivered to a message group queue that do not contain an identifier.") - ("enable-timestamp", optValue(timestampRcvMsgs, "yes|no"), "Add current time to each received message."); + ("async-queue-events", optValue(asyncQueueEvents, "yes|no"), "Set Queue Events async, used for services like replication"); } const std::string empty; @@ -196,10 +166,9 @@ Broker::Broker(const Broker::Options& conf) : conf.replayFlushLimit*1024, // convert kb to bytes. conf.replayHardLimit*1024), *this), - queueCleaner(queues, &timer), - queueEvents(poller,!conf.asyncQueueEvents), + queueCleaner(queues, timer), + queueEvents(poller,!conf.asyncQueueEvents), recovery(true), - inCluster(false), clusterUpdatee(false), expiryPolicy(new ExpiryPolicy), connectionCounter(conf.maxConnections), @@ -256,11 +225,8 @@ Broker::Broker(const Broker::Options& conf) : // Early-Initialize plugins Plugin::earlyInitAll(*this); - QueueFlowLimit::setDefaults(conf.queueLimit, conf.queueFlowStopRatio, conf.queueFlowResumeRatio); - MessageGroupManager::setDefaults(conf.defaultMsgGroup); - // If no plugin store module registered itself, set up the null store. - if (NullMessageStore::isNullStore(store.get())) + if (NullMessageStore::isNullStore(store.get())) setStore(); exchanges.declare(empty, DirectExchange::typeName); // Default exchange. @@ -305,11 +271,6 @@ Broker::Broker(const Broker::Options& conf) : else QPID_LOG(info, "Management not enabled"); - // this feature affects performance, so let's be sure that gets logged! - if (conf.timestampRcvMsgs) { - QPID_LOG(notice, "Receive message timestamping is ENABLED."); - } - /** * SASL setup, can fail and terminate startup */ @@ -384,14 +345,14 @@ void Broker::run() { Dispatcher d(poller); int numIOThreads = config.workerThreads; std::vector<Thread> t(numIOThreads-1); - + // Run n-1 io threads for (int i=0; i<numIOThreads-1; ++i) t[i] = Thread(d); - + // Run final thread d.run(); - + // Now wait for n-1 io threads to exit for (int i=0; i<numIOThreads-1; ++i) { t[i].join(); @@ -438,9 +399,9 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId, { case _qmf::Broker::METHOD_ECHO : QPID_LOG (debug, "Broker::echo(" - << dynamic_cast<_qmf::ArgsBrokerEcho&>(args).io_sequence - << ", " - << dynamic_cast<_qmf::ArgsBrokerEcho&>(args).io_body + << dynamic_cast<_qmf::ArgsBrokerEcho&>(args).io_sequence + << ", " + << dynamic_cast<_qmf::ArgsBrokerEcho&>(args).io_body << ")"); status = Manageable::STATUS_OK; break; @@ -448,9 +409,8 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId, _qmf::ArgsBrokerConnect& hp= dynamic_cast<_qmf::ArgsBrokerConnect&>(args); + QPID_LOG (debug, "Broker::connect()"); string transport = hp.i_transport.empty() ? TCP_TRANSPORT : hp.i_transport; - QPID_LOG (debug, "Broker::connect() " << hp.i_host << ":" << hp.i_port << "; transport=" << transport << - "; durable=" << (hp.i_durable?"T":"F") << "; authMech=\"" << hp.i_authMechanism << "\""); if (!getProtocolFactory(transport)) { QPID_LOG(error, "Transport '" << transport << "' not supported"); return Manageable::STATUS_NOT_IMPLEMENTED; @@ -467,9 +427,9 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId, _qmf::ArgsBrokerQueueMoveMessages& moveArgs= dynamic_cast<_qmf::ArgsBrokerQueueMoveMessages&>(args); QPID_LOG (debug, "Broker::queueMoveMessages()"); - if (queueMoveMessages(moveArgs.i_srcQueue, moveArgs.i_destQueue, moveArgs.i_qty, moveArgs.i_filter)) + if (queueMoveMessages(moveArgs.i_srcQueue, moveArgs.i_destQueue, moveArgs.i_qty)) status = Manageable::STATUS_OK; - else + else return Manageable::STATUS_PARAMETER_INVALID; break; } @@ -483,38 +443,6 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId, QPID_LOG (debug, "Broker::getLogLevel()"); status = Manageable::STATUS_OK; break; - case _qmf::Broker::METHOD_CREATE : - { - _qmf::ArgsBrokerCreate& a = dynamic_cast<_qmf::ArgsBrokerCreate&>(args); - createObject(a.i_type, a.i_name, a.i_properties, a.i_strict, getManagementExecutionContext()); - status = Manageable::STATUS_OK; - break; - } - case _qmf::Broker::METHOD_DELETE : - { - _qmf::ArgsBrokerDelete& a = dynamic_cast<_qmf::ArgsBrokerDelete&>(args); - deleteObject(a.i_type, a.i_name, a.i_options, getManagementExecutionContext()); - status = Manageable::STATUS_OK; - break; - } - case _qmf::Broker::METHOD_QUERY : - { - _qmf::ArgsBrokerQuery& a = dynamic_cast<_qmf::ArgsBrokerQuery&>(args); - status = queryObject(a.i_type, a.i_name, a.o_results, getManagementExecutionContext()); - break; - } - case _qmf::Broker::METHOD_GETTIMESTAMPCONFIG: - { - _qmf::ArgsBrokerGetTimestampConfig& a = dynamic_cast<_qmf::ArgsBrokerGetTimestampConfig&>(args); - status = getTimestampConfig(a.o_receive, getManagementExecutionContext()); - break; - } - case _qmf::Broker::METHOD_SETTIMESTAMPCONFIG: - { - _qmf::ArgsBrokerSetTimestampConfig& a = dynamic_cast<_qmf::ArgsBrokerSetTimestampConfig&>(args); - status = setTimestampConfig(a.i_receive, getManagementExecutionContext()); - break; - } default: QPID_LOG (debug, "Broker ManagementMethod not implemented: id=" << methodId << "]"); status = Manageable::STATUS_NOT_IMPLEMENTED; @@ -524,240 +452,6 @@ Manageable::status_t Broker::ManagementMethod (uint32_t methodId, return status; } -namespace -{ -const std::string TYPE_QUEUE("queue"); -const std::string TYPE_EXCHANGE("exchange"); -const std::string TYPE_TOPIC("topic"); -const std::string TYPE_BINDING("binding"); -const std::string DURABLE("durable"); -const std::string AUTO_DELETE("auto-delete"); -const std::string ALTERNATE_EXCHANGE("alternate-exchange"); -const std::string EXCHANGE_TYPE("exchange-type"); -const std::string QUEUE_NAME("queue"); -const std::string EXCHANGE_NAME("exchange"); - -const std::string ATTRIBUTE_TIMESTAMP_0_10("timestamp-0.10"); - -const std::string _TRUE("true"); -const std::string _FALSE("false"); -} - -struct InvalidBindingIdentifier : public qpid::Exception -{ - InvalidBindingIdentifier(const std::string& name) : qpid::Exception(name) {} - std::string getPrefix() const { return "invalid binding"; } -}; - -struct BindingIdentifier -{ - std::string exchange; - std::string queue; - std::string key; - - BindingIdentifier(const std::string& name) - { - std::vector<std::string> path; - split(path, name, "/"); - switch (path.size()) { - case 1: - queue = path[0]; - break; - case 2: - exchange = path[0]; - queue = path[1]; - break; - case 3: - exchange = path[0]; - queue = path[1]; - key = path[2]; - break; - default: - throw InvalidBindingIdentifier(name); - } - } -}; - -struct ObjectAlreadyExists : public qpid::Exception -{ - ObjectAlreadyExists(const std::string& name) : qpid::Exception(name) {} - std::string getPrefix() const { return "object already exists"; } -}; - -struct UnknownObjectType : public qpid::Exception -{ - UnknownObjectType(const std::string& type) : qpid::Exception(type) {} - std::string getPrefix() const { return "unknown object type"; } -}; - -void Broker::createObject(const std::string& type, const std::string& name, - const Variant::Map& properties, bool /*strict*/, const ConnectionState* context) -{ - std::string userId; - std::string connectionId; - if (context) { - userId = context->getUserId(); - connectionId = context->getUrl(); - } - //TODO: implement 'strict' option (check there are no unrecognised properties) - QPID_LOG (debug, "Broker::create(" << type << ", " << name << "," << properties << ")"); - if (type == TYPE_QUEUE) { - bool durable(false); - bool autodelete(false); - std::string alternateExchange; - Variant::Map extensions; - for (Variant::Map::const_iterator i = properties.begin(); i != properties.end(); ++i) { - // extract durable, auto-delete and alternate-exchange properties - if (i->first == DURABLE) durable = i->second; - else if (i->first == AUTO_DELETE) autodelete = i->second; - else if (i->first == ALTERNATE_EXCHANGE) alternateExchange = i->second.asString(); - //treat everything else as extension properties - else extensions[i->first] = i->second; - } - framing::FieldTable arguments; - amqp_0_10::translate(extensions, arguments); - - std::pair<boost::shared_ptr<Queue>, bool> result = - createQueue(name, durable, autodelete, 0, alternateExchange, arguments, userId, connectionId); - if (!result.second) { - throw ObjectAlreadyExists(name); - } - } else if (type == TYPE_EXCHANGE || type == TYPE_TOPIC) { - bool durable(false); - std::string exchangeType("topic"); - std::string alternateExchange; - Variant::Map extensions; - for (Variant::Map::const_iterator i = properties.begin(); i != properties.end(); ++i) { - // extract durable, auto-delete and alternate-exchange properties - if (i->first == DURABLE) durable = i->second; - else if (i->first == EXCHANGE_TYPE) exchangeType = i->second.asString(); - else if (i->first == ALTERNATE_EXCHANGE) alternateExchange = i->second.asString(); - //treat everything else as extension properties - else extensions[i->first] = i->second; - } - framing::FieldTable arguments; - amqp_0_10::translate(extensions, arguments); - - try { - std::pair<boost::shared_ptr<Exchange>, bool> result = - createExchange(name, exchangeType, durable, alternateExchange, arguments, userId, connectionId); - if (!result.second) { - throw ObjectAlreadyExists(name); - } - } catch (const UnknownExchangeTypeException&) { - throw Exception(QPID_MSG("Invalid exchange type: " << exchangeType)); - } - } else if (type == TYPE_BINDING) { - BindingIdentifier binding(name); - std::string exchangeType("topic"); - Variant::Map extensions; - for (Variant::Map::const_iterator i = properties.begin(); i != properties.end(); ++i) { - // extract durable, auto-delete and alternate-exchange properties - if (i->first == EXCHANGE_TYPE) exchangeType = i->second.asString(); - //treat everything else as extension properties - else extensions[i->first] = i->second; - } - framing::FieldTable arguments; - amqp_0_10::translate(extensions, arguments); - - bind(binding.queue, binding.exchange, binding.key, arguments, userId, connectionId); - } else { - throw UnknownObjectType(type); - } -} - -void Broker::deleteObject(const std::string& type, const std::string& name, - const Variant::Map& options, const ConnectionState* context) -{ - std::string userId; - std::string connectionId; - if (context) { - userId = context->getUserId(); - connectionId = context->getUrl(); - } - QPID_LOG (debug, "Broker::delete(" << type << ", " << name << "," << options << ")"); - if (type == TYPE_QUEUE) { - deleteQueue(name, userId, connectionId); - } else if (type == TYPE_EXCHANGE || type == TYPE_TOPIC) { - deleteExchange(name, userId, connectionId); - } else if (type == TYPE_BINDING) { - BindingIdentifier binding(name); - unbind(binding.queue, binding.exchange, binding.key, userId, connectionId); - } else { - throw UnknownObjectType(type); - } - -} - -Manageable::status_t Broker::queryObject(const std::string& type, - const std::string& name, - Variant::Map& results, - const ConnectionState* context) -{ - std::string userId; - std::string connectionId; - if (context) { - userId = context->getUserId(); - connectionId = context->getUrl(); - } - QPID_LOG (debug, "Broker::query(" << type << ", " << name << ")"); - - if (type == TYPE_QUEUE) - return queryQueue( name, userId, connectionId, results ); - - if (type == TYPE_EXCHANGE || - type == TYPE_TOPIC || - type == TYPE_BINDING) - return Manageable::STATUS_NOT_IMPLEMENTED; - - throw UnknownObjectType(type); -} - -Manageable::status_t Broker::queryQueue( const std::string& name, - const std::string& userId, - const std::string& /*connectionId*/, - Variant::Map& results ) -{ - (void) results; - if (acl) { - if (!acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_QUEUE, name, NULL) ) - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied queue query request from " << userId)); - } - - boost::shared_ptr<Queue> q(queues.find(name)); - if (!q) { - QPID_LOG(error, "Query failed: queue not found, name=" << name); - return Manageable::STATUS_UNKNOWN_OBJECT; - } - q->query( results ); - return Manageable::STATUS_OK;; -} - -Manageable::status_t Broker::getTimestampConfig(bool& receive, - const ConnectionState* context) -{ - std::string name; // none needed for broker - std::string userId = context->getUserId(); - if (acl && !acl->authorise(userId, acl::ACT_ACCESS, acl::OBJ_BROKER, name, NULL)) { - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied broker timestamp get request from " << userId)); - } - receive = config.timestampRcvMsgs; - return Manageable::STATUS_OK; -} - -Manageable::status_t Broker::setTimestampConfig(const bool receive, - const ConnectionState* context) -{ - std::string name; // none needed for broker - std::string userId = context->getUserId(); - if (acl && !acl->authorise(userId, acl::ACT_UPDATE, acl::OBJ_BROKER, name, NULL)) { - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied broker timestamp set request from " << userId)); - } - config.timestampRcvMsgs = receive; - QPID_LOG(notice, "Receive message timestamping is " << ((config.timestampRcvMsgs) ? "ENABLED." : "DISABLED.")); - return Manageable::STATUS_OK; -} - void Broker::setLogLevel(const std::string& level) { QPID_LOG(notice, "Changing log level to " << level); @@ -772,7 +466,7 @@ std::string Broker::getLogLevel() const std::vector<std::string>& selectors = qpid::log::Logger::instance().getOptions().selectors; for (std::vector<std::string>::const_iterator i = selectors.begin(); i != selectors.end(); ++i) { if (i != selectors.begin()) level += std::string(","); - level += *i; + level += *i; } return level; } @@ -805,7 +499,7 @@ void Broker::accept() { } void Broker::connect( - const std::string& host, const std::string& port, const std::string& transport, + const std::string& host, uint16_t port, const std::string& transport, boost::function2<void, int, std::string> failed, sys::ConnectionCodec::Factory* f) { @@ -821,14 +515,13 @@ void Broker::connect( { url.throwIfEmpty(); const Address& addr=url[0]; - connect(addr.host, boost::lexical_cast<std::string>(addr.port), addr.protocol, failed, f); + connect(addr.host, addr.port, addr.protocol, failed, f); } uint32_t Broker::queueMoveMessages( const std::string& srcQueue, const std::string& destQueue, - uint32_t qty, - const Variant::Map& filter) + uint32_t qty) { Queue::shared_ptr src_queue = queues.find(srcQueue); if (!src_queue) @@ -837,7 +530,7 @@ uint32_t Broker::queueMoveMessages( if (!dest_queue) return 0; - return src_queue->move(dest_queue, qty, &filter); + return src_queue->move(dest_queue, qty); } @@ -855,228 +548,9 @@ bool Broker::deferDeliveryImpl(const std::string& , void Broker::setClusterTimer(std::auto_ptr<sys::Timer> t) { clusterTimer = t; - queueCleaner.setTimer(clusterTimer.get()); - dtxManager.setTimer(*clusterTimer.get()); } const std::string Broker::TCP_TRANSPORT("tcp"); - -std::pair<boost::shared_ptr<Queue>, bool> Broker::createQueue( - const std::string& name, - bool durable, - bool autodelete, - const OwnershipToken* owner, - const std::string& alternateExchange, - const qpid::framing::FieldTable& arguments, - const std::string& userId, - const std::string& connectionId) -{ - if (acl) { - std::map<acl::Property, std::string> params; - params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange)); - params.insert(make_pair(acl::PROP_PASSIVE, _FALSE)); - params.insert(make_pair(acl::PROP_DURABLE, durable ? _TRUE : _FALSE)); - params.insert(make_pair(acl::PROP_EXCLUSIVE, owner ? _TRUE : _FALSE)); - params.insert(make_pair(acl::PROP_AUTODELETE, autodelete ? _TRUE : _FALSE)); - params.insert(make_pair(acl::PROP_POLICYTYPE, arguments.getAsString("qpid.policy_type"))); - params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.max_count")))); - params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.max_size")))); - - if (!acl->authorise(userId,acl::ACT_CREATE,acl::OBJ_QUEUE,name,¶ms) ) - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied queue create request from " << userId)); - } - - Exchange::shared_ptr alternate; - if (!alternateExchange.empty()) { - alternate = exchanges.get(alternateExchange); - if (!alternate) throw framing::NotFoundException(QPID_MSG("Alternate exchange does not exist: " << alternateExchange)); - } - - std::pair<Queue::shared_ptr, bool> result = queues.declare(name, durable, autodelete, owner, alternate, arguments); - if (result.second) { - //add default binding: - result.first->bind(exchanges.getDefault(), name); - - if (managementAgent.get()) { - //TODO: debatable whether we should raise an event here for - //create when this is a 'declare' event; ideally add a create - //event instead? - managementAgent->raiseEvent( - _qmf::EventQueueDeclare(connectionId, userId, name, - durable, owner, autodelete, - ManagementAgent::toMap(arguments), - "created")); - } - } - return result; -} - -void Broker::deleteQueue(const std::string& name, const std::string& userId, - const std::string& connectionId, QueueFunctor check) -{ - if (acl && !acl->authorise(userId,acl::ACT_DELETE,acl::OBJ_QUEUE,name,NULL)) { - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied queue delete request from " << userId)); - } - - Queue::shared_ptr queue = queues.find(name); - if (queue) { - if (check) check(queue); - queues.destroy(name); - queue->destroyed(); - } else { - throw framing::NotFoundException(QPID_MSG("Delete failed. No such queue: " << name)); - } - - if (managementAgent.get()) - managementAgent->raiseEvent(_qmf::EventQueueDelete(connectionId, userId, name)); - -} - -std::pair<Exchange::shared_ptr, bool> Broker::createExchange( - const std::string& name, - const std::string& type, - bool durable, - const std::string& alternateExchange, - const qpid::framing::FieldTable& arguments, - const std::string& userId, - const std::string& connectionId) -{ - if (acl) { - std::map<acl::Property, std::string> params; - params.insert(make_pair(acl::PROP_TYPE, type)); - params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange)); - params.insert(make_pair(acl::PROP_PASSIVE, _FALSE)); - params.insert(make_pair(acl::PROP_DURABLE, durable ? _TRUE : _FALSE)); - if (!acl->authorise(userId,acl::ACT_CREATE,acl::OBJ_EXCHANGE,name,¶ms) ) - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied exchange create request from " << userId)); - } - - Exchange::shared_ptr alternate; - if (!alternateExchange.empty()) { - alternate = exchanges.get(alternateExchange); - if (!alternate) throw framing::NotFoundException(QPID_MSG("Alternate exchange does not exist: " << alternateExchange)); - } - - std::pair<Exchange::shared_ptr, bool> result; - result = exchanges.declare(name, type, durable, arguments); - if (result.second) { - if (alternate) { - result.first->setAlternate(alternate); - alternate->incAlternateUsers(); - } - if (durable) { - store->create(*result.first, arguments); - } - if (managementAgent.get()) { - //TODO: debatable whether we should raise an event here for - //create when this is a 'declare' event; ideally add a create - //event instead? - managementAgent->raiseEvent(_qmf::EventExchangeDeclare(connectionId, - userId, - name, - type, - alternateExchange, - durable, - false, - ManagementAgent::toMap(arguments), - "created")); - } - } - return result; -} - -void Broker::deleteExchange(const std::string& name, const std::string& userId, - const std::string& connectionId) -{ - if (acl) { - if (!acl->authorise(userId,acl::ACT_DELETE,acl::OBJ_EXCHANGE,name,NULL) ) - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied exchange delete request from " << userId)); - } - - if (name.empty()) { - throw framing::InvalidArgumentException(QPID_MSG("Delete not allowed for default exchange")); - } - Exchange::shared_ptr exchange(exchanges.get(name)); - if (!exchange) throw framing::NotFoundException(QPID_MSG("Delete failed. No such exchange: " << name)); - if (exchange->inUseAsAlternate()) throw framing::NotAllowedException(QPID_MSG("Exchange in use as alternate-exchange.")); - if (exchange->isDurable()) store->destroy(*exchange); - if (exchange->getAlternate()) exchange->getAlternate()->decAlternateUsers(); - exchanges.destroy(name); - - if (managementAgent.get()) - managementAgent->raiseEvent(_qmf::EventExchangeDelete(connectionId, userId, name)); - -} - -void Broker::bind(const std::string& queueName, - const std::string& exchangeName, - const std::string& key, - const qpid::framing::FieldTable& arguments, - const std::string& userId, - const std::string& connectionId) -{ - if (acl) { - std::map<acl::Property, std::string> params; - params.insert(make_pair(acl::PROP_QUEUENAME, queueName)); - params.insert(make_pair(acl::PROP_ROUTINGKEY, key)); - - if (!acl->authorise(userId,acl::ACT_BIND,acl::OBJ_EXCHANGE,exchangeName,¶ms)) - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied exchange bind request from " << userId)); - } - if (exchangeName.empty()) { - throw framing::InvalidArgumentException(QPID_MSG("Bind not allowed for default exchange")); - } - - Queue::shared_ptr queue = queues.find(queueName); - Exchange::shared_ptr exchange = exchanges.get(exchangeName); - if (!queue) { - throw framing::NotFoundException(QPID_MSG("Bind failed. No such queue: " << queueName)); - } else if (!exchange) { - throw framing::NotFoundException(QPID_MSG("Bind failed. No such exchange: " << exchangeName)); - } else { - if (queue->bind(exchange, key, arguments)) { - if (managementAgent.get()) { - managementAgent->raiseEvent(_qmf::EventBind(connectionId, userId, exchangeName, - queueName, key, ManagementAgent::toMap(arguments))); - } - } - } -} - -void Broker::unbind(const std::string& queueName, - const std::string& exchangeName, - const std::string& key, - const std::string& userId, - const std::string& connectionId) -{ - if (acl) { - std::map<acl::Property, std::string> params; - params.insert(make_pair(acl::PROP_QUEUENAME, queueName)); - params.insert(make_pair(acl::PROP_ROUTINGKEY, key)); - if (!acl->authorise(userId,acl::ACT_UNBIND,acl::OBJ_EXCHANGE,exchangeName,¶ms) ) - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied exchange unbind request from " << userId)); - } - if (exchangeName.empty()) { - throw framing::InvalidArgumentException(QPID_MSG("Unbind not allowed for default exchange")); - } - Queue::shared_ptr queue = queues.find(queueName); - Exchange::shared_ptr exchange = exchanges.get(exchangeName); - if (!queue) { - throw framing::NotFoundException(QPID_MSG("Unbind failed. No such queue: " << queueName)); - } else if (!exchange) { - throw framing::NotFoundException(QPID_MSG("Unbind failed. No such exchange: " << exchangeName)); - } else { - if (exchange->unbind(queue, key, 0)) { - if (exchange->isDurable() && queue->isDurable()) { - store->unbind(*exchange, *queue, key, qpid::framing::FieldTable()); - } - if (managementAgent.get()) { - managementAgent->raiseEvent(_qmf::EventUnbind(connectionId, userId, exchangeName, queueName, key)); - } - } - } -} - }} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/Broker.h b/cpp/src/qpid/broker/Broker.h index b3b751be98..cd6f81dc70 100644 --- a/cpp/src/qpid/broker/Broker.h +++ b/cpp/src/qpid/broker/Broker.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -49,7 +49,6 @@ #include "qpid/framing/ProtocolInitiation.h" #include "qpid/sys/Runnable.h" #include "qpid/sys/Timer.h" -#include "qpid/types/Variant.h" #include "qpid/RefCounted.h" #include "qpid/broker/AclModule.h" #include "qpid/sys/Mutex.h" @@ -58,7 +57,7 @@ #include <string> #include <vector> -namespace qpid { +namespace qpid { namespace sys { class ProtocolFactory; @@ -69,7 +68,6 @@ struct Url; namespace broker { -class ConnectionState; class ExpiryPolicy; class Message; @@ -82,7 +80,7 @@ struct NoSuchTransportException : qpid::Exception }; /** - * A broker instance. + * A broker instance. */ class Broker : public sys::Runnable, public Plugin::Target, public management::Manageable, @@ -118,34 +116,29 @@ public: bool asyncQueueEvents; bool qmf2Support; bool qmf1Support; - uint queueFlowStopRatio; // producer flow control: on - uint queueFlowResumeRatio; // producer flow control: off - uint16_t queueThresholdEventRatio; - std::string defaultMsgGroup; - bool timestampRcvMsgs; private: std::string getHome(); }; - + class ConnectionCounter { int maxConnections; int connectionCount; sys::Mutex connectionCountLock; public: ConnectionCounter(int mc): maxConnections(mc),connectionCount(0) {}; - void inc_connectionCount() { - sys::ScopedLock<sys::Mutex> l(connectionCountLock); + void inc_connectionCount() { + sys::ScopedLock<sys::Mutex> l(connectionCountLock); connectionCount++; - } - void dec_connectionCount() { - sys::ScopedLock<sys::Mutex> l(connectionCountLock); + } + void dec_connectionCount() { + sys::ScopedLock<sys::Mutex> l(connectionCountLock); connectionCount--; } bool allowConnection() { - sys::ScopedLock<sys::Mutex> l(connectionCountLock); + sys::ScopedLock<sys::Mutex> l(connectionCountLock); return (maxConnections <= connectionCount); - } + } }; private: @@ -155,20 +148,7 @@ public: void setStore (); void setLogLevel(const std::string& level); std::string getLogLevel(); - void createObject(const std::string& type, const std::string& name, - const qpid::types::Variant::Map& properties, bool strict, const ConnectionState* context); - void deleteObject(const std::string& type, const std::string& name, - const qpid::types::Variant::Map& options, const ConnectionState* context); - Manageable::status_t queryObject(const std::string& type, const std::string& name, - qpid::types::Variant::Map& results, const ConnectionState* context); - Manageable::status_t queryQueue( const std::string& name, - const std::string& userId, - const std::string& connectionId, - qpid::types::Variant::Map& results); - Manageable::status_t getTimestampConfig(bool& receive, - const ConnectionState* context); - Manageable::status_t setTimestampConfig(const bool receive, - const ConnectionState* context); + boost::shared_ptr<sys::Poller> poller; sys::Timer timer; std::auto_ptr<sys::Timer> clusterTimer; @@ -196,10 +176,10 @@ public: const boost::intrusive_ptr<Message>& msg); std::string federationTag; bool recovery; - bool inCluster, clusterUpdatee; + bool clusterUpdatee; boost::intrusive_ptr<ExpiryPolicy> expiryPolicy; ConnectionCounter connectionCounter; - + public: virtual ~Broker(); @@ -255,7 +235,7 @@ public: QPID_BROKER_EXTERN void accept(); /** Create a connection to another broker. */ - void connect(const std::string& host, const std::string& port, + void connect(const std::string& host, uint16_t port, const std::string& transport, boost::function2<void, int, std::string> failed, sys::ConnectionCodec::Factory* =0); @@ -267,10 +247,9 @@ public: /** Move messages from one queue to another. A zero quantity means to move all messages */ - uint32_t queueMoveMessages( const std::string& srcQueue, + uint32_t queueMoveMessages( const std::string& srcQueue, const std::string& destQueue, - uint32_t qty, - const qpid::types::Variant::Map& filter); + uint32_t qty); boost::shared_ptr<sys::ProtocolFactory> getProtocolFactory(const std::string& name = TCP_TRANSPORT) const; @@ -294,20 +273,11 @@ public: void setRecovery(bool set) { recovery = set; } bool getRecovery() const { return recovery; } - /** True of this broker is part of a cluster. - * Only valid after early initialization of plugins is complete. - */ - bool isInCluster() const { return inCluster; } - void setInCluster(bool set) { inCluster = set; } - - /** True if this broker is joining a cluster and in the process of - * receiving a state update. - */ - bool isClusterUpdatee() const { return clusterUpdatee; } void setClusterUpdatee(bool set) { clusterUpdatee = set; } + bool isClusterUpdatee() const { return clusterUpdatee; } management::ManagementAgent* getManagementAgent() { return managementAgent.get(); } - + ConnectionCounter& getConnectionCounter() {return connectionCounter;} /** @@ -320,43 +290,6 @@ public: const boost::intrusive_ptr<Message>& msg)> deferDelivery; bool isAuthenticating ( ) { return config.auth; } - bool isTimestamping() { return config.timestampRcvMsgs; } - - typedef boost::function1<void, boost::shared_ptr<Queue> > QueueFunctor; - - std::pair<boost::shared_ptr<Queue>, bool> createQueue( - const std::string& name, - bool durable, - bool autodelete, - const OwnershipToken* owner, - const std::string& alternateExchange, - const qpid::framing::FieldTable& arguments, - const std::string& userId, - const std::string& connectionId); - void deleteQueue(const std::string& name, - const std::string& userId, - const std::string& connectionId, - QueueFunctor check = QueueFunctor()); - std::pair<Exchange::shared_ptr, bool> createExchange( - const std::string& name, - const std::string& type, - bool durable, - const std::string& alternateExchange, - const qpid::framing::FieldTable& args, - const std::string& userId, const std::string& connectionId); - void deleteExchange(const std::string& name, const std::string& userId, - const std::string& connectionId); - void bind(const std::string& queue, - const std::string& exchange, - const std::string& key, - const qpid::framing::FieldTable& arguments, - const std::string& userId, - const std::string& connectionId); - void unbind(const std::string& queue, - const std::string& exchange, - const std::string& key, - const std::string& userId, - const std::string& connectionId); }; }} diff --git a/cpp/src/qpid/broker/BrokerImportExport.h b/cpp/src/qpid/broker/BrokerImportExport.h index ee05788063..4edf8c9844 100644 --- a/cpp/src/qpid/broker/BrokerImportExport.h +++ b/cpp/src/qpid/broker/BrokerImportExport.h @@ -20,23 +20,14 @@ * under the License. */ -#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) -# if defined(BROKER_EXPORT) || defined (qpidbroker_EXPORTS) -# define QPID_BROKER_EXTERN __declspec(dllexport) -# else -# define QPID_BROKER_EXTERN __declspec(dllimport) -# endif -# ifdef _MSC_VER -# define QPID_BROKER_CLASS_EXTERN -# define QPID_BROKER_INLINE_EXTERN QPID_BROKER_EXTERN -# else -# define QPID_BROKER_CLASS_EXTERN QPID_BROKER_EXTERN -# define QPID_BROKER_INLINE_EXTERN -# endif +#if defined(WIN32) && !defined(QPID_BROKER_STATIC) +#if defined(BROKER_EXPORT) || defined (qpidbroker_EXPORTS) +#define QPID_BROKER_EXTERN __declspec(dllexport) #else -# define QPID_BROKER_EXTERN -# define QPID_BROKER_CLASS_EXTERN -# define QPID_BROKER_INLINE_EXTERN +#define QPID_BROKER_EXTERN __declspec(dllimport) +#endif +#else +#define QPID_BROKER_EXTERN #endif #endif diff --git a/cpp/src/qpid/broker/Connection.cpp b/cpp/src/qpid/broker/Connection.cpp index 0b3059d26c..460799280e 100644 --- a/cpp/src/qpid/broker/Connection.cpp +++ b/cpp/src/qpid/broker/Connection.cpp @@ -156,7 +156,16 @@ Connection::~Connection() void Connection::received(framing::AMQFrame& frame) { // Received frame on connection so delay timeout restartTimeout(); - adapter.handle(frame); + + if (frame.getChannel() == 0 && frame.getMethod()) { + adapter.handle(frame); + } else { + if (adapter.isOpen()) + getChannel(frame.getChannel()).in(frame); + else + close(connection::CLOSE_CODE_FRAMING_ERROR, "Connection not yet open, invalid frame received."); + } + if (isLink) //i.e. we are acting as the client to another broker recordFromServer(frame); else @@ -269,7 +278,8 @@ void Connection::setUserId(const string& userId) ConnectionState::setUserId(userId); // In a cluster, the cluster code will raise the connect event // when the connection is replicated to the cluster. - if (!broker.isInCluster()) raiseConnectEvent(); + if (!sys::isCluster()) + raiseConnectEvent(); } void Connection::raiseConnectEvent() { @@ -279,11 +289,11 @@ void Connection::raiseConnectEvent() { } } -void Connection::setUserProxyAuth(bool b) +void Connection::setFederationLink(bool b) { - ConnectionState::setUserProxyAuth(b); + ConnectionState::setFederationLink(b); if (mgmtObject != 0) - mgmtObject->set_userProxyAuth(b); + mgmtObject->set_federationLink(b); } void Connection::close(connection::CloseCode code, const string& text) @@ -322,30 +332,31 @@ void Connection::closed(){ // Physically closed, suspend open sessions. try { while (!channels.empty()) ptr_map_ptr(channels.begin())->handleDetach(); + while (!exclusiveQueues.empty()) { + boost::shared_ptr<Queue> q(exclusiveQueues.front()); + q->releaseExclusiveOwnership(); + if (q->canAutoDelete()) { + Queue::tryAutoDelete(broker, q); + } + exclusiveQueues.erase(exclusiveQueues.begin()); + } } catch(std::exception& e) { QPID_LOG(error, QPID_MSG("While closing connection: " << e.what())); assert(0); } } -void Connection::doIoCallbacks() { - { - ScopedLock<Mutex> l(ioCallbackLock); - // Although IO callbacks execute in the connection thread context, they are - // not cluster safe because they are queued for execution in non-IO threads. - ClusterUnsafeScope cus; - while (!ioCallbacks.empty()) { - boost::function0<void> cb = ioCallbacks.front(); - ioCallbacks.pop(); - ScopedUnlock<Mutex> ul(ioCallbackLock); - cb(); // Lend the IO thread for management processing - } - } -} - bool Connection::doOutput() { try { - doIoCallbacks(); + { + ScopedLock<Mutex> l(ioCallbackLock); + while (!ioCallbacks.empty()) { + boost::function0<void> cb = ioCallbacks.front(); + ioCallbacks.pop(); + ScopedUnlock<Mutex> ul(ioCallbackLock); + cb(); // Lend the IO thread for management processing + } + } if (mgmtClosing) { closed(); close(connection::CLOSE_CODE_CONNECTION_FORCED, "Closed by Management Request"); @@ -465,8 +476,8 @@ void Connection::OutboundFrameTracker::abort() { next->abort(); } void Connection::OutboundFrameTracker::activateOutput() { next->activateOutput(); } void Connection::OutboundFrameTracker::giveReadCredit(int32_t credit) { next->giveReadCredit(credit); } void Connection::OutboundFrameTracker::send(framing::AMQFrame& f) -{ - next->send(f); +{ + next->send(f); con.sent(f); } void Connection::OutboundFrameTracker::wrap(sys::ConnectionOutputHandlerPtr& p) diff --git a/cpp/src/qpid/broker/Connection.h b/cpp/src/qpid/broker/Connection.h index 3522d70b35..b751848d73 100644 --- a/cpp/src/qpid/broker/Connection.h +++ b/cpp/src/qpid/broker/Connection.h @@ -125,7 +125,7 @@ class Connection : public sys::ConnectionInputHandler, const std::string& getUserId() const { return ConnectionState::getUserId(); } const std::string& getMgmtId() const { return mgmtId; } management::ManagementAgent* getAgent() const { return agent; } - void setUserProxyAuth(bool b); + void setFederationLink(bool b); /** Connection does not delete the listener. 0 resets. */ void setErrorListener(ErrorListener* l) { errorListener=l; } ErrorListener* getErrorListener() { return errorListener; } @@ -153,16 +153,13 @@ class Connection : public sys::ConnectionInputHandler, void addManagementObject(); const qpid::sys::SecuritySettings& getExternalSecuritySettings() const - { + { return securitySettings; } /** @return true if the initial connection negotiation is complete. */ bool isOpen(); - // Used by cluster during catch-up, see cluster::OutputInterceptor - void doIoCallbacks(); - private: typedef boost::ptr_map<framing::ChannelId, SessionHandler> ChannelMap; typedef std::vector<boost::shared_ptr<Queue> >::iterator queue_iterator; @@ -204,7 +201,7 @@ class Connection : public sys::ConnectionInputHandler, sys::ConnectionOutputHandler* next; }; OutboundFrameTracker outboundTracker; - + void sent(const framing::AMQFrame& f); public: diff --git a/cpp/src/qpid/broker/ConnectionHandler.cpp b/cpp/src/qpid/broker/ConnectionHandler.cpp index 7cd91ae539..3f97e5b9de 100644 --- a/cpp/src/qpid/broker/ConnectionHandler.cpp +++ b/cpp/src/qpid/broker/ConnectionHandler.cpp @@ -26,7 +26,6 @@ #include "qpid/broker/SecureConnection.h" #include "qpid/Url.h" #include "qpid/framing/AllInvoker.h" -#include "qpid/framing/ConnectionStartOkBody.h" #include "qpid/framing/enum.h" #include "qpid/log/Statement.h" #include "qpid/sys/SecurityLayer.h" @@ -64,31 +63,13 @@ void ConnectionHandler::heartbeat() handler->proxy.heartbeat(); } -bool ConnectionHandler::handle(const framing::AMQMethodBody& method) -{ - //Need special handling for start-ok, in order to distinguish - //between null and empty response - if (method.isA<ConnectionStartOkBody>()) { - handler->startOk(dynamic_cast<const ConnectionStartOkBody&>(method)); - return true; - } else { - return invoke(static_cast<AMQP_AllOperations::ConnectionHandler&>(*handler), method); - } -} - void ConnectionHandler::handle(framing::AMQFrame& frame) { AMQMethodBody* method=frame.getBody()->getMethod(); Connection::ErrorListener* errorListener = handler->connection.getErrorListener(); try{ - if (method && handle(*method)) { - // This is a connection control frame, nothing more to do. - } else if (isOpen()) { + if (!invoke(static_cast<AMQP_AllOperations::ConnectionHandler&>(*handler.get()), *method)) { handler->connection.getChannel(frame.getChannel()).in(frame); - } else { - handler->proxy.close( - connection::CLOSE_CODE_FRAMING_ERROR, - "Connection not yet open, invalid frame received."); } }catch(ConnectionException& e){ if (errorListener) errorListener->connectionError(e.what()); @@ -108,10 +89,13 @@ ConnectionHandler::ConnectionHandler(Connection& connection, bool isClient, bool ConnectionHandler::Handler::Handler(Connection& c, bool isClient, bool isShadow) : proxy(c.getOutput()), - connection(c), serverMode(!isClient), secured(0), + connection(c), serverMode(!isClient), acl(0), secured(0), isOpen(false) { if (serverMode) { + + acl = connection.getBroker().getAcl(); + FieldTable properties; Array mechanisms(0x95); @@ -134,20 +118,13 @@ ConnectionHandler::Handler::Handler(Connection& c, bool isClient, bool isShadow) ConnectionHandler::Handler::~Handler() {} -void ConnectionHandler::Handler::startOk(const framing::FieldTable& /*clientProperties*/, - const string& /*mechanism*/, - const string& /*response*/, +void ConnectionHandler::Handler::startOk(const framing::FieldTable& clientProperties, + const string& mechanism, + const string& response, const string& /*locale*/) { - //Need special handling for start-ok, in order to distinguish - //between null and empty response -> should never use this method - assert(false); -} - -void ConnectionHandler::Handler::startOk(const ConnectionStartOkBody& body) -{ try { - authenticator->start(body.getMechanism(), body.hasResponse() ? &body.getResponse() : 0); + authenticator->start(mechanism, response); } catch (std::exception& /*e*/) { management::ManagementAgent* agent = connection.getAgent(); if (agent) { @@ -159,14 +136,9 @@ void ConnectionHandler::Handler::startOk(const ConnectionStartOkBody& body) } throw; } - const framing::FieldTable& clientProperties = body.getClientProperties(); connection.setFederationLink(clientProperties.get(QPID_FED_LINK)); - if (clientProperties.isSet(QPID_FED_TAG)) { - connection.setFederationPeerTag(clientProperties.getAsString(QPID_FED_TAG)); - } + connection.setFederationPeerTag(clientProperties.getAsString(QPID_FED_TAG)); if (connection.isFederationLink()) { - AclModule* acl = connection.getBroker().getAcl(); - FieldTable properties; if (acl && !acl->authorise(connection.getUserId(),acl::ACT_CREATE,acl::OBJ_LINK,"")){ proxy.close(framing::connection::CLOSE_CODE_CONNECTION_FORCED,"ACL denied creating a federation link"); return; @@ -211,7 +183,7 @@ void ConnectionHandler::Handler::secureOk(const string& response) void ConnectionHandler::Handler::tuneOk(uint16_t /*channelmax*/, uint16_t framemax, uint16_t heartbeat) { - if (framemax) connection.setFrameMax(framemax); + connection.setFrameMax(framemax); connection.setHeartbeatInterval(heartbeat); } @@ -284,6 +256,7 @@ void ConnectionHandler::Handler::start(const FieldTable& serverProperties, false ); // disallow interaction } std::string supportedMechanismsList; + bool requestedMechanismIsSupported = false; Array::const_iterator i; /* @@ -296,9 +269,11 @@ void ConnectionHandler::Handler::start(const FieldTable& serverProperties, if (i != supportedMechanisms.begin()) supportedMechanismsList += SPACE; supportedMechanismsList += (*i)->get<std::string>(); + requestedMechanismIsSupported = true; } } else { + requestedMechanismIsSupported = false; /* The caller has requested a mechanism. If it's available, make sure it ends up at the head of the list. @@ -307,6 +282,7 @@ void ConnectionHandler::Handler::start(const FieldTable& serverProperties, string currentMechanism = (*i)->get<std::string>(); if ( requestedMechanism == currentMechanism ) { + requestedMechanismIsSupported = true; supportedMechanismsList = currentMechanism + SPACE + supportedMechanismsList; } else { if (i != supportedMechanisms.begin()) @@ -316,9 +292,7 @@ void ConnectionHandler::Handler::start(const FieldTable& serverProperties, } } - if (serverProperties.isSet(QPID_FED_TAG)) { - connection.setFederationPeerTag(serverProperties.getAsString(QPID_FED_TAG)); - } + connection.setFederationPeerTag(serverProperties.getAsString(QPID_FED_TAG)); FieldTable ft; ft.setInt(QPID_FED_LINK,1); @@ -327,21 +301,11 @@ void ConnectionHandler::Handler::start(const FieldTable& serverProperties, string response; if (sasl.get()) { const qpid::sys::SecuritySettings& ss = connection.getExternalSecuritySettings(); - if (sasl->start ( requestedMechanism.empty() - ? supportedMechanismsList - : requestedMechanism, - response, - & ss )) { - proxy.startOk ( ft, sasl->getMechanism(), response, en_US ); - } else { - //response was null - ConnectionStartOkBody body; - body.setClientProperties(ft); - body.setMechanism(sasl->getMechanism()); - //Don't set response, as none was given - body.setLocale(en_US); - proxy.send(body); - } + response = sasl->start ( requestedMechanism.empty() + ? supportedMechanismsList + : requestedMechanism, + & ss ); + proxy.startOk ( ft, sasl->getMechanism(), response, en_US ); } else { response = ((char)0) + username + ((char)0) + password; diff --git a/cpp/src/qpid/broker/ConnectionHandler.h b/cpp/src/qpid/broker/ConnectionHandler.h index 05c5f00c57..b32167669e 100644 --- a/cpp/src/qpid/broker/ConnectionHandler.h +++ b/cpp/src/qpid/broker/ConnectionHandler.h @@ -26,10 +26,8 @@ #include "qpid/broker/SaslAuthenticator.h" #include "qpid/framing/amqp_types.h" #include "qpid/framing/AMQFrame.h" -#include "qpid/framing/AMQMethodBody.h" #include "qpid/framing/AMQP_AllOperations.h" #include "qpid/framing/AMQP_AllProxy.h" -#include "qpid/framing/ConnectionStartOkBody.h" #include "qpid/framing/enum.h" #include "qpid/framing/FrameHandler.h" #include "qpid/framing/ProtocolInitiation.h" @@ -59,12 +57,12 @@ class ConnectionHandler : public framing::FrameHandler Connection& connection; bool serverMode; std::auto_ptr<SaslAuthenticator> authenticator; + AclModule* acl; SecureConnection* secured; bool isOpen; Handler(Connection& connection, bool isClient, bool isShadow=false); ~Handler(); - void startOk(const qpid::framing::ConnectionStartOkBody& body); void startOk(const qpid::framing::FieldTable& clientProperties, const std::string& mechanism, const std::string& response, const std::string& locale); @@ -98,7 +96,7 @@ class ConnectionHandler : public framing::FrameHandler }; std::auto_ptr<Handler> handler; - bool handle(const qpid::framing::AMQMethodBody& method); + public: ConnectionHandler(Connection& connection, bool isClient, bool isShadow=false ); void close(framing::connection::CloseCode code, const std::string& text); diff --git a/cpp/src/qpid/broker/ConnectionState.h b/cpp/src/qpid/broker/ConnectionState.h index fdd3c4ddc0..774c37408d 100644 --- a/cpp/src/qpid/broker/ConnectionState.h +++ b/cpp/src/qpid/broker/ConnectionState.h @@ -46,7 +46,6 @@ class ConnectionState : public ConnectionToken, public management::Manageable framemax(65535), heartbeat(0), heartbeatmax(120), - userProxyAuth(false), // Can proxy msgs with non-matching auth ids when true (used by federation links & clustering) federationLink(true), clientSupportsThrottling(false), clusterOrderOut(0) @@ -68,10 +67,8 @@ class ConnectionState : public ConnectionToken, public management::Manageable void setUrl(const std::string& _url) { url = _url; } const std::string& getUrl() const { return url; } - void setUserProxyAuth(const bool b) { userProxyAuth = b; } - bool isUserProxyAuth() const { return userProxyAuth || federationPeerTag.size() > 0; } // links can proxy msgs with non-matching auth ids - void setFederationLink(bool b) { federationLink = b; } // deprecated - use setFederationPeerTag() instead - bool isFederationLink() const { return federationPeerTag.size() > 0; } + void setFederationLink(bool b) { federationLink = b; } + bool isFederationLink() const { return federationLink; } void setFederationPeerTag(const std::string& tag) { federationPeerTag = std::string(tag); } const std::string& getFederationPeerTag() const { return federationPeerTag; } std::vector<Url>& getKnownHosts() { return knownHosts; } @@ -82,6 +79,7 @@ class ConnectionState : public ConnectionToken, public management::Manageable Broker& getBroker() { return broker; } Broker& broker; + std::vector<boost::shared_ptr<Queue> > exclusiveQueues; //contained output tasks sys::AggregateOutput outputTasks; @@ -108,7 +106,6 @@ class ConnectionState : public ConnectionToken, public management::Manageable uint16_t heartbeatmax; std::string userId; std::string url; - bool userProxyAuth; bool federationLink; std::string federationPeerTag; std::vector<Url> knownHosts; diff --git a/cpp/src/qpid/broker/Consumer.h b/cpp/src/qpid/broker/Consumer.h index 2af9b0c121..b96443fa7c 100644 --- a/cpp/src/qpid/broker/Consumer.h +++ b/cpp/src/qpid/broker/Consumer.h @@ -29,33 +29,22 @@ namespace qpid { namespace broker { class Queue; -class QueueListeners; class Consumer { const bool acquires; - // inListeners allows QueueListeners to efficiently track if this instance is registered - // for notifications without having to search its containers - bool inListeners; - // the name is generated by broker and is unique within broker scope. It is not - // provided or known by the remote Consumer. - const std::string name; - public: - typedef boost::shared_ptr<Consumer> shared_ptr; - + public: + typedef boost::shared_ptr<Consumer> shared_ptr; + framing::SequenceNumber position; - - Consumer(const std::string& _name, bool preAcquires = true) - : acquires(preAcquires), inListeners(false), name(_name), position(0) {} + + Consumer(bool preAcquires = true) : acquires(preAcquires) {} bool preAcquires() const { return acquires; } - const std::string& getName() const { return name; } - virtual bool deliver(QueuedMessage& msg) = 0; virtual void notify() = 0; virtual bool filter(boost::intrusive_ptr<Message>) { return true; } virtual bool accept(boost::intrusive_ptr<Message>) { return true; } virtual OwnershipToken* getSession() = 0; virtual ~Consumer(){} - friend class QueueListeners; }; }} diff --git a/cpp/src/qpid/broker/Daemon.cpp b/cpp/src/qpid/broker/Daemon.cpp index c36538beb7..b30e5f18cb 100644 --- a/cpp/src/qpid/broker/Daemon.cpp +++ b/cpp/src/qpid/broker/Daemon.cpp @@ -93,10 +93,11 @@ void Daemon::fork() catch (const exception& e) { QPID_LOG(critical, "Unexpected error: " << e.what()); uint16_t port = 0; - (void) write(pipeFds[1], &port, sizeof(uint16_t)); + int unused_ret; //Supress warning about ignoring return value. + unused_ret = write(pipeFds[1], &port, sizeof(uint16_t)); std::string pipeFailureMessage = e.what(); - (void) write ( pipeFds[1], + unused_ret = write ( pipeFds[1], pipeFailureMessage.c_str(), strlen(pipeFailureMessage.c_str()) ); diff --git a/cpp/src/qpid/broker/DeliverableMessage.h b/cpp/src/qpid/broker/DeliverableMessage.h index c8d21001eb..ce613e7b6e 100644 --- a/cpp/src/qpid/broker/DeliverableMessage.h +++ b/cpp/src/qpid/broker/DeliverableMessage.h @@ -29,7 +29,7 @@ namespace qpid { namespace broker { - class QPID_BROKER_CLASS_EXTERN DeliverableMessage : public Deliverable{ + class DeliverableMessage : public Deliverable{ boost::intrusive_ptr<Message> msg; public: QPID_BROKER_EXTERN DeliverableMessage(const boost::intrusive_ptr<Message>& msg); diff --git a/cpp/src/qpid/broker/DeliveryRecord.cpp b/cpp/src/qpid/broker/DeliveryRecord.cpp index 0b8fe95d5e..9443eb6ea5 100644 --- a/cpp/src/qpid/broker/DeliveryRecord.cpp +++ b/cpp/src/qpid/broker/DeliveryRecord.cpp @@ -75,7 +75,7 @@ void DeliveryRecord::deliver(framing::FrameHandler& h, DeliveryId deliveryId, ui { id = deliveryId; if (msg.payload->getRedelivered()){ - msg.payload->setRedelivered(); + msg.payload->getProperties<framing::DeliveryProperties>()->setRedelivered(true); } msg.payload->adjustTtl(); @@ -131,20 +131,18 @@ void DeliveryRecord::committed() const{ void DeliveryRecord::reject() { - if (acquired && !ended) { - Exchange::shared_ptr alternate = queue->getAlternateExchange(); - if (alternate) { - DeliverableMessage delivery(msg.payload); - alternate->routeWithAlternate(delivery); - QPID_LOG(info, "Routed rejected message from " << queue->getName() << " to " - << alternate->getName()); - } else { - //just drop it - QPID_LOG(info, "Dropping rejected message from " << queue->getName()); - } - dequeue(); - setEnded(); + Exchange::shared_ptr alternate = queue->getAlternateExchange(); + if (alternate) { + DeliverableMessage delivery(msg.payload); + alternate->route(delivery, msg.payload->getRoutingKey(), msg.payload->getApplicationHeaders()); + QPID_LOG(info, "Routed rejected message from " << queue->getName() << " to " + << alternate->getName()); + } else { + //just drop it + QPID_LOG(info, "Dropping rejected message from " << queue->getName()); } + + dequeue(); } uint32_t DeliveryRecord::getCredit() const @@ -153,7 +151,7 @@ uint32_t DeliveryRecord::getCredit() const } void DeliveryRecord::acquire(DeliveryIds& results) { - if (queue->acquire(msg, tag)) { + if (queue->acquire(msg)) { acquired = true; results.push_back(id); if (!acceptExpected) { diff --git a/cpp/src/qpid/broker/DeliveryRecord.h b/cpp/src/qpid/broker/DeliveryRecord.h index 5a331357be..d388ba94be 100644 --- a/cpp/src/qpid/broker/DeliveryRecord.h +++ b/cpp/src/qpid/broker/DeliveryRecord.h @@ -46,7 +46,7 @@ class DeliveryRecord { QueuedMessage msg; mutable boost::shared_ptr<Queue> queue; - std::string tag; // name of consumer + std::string tag; DeliveryId id; bool acquired : 1; bool acceptExpected : 1; @@ -90,7 +90,7 @@ class DeliveryRecord bool isAcquired() const { return acquired; } bool isComplete() const { return completed; } - bool isRedundant() const { return ended && (!windowing || completed || cancelled); } + bool isRedundant() const { return ended && (!windowing || completed); } bool isCancelled() const { return cancelled; } bool isAccepted() const { return !acceptExpected; } bool isEnded() const { return ended; } diff --git a/cpp/src/qpid/broker/DirectExchange.cpp b/cpp/src/qpid/broker/DirectExchange.cpp index 5591539853..5b8104c77c 100644 --- a/cpp/src/qpid/broker/DirectExchange.cpp +++ b/cpp/src/qpid/broker/DirectExchange.cpp @@ -94,7 +94,7 @@ bool DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, con propagate = bk.fedBinding.delOrigin(queue->getName(), fedOrigin); if (bk.fedBinding.countFedBindings(queue->getName()) == 0) - unbind(queue, routingKey, args); + unbind(queue, routingKey, 0); } else if (fedOp == fedOpReorigin) { /** gather up all the keys that need rebinding in a local vector @@ -124,24 +124,20 @@ bool DirectExchange::bind(Queue::shared_ptr queue, const string& routingKey, con return true; } -bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args) +bool DirectExchange::unbind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* /*args*/) { - string fedOrigin(args ? args->getAsString(qpidFedOrigin) : ""); bool propagate = false; - QPID_LOG(debug, "Unbinding key [" << routingKey << "] from queue " << queue->getName() - << " on exchange " << getName() << " origin=" << fedOrigin << ")" ); + QPID_LOG(debug, "Unbind key [" << routingKey << "] from queue " << queue->getName()); + { Mutex::ScopedLock l(lock); BoundKey& bk = bindings[routingKey]; if (bk.queues.remove_if(MatchQueue(queue))) { - propagate = bk.fedBinding.delOrigin(queue->getName(), fedOrigin); + propagate = bk.fedBinding.delOrigin(); if (mgmtExchange != 0) { mgmtExchange->dec_bindingCount(); } - if (bk.queues.empty()) { - bindings.erase(routingKey); - } } else { return false; } diff --git a/cpp/src/qpid/broker/DtxAck.cpp b/cpp/src/qpid/broker/DtxAck.cpp index c558681d62..bca3f90bbe 100644 --- a/cpp/src/qpid/broker/DtxAck.cpp +++ b/cpp/src/qpid/broker/DtxAck.cpp @@ -32,10 +32,6 @@ DtxAck::DtxAck(const qpid::framing::SequenceSet& acked, DeliveryRecords& unacked not1(bind2nd(mem_fun_ref(&DeliveryRecord::coveredBy), &acked))); } -DtxAck::DtxAck(DeliveryRecords& unacked) { - pending = unacked; -} - bool DtxAck::prepare(TransactionContext* ctxt) throw() { try{ diff --git a/cpp/src/qpid/broker/DtxAck.h b/cpp/src/qpid/broker/DtxAck.h index 16c3ff8ba0..166147e58d 100644 --- a/cpp/src/qpid/broker/DtxAck.h +++ b/cpp/src/qpid/broker/DtxAck.h @@ -1,6 +1,3 @@ -#ifndef QPID_BROKER_DTXACK_H -#define QPID_BROKER_DTXACK_H - /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -21,6 +18,9 @@ * under the License. * */ +#ifndef _DtxAck_ +#define _DtxAck_ + #include <algorithm> #include <functional> #include <list> @@ -29,21 +29,20 @@ #include "qpid/broker/TxOp.h" namespace qpid { -namespace broker { -class DtxAck : public TxOp{ - DeliveryRecords pending; + namespace broker { + class DtxAck : public TxOp{ + DeliveryRecords pending; - public: - DtxAck(const framing::SequenceSet& acked, DeliveryRecords& unacked); - DtxAck(DeliveryRecords& unacked); - virtual bool prepare(TransactionContext* ctxt) throw(); - virtual void commit() throw(); - virtual void rollback() throw(); - virtual ~DtxAck(){} - virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); } - const DeliveryRecords& getPending() const { return pending; } -}; + public: + DtxAck(const framing::SequenceSet& acked, DeliveryRecords& unacked); + virtual bool prepare(TransactionContext* ctxt) throw(); + virtual void commit() throw(); + virtual void rollback() throw(); + virtual ~DtxAck(){} + virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); } + }; + } +} -}} // qpid::broker -#endif /*!QPID_BROKER_DTXACK_H*/ +#endif diff --git a/cpp/src/qpid/broker/DtxBuffer.cpp b/cpp/src/qpid/broker/DtxBuffer.cpp index 13177d3b72..f1b8169cf7 100644 --- a/cpp/src/qpid/broker/DtxBuffer.cpp +++ b/cpp/src/qpid/broker/DtxBuffer.cpp @@ -23,11 +23,8 @@ using namespace qpid::broker; using qpid::sys::Mutex; -DtxBuffer::DtxBuffer( - const std::string& _xid, - bool ended_, bool suspended_, bool failed_, bool expired_) - : xid(_xid), ended(ended_), suspended(suspended_), failed(failed_), expired(expired_) -{} +DtxBuffer::DtxBuffer(const std::string& _xid) + : xid(_xid), ended(false), suspended(false), failed(false), expired(false) {} DtxBuffer::~DtxBuffer() {} @@ -37,7 +34,7 @@ void DtxBuffer::markEnded() ended = true; } -bool DtxBuffer::isEnded() const +bool DtxBuffer::isEnded() { Mutex::ScopedLock locker(lock); return ended; @@ -48,7 +45,7 @@ void DtxBuffer::setSuspended(bool isSuspended) suspended = isSuspended; } -bool DtxBuffer::isSuspended() const +bool DtxBuffer::isSuspended() { return suspended; } @@ -61,13 +58,13 @@ void DtxBuffer::fail() ended = true; } -bool DtxBuffer::isRollbackOnly() const +bool DtxBuffer::isRollbackOnly() { Mutex::ScopedLock locker(lock); return failed; } -std::string DtxBuffer::getXid() const +const std::string& DtxBuffer::getXid() { return xid; } @@ -79,13 +76,8 @@ void DtxBuffer::timedout() fail(); } -bool DtxBuffer::isExpired() const +bool DtxBuffer::isExpired() { Mutex::ScopedLock locker(lock); return expired; } - -bool DtxBuffer::isFailed() const -{ - return failed; -} diff --git a/cpp/src/qpid/broker/DtxBuffer.h b/cpp/src/qpid/broker/DtxBuffer.h index cabd37647a..1511cb032f 100644 --- a/cpp/src/qpid/broker/DtxBuffer.h +++ b/cpp/src/qpid/broker/DtxBuffer.h @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -26,34 +26,31 @@ #include "qpid/sys/Mutex.h" namespace qpid { -namespace broker { -class DtxBuffer : public TxBuffer{ - mutable sys::Mutex lock; - const std::string xid; - bool ended; - bool suspended; - bool failed; - bool expired; + namespace broker { + class DtxBuffer : public TxBuffer{ + sys::Mutex lock; + const std::string xid; + bool ended; + bool suspended; + bool failed; + bool expired; - public: - typedef boost::shared_ptr<DtxBuffer> shared_ptr; + public: + typedef boost::shared_ptr<DtxBuffer> shared_ptr; - QPID_BROKER_EXTERN DtxBuffer( - const std::string& xid = "", - bool ended=false, bool suspended=false, bool failed=false, bool expired=false); - QPID_BROKER_EXTERN ~DtxBuffer(); - QPID_BROKER_EXTERN void markEnded(); - bool isEnded() const; - void setSuspended(bool suspended); - bool isSuspended() const; - void fail(); - bool isRollbackOnly() const; - void timedout(); - bool isExpired() const; - bool isFailed() const; - std::string getXid() const; -}; -} + 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(); + void fail(); + bool isRollbackOnly(); + void timedout(); + bool isExpired(); + const std::string& getXid(); + }; + } } diff --git a/cpp/src/qpid/broker/DtxManager.cpp b/cpp/src/qpid/broker/DtxManager.cpp index febd547478..3caa41c3f4 100644 --- a/cpp/src/qpid/broker/DtxManager.cpp +++ b/cpp/src/qpid/broker/DtxManager.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -34,7 +34,7 @@ using qpid::ptr_map_ptr; using namespace qpid::broker; using namespace qpid::framing; -DtxManager::DtxManager(qpid::sys::Timer& t) : store(0), timer(&t) {} +DtxManager::DtxManager(qpid::sys::Timer& t) : store(0), timer(t) {} DtxManager::~DtxManager() {} @@ -53,8 +53,8 @@ void DtxManager::recover(const std::string& xid, std::auto_ptr<TPCTransactionCon createWork(xid)->recover(txn, ops); } -bool DtxManager::prepare(const std::string& xid) -{ +bool DtxManager::prepare(const std::string& xid) +{ QPID_LOG(debug, "preparing: " << xid); try { return getWork(xid)->prepare(); @@ -64,8 +64,8 @@ bool DtxManager::prepare(const std::string& xid) } } -bool DtxManager::commit(const std::string& xid, bool onePhase) -{ +bool DtxManager::commit(const std::string& xid, bool onePhase) +{ QPID_LOG(debug, "committing: " << xid); try { bool result = getWork(xid)->commit(onePhase); @@ -77,8 +77,8 @@ bool DtxManager::commit(const std::string& xid, bool onePhase) } } -void DtxManager::rollback(const std::string& xid) -{ +void DtxManager::rollback(const std::string& xid) +{ QPID_LOG(debug, "rolling back: " << xid); try { getWork(xid)->rollback(); @@ -91,7 +91,7 @@ void DtxManager::rollback(const std::string& xid) DtxWorkRecord* DtxManager::getWork(const std::string& xid) { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); WorkMap::iterator i = work.find(xid); if (i == work.end()) { throw NotFoundException(QPID_MSG("Unrecognised xid " << xid)); @@ -99,14 +99,9 @@ DtxWorkRecord* DtxManager::getWork(const std::string& xid) return ptr_map_ptr(i); } -bool DtxManager::exists(const std::string& xid) { - Mutex::ScopedLock locker(lock); - return work.find(xid) != work.end(); -} - void DtxManager::remove(const std::string& xid) { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); WorkMap::iterator i = work.find(xid); if (i == work.end()) { throw NotFoundException(QPID_MSG("Unrecognised xid " << xid)); @@ -115,15 +110,14 @@ void DtxManager::remove(const std::string& xid) } } -DtxWorkRecord* DtxManager::createWork(const std::string& xid) +DtxWorkRecord* DtxManager::createWork(std::string xid) { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); WorkMap::iterator i = work.find(xid); if (i != work.end()) { throw NotAllowedException(QPID_MSG("Xid " << xid << " is already known (use 'join' to add work to an existing xid)")); } else { - std::string ncxid = xid; // Work around const correctness problems in ptr_map. - return ptr_map_ptr(work.insert(ncxid, new DtxWorkRecord(ncxid, store)).first); + return ptr_map_ptr(work.insert(xid, new DtxWorkRecord(xid, store)).first); } } @@ -137,7 +131,7 @@ void DtxManager::setTimeout(const std::string& xid, uint32_t secs) } timeout = intrusive_ptr<DtxTimeout>(new DtxTimeout(secs, *this, xid)); record->setTimeout(timeout); - timer->add(timeout); + timer.add(timeout); } uint32_t DtxManager::getTimeout(const std::string& xid) @@ -148,7 +142,7 @@ uint32_t DtxManager::getTimeout(const std::string& xid) void DtxManager::timedout(const std::string& xid) { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); WorkMap::iterator i = work.find(xid); if (i == work.end()) { QPID_LOG(warning, "Transaction timeout failed: no record for xid"); @@ -159,7 +153,7 @@ void DtxManager::timedout(const std::string& xid) } } -DtxManager::DtxCleanup::DtxCleanup(uint32_t _timeout, DtxManager& _mgr, const std::string& _xid) +DtxManager::DtxCleanup::DtxCleanup(uint32_t _timeout, DtxManager& _mgr, const std::string& _xid) : TimerTask(qpid::sys::Duration(_timeout * qpid::sys::TIME_SEC),"DtxCleanup"), mgr(_mgr), xid(_xid) {} void DtxManager::DtxCleanup::fire() diff --git a/cpp/src/qpid/broker/DtxManager.h b/cpp/src/qpid/broker/DtxManager.h index 11895695a3..680b62eeb2 100644 --- a/cpp/src/qpid/broker/DtxManager.h +++ b/cpp/src/qpid/broker/DtxManager.h @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -26,8 +26,8 @@ #include "qpid/broker/DtxWorkRecord.h" #include "qpid/broker/TransactionalStore.h" #include "qpid/framing/amqp_types.h" +#include "qpid/sys/Timer.h" #include "qpid/sys/Mutex.h" -#include "qpid/ptr_map.h" namespace qpid { namespace broker { @@ -39,21 +39,22 @@ class DtxManager{ { DtxManager& mgr; const std::string& xid; - - DtxCleanup(uint32_t timeout, DtxManager& mgr, const std::string& xid); + + DtxCleanup(uint32_t timeout, DtxManager& mgr, const std::string& xid); void fire(); }; WorkMap work; TransactionalStore* store; qpid::sys::Mutex lock; - qpid::sys::Timer* timer; + qpid::sys::Timer& timer; void remove(const std::string& xid); - DtxWorkRecord* createWork(const std::string& xid); + DtxWorkRecord* getWork(const std::string& xid); + DtxWorkRecord* createWork(std::string xid); public: - DtxManager(sys::Timer&); + DtxManager(qpid::sys::Timer&); ~DtxManager(); void start(const std::string& xid, DtxBuffer::shared_ptr work); void join(const std::string& xid, DtxBuffer::shared_ptr work); @@ -65,15 +66,6 @@ public: uint32_t getTimeout(const std::string& xid); void timedout(const std::string& xid); void setStore(TransactionalStore* store); - void setTimer(sys::Timer& t) { timer = &t; } - - // Used by cluster for replication. - template<class F> void each(F f) const { - for (WorkMap::const_iterator i = work.begin(); i != work.end(); ++i) - f(*ptr_map_ptr(i)); - } - DtxWorkRecord* getWork(const std::string& xid); - bool exists(const std::string& xid); }; } diff --git a/cpp/src/qpid/broker/DtxTimeout.cpp b/cpp/src/qpid/broker/DtxTimeout.cpp index 58700846ef..c4c52ec40a 100644 --- a/cpp/src/qpid/broker/DtxTimeout.cpp +++ b/cpp/src/qpid/broker/DtxTimeout.cpp @@ -25,7 +25,7 @@ using namespace qpid::broker; DtxTimeout::DtxTimeout(uint32_t _timeout, DtxManager& _mgr, const std::string& _xid) - : TimerTask(qpid::sys::Duration(_timeout * qpid::sys::TIME_SEC),"DtxTimeout-"+_xid), timeout(_timeout), mgr(_mgr), xid(_xid) + : TimerTask(qpid::sys::Duration(_timeout * qpid::sys::TIME_SEC),"DtxTimeout"), timeout(_timeout), mgr(_mgr), xid(_xid) { } diff --git a/cpp/src/qpid/broker/DtxTimeout.h b/cpp/src/qpid/broker/DtxTimeout.h index 1fcb4cee2a..680a210e4f 100644 --- a/cpp/src/qpid/broker/DtxTimeout.h +++ b/cpp/src/qpid/broker/DtxTimeout.h @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -29,9 +29,7 @@ namespace broker { class DtxManager; -struct DtxTimeoutException : public Exception { - DtxTimeoutException(const std::string& msg=std::string()) : Exception(msg) {} -}; +struct DtxTimeoutException : public Exception {}; struct DtxTimeout : public sys::TimerTask { @@ -39,7 +37,7 @@ struct DtxTimeout : public sys::TimerTask DtxManager& mgr; const std::string xid; - DtxTimeout(uint32_t timeout, DtxManager& mgr, const std::string& xid); + DtxTimeout(uint32_t timeout, DtxManager& mgr, const std::string& xid); void fire(); }; diff --git a/cpp/src/qpid/broker/DtxWorkRecord.cpp b/cpp/src/qpid/broker/DtxWorkRecord.cpp index a413fe418d..9f33e698db 100644 --- a/cpp/src/qpid/broker/DtxWorkRecord.cpp +++ b/cpp/src/qpid/broker/DtxWorkRecord.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -28,19 +28,19 @@ using qpid::sys::Mutex; using namespace qpid::broker; using namespace qpid::framing; -DtxWorkRecord::DtxWorkRecord(const std::string& _xid, TransactionalStore* const _store) : +DtxWorkRecord::DtxWorkRecord(const std::string& _xid, TransactionalStore* const _store) : xid(_xid), store(_store), completed(false), rolledback(false), prepared(false), expired(false) {} -DtxWorkRecord::~DtxWorkRecord() +DtxWorkRecord::~DtxWorkRecord() { - if (timeout.get()) { + if (timeout.get()) { timeout->cancel(); } } bool DtxWorkRecord::prepare() { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); if (check()) { txn = store->begin(xid); if (prepare(txn.get())) { @@ -68,7 +68,7 @@ bool DtxWorkRecord::prepare(TransactionContext* _txn) bool DtxWorkRecord::commit(bool onePhase) { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); if (check()) { if (prepared) { //already prepared i.e. 2pc @@ -78,13 +78,13 @@ bool DtxWorkRecord::commit(bool onePhase) store->commit(*txn); txn.reset(); - + std::for_each(work.begin(), work.end(), mem_fn(&TxBuffer::commit)); return true; } else { //1pc commit optimisation, don't need a 2pc transaction context: if (!onePhase) { - throw IllegalStateException(QPID_MSG("Branch with xid " << xid << " has not been prepared, one-phase option required!")); + throw IllegalStateException(QPID_MSG("Branch with xid " << xid << " has not been prepared, one-phase option required!")); } std::auto_ptr<TransactionContext> localtxn = store->begin(); if (prepare(localtxn.get())) { @@ -107,16 +107,16 @@ bool DtxWorkRecord::commit(bool onePhase) void DtxWorkRecord::rollback() { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); check(); abort(); } void DtxWorkRecord::add(DtxBuffer::shared_ptr ops) { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); if (expired) { - throw DtxTimeoutException(QPID_MSG("Branch with xid " << xid << " has timed out.")); + throw DtxTimeoutException(); } if (completed) { throw CommandInvalidException(QPID_MSG("Branch with xid " << xid << " has been completed!")); @@ -163,7 +163,7 @@ void DtxWorkRecord::recover(std::auto_ptr<TPCTransactionContext> _txn, DtxBuffer void DtxWorkRecord::timedout() { - Mutex::ScopedLock locker(lock); + Mutex::ScopedLock locker(lock); expired = true; rolledback = true; if (!completed) { @@ -175,17 +175,3 @@ void DtxWorkRecord::timedout() } abort(); } - -size_t DtxWorkRecord::indexOf(const DtxBuffer::shared_ptr& buf) { - Work::iterator i = std::find(work.begin(), work.end(), buf); - if (i == work.end()) throw NotFoundException( - QPID_MSG("Can't find DTX buffer for xid: " << buf->getXid())); - return i - work.begin(); -} - -DtxBuffer::shared_ptr DtxWorkRecord::operator[](size_t i) const { - if (i > work.size()) - throw NotFoundException( - QPID_MSG("Can't find DTX buffer " << i << " for xid: " << xid)); - return work[i]; -} diff --git a/cpp/src/qpid/broker/DtxWorkRecord.h b/cpp/src/qpid/broker/DtxWorkRecord.h index 331e42fefd..aec2d2aed4 100644 --- a/cpp/src/qpid/broker/DtxWorkRecord.h +++ b/cpp/src/qpid/broker/DtxWorkRecord.h @@ -73,19 +73,9 @@ public: void timedout(); void setTimeout(boost::intrusive_ptr<DtxTimeout> t) { timeout = t; } boost::intrusive_ptr<DtxTimeout> getTimeout() { return timeout; } - std::string getXid() const { return xid; } - bool isCompleted() const { return completed; } - bool isRolledback() const { return rolledback; } - bool isPrepared() const { return prepared; } - bool isExpired() const { return expired; } - - // Used by cluster update; - size_t size() const { return work.size(); } - DtxBuffer::shared_ptr operator[](size_t i) const; - uint32_t getTimeout() const { return timeout? timeout->timeout : 0; } - size_t indexOf(const DtxBuffer::shared_ptr&); }; -}} // qpid::broker +} +} #endif diff --git a/cpp/src/qpid/broker/Exchange.cpp b/cpp/src/qpid/broker/Exchange.cpp index d68845062d..d143471559 100644 --- a/cpp/src/qpid/broker/Exchange.cpp +++ b/cpp/src/qpid/broker/Exchange.cpp @@ -19,18 +19,16 @@ * */ -#include "qpid/broker/Broker.h" -#include "qpid/broker/DeliverableMessage.h" #include "qpid/broker/Exchange.h" #include "qpid/broker/ExchangeRegistry.h" #include "qpid/broker/FedOps.h" +#include "qpid/broker/Broker.h" +#include "qpid/management/ManagementAgent.h" #include "qpid/broker/Queue.h" +#include "qpid/log/Statement.h" #include "qpid/framing/MessageProperties.h" #include "qpid/framing/reply_exceptions.h" -#include "qpid/log/Statement.h" -#include "qpid/management/ManagementAgent.h" -#include "qpid/sys/ExceptionHolder.h" -#include <stdexcept> +#include "qpid/broker/DeliverableMessage.h" using namespace qpid::broker; using namespace qpid::framing; @@ -58,7 +56,7 @@ Exchange::PreRoute::PreRoute(Deliverable& msg, Exchange* _p):parent(_p) { if (parent->sequence){ parent->sequenceNo++; - msg.getMessage().insertCustomProperty(qpidMsgSequence,parent->sequenceNo); + msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders().setInt64(qpidMsgSequence,parent->sequenceNo); } if (parent->ive) { parent->lastMsg = &( msg.getMessage()); @@ -72,36 +70,6 @@ Exchange::PreRoute::~PreRoute(){ } } -namespace { -/** Store information about an exception to be thrown later. - * If multiple exceptions are stored, save the first of the "most severe" - * exceptions, SESSION is les sever than CONNECTION etc. - */ -class ExInfo { - public: - enum Type { NONE, SESSION, CONNECTION, OTHER }; - - ExInfo(string exchange) : type(NONE), exchange(exchange) {} - void store(Type type_, const qpid::sys::ExceptionHolder& exception_, const boost::shared_ptr<Queue>& queue) { - QPID_LOG(warning, "Exchange " << exchange << " cannot deliver to queue " - << queue->getName() << ": " << exception_.what()); - if (type < type_) { // Replace less severe exception - type = type_; - exception = exception_; - } - } - - void raise() { - exception.raise(); - } - - private: - Type type; - string exchange; - qpid::sys::ExceptionHolder exception; -}; -} - void Exchange::doRoute(Deliverable& msg, ConstBindingList b) { int count = 0; @@ -112,25 +80,11 @@ void Exchange::doRoute(Deliverable& msg, ConstBindingList b) msg.getMessage().blockContentRelease(); } - - ExInfo error(getName()); // Save exception to throw at the end. for(std::vector<Binding::shared_ptr>::const_iterator i = b->begin(); i != b->end(); i++, count++) { - try { - msg.deliverTo((*i)->queue); - if ((*i)->mgmtBinding != 0) - (*i)->mgmtBinding->inc_msgMatched(); - } - catch (const SessionException& e) { - error.store(ExInfo::SESSION, framing::createSessionException(e.code, e.what()),(*i)->queue); - } - catch (const ConnectionException& e) { - error.store(ExInfo::CONNECTION, framing::createConnectionException(e.code, e.what()), (*i)->queue); - } - catch (const std::exception& e) { - error.store(ExInfo::OTHER, qpid::sys::ExceptionHolder(new Exception(e.what())), (*i)->queue); - } + msg.deliverTo((*i)->queue); + if ((*i)->mgmtBinding != 0) + (*i)->mgmtBinding->inc_msgMatched(); } - error.raise(); } if (mgmtExchange != 0) @@ -161,7 +115,7 @@ void Exchange::routeIVE(){ Exchange::Exchange (const string& _name, Manageable* parent, Broker* b) : name(_name), durable(false), persistenceId(0), sequence(false), - sequenceNo(0), ive(false), mgmtExchange(0), broker(b), destroyed(false) + sequenceNo(0), ive(false), mgmtExchange(0), broker(b) { if (parent != 0 && broker != 0) { @@ -179,7 +133,7 @@ Exchange::Exchange (const string& _name, Manageable* parent, Broker* b) : Exchange::Exchange(const string& _name, bool _durable, const qpid::framing::FieldTable& _args, Manageable* parent, Broker* b) : name(_name), durable(_durable), alternateUsers(0), persistenceId(0), - args(_args), sequence(false), sequenceNo(0), ive(false), mgmtExchange(0), broker(b), destroyed(false) + args(_args), sequence(false), sequenceNo(0), ive(false), mgmtExchange(0), broker(b) { if (parent != 0 && broker != 0) { @@ -201,11 +155,7 @@ Exchange::Exchange(const string& _name, bool _durable, const qpid::framing::Fiel } ive = _args.get(qpidIVE); - if (ive) { - if (broker && broker->isInCluster()) - throw framing::NotImplementedException("Cannot use Initial Value Exchanges in a cluster"); - QPID_LOG(debug, "Configured exchange " << _name << " with Initial Value"); - } + if (ive) QPID_LOG(debug, "Configured exchange " << _name << " with Initial Value"); } Exchange::~Exchange () @@ -390,14 +340,5 @@ bool Exchange::MatchQueue::operator()(Exchange::Binding::shared_ptr b) } void Exchange::setProperties(const boost::intrusive_ptr<Message>& msg) { - msg->setExchange(getName()); -} - -bool Exchange::routeWithAlternate(Deliverable& msg) -{ - route(msg, msg.getMessage().getRoutingKey(), msg.getMessage().getApplicationHeaders()); - if (!msg.delivered && alternate) { - alternate->route(msg, msg.getMessage().getRoutingKey(), msg.getMessage().getApplicationHeaders()); - } - return msg.delivered; + msg->getProperties<DeliveryProperties>()->setExchange(getName()); } diff --git a/cpp/src/qpid/broker/Exchange.h b/cpp/src/qpid/broker/Exchange.h index b12af9a1dd..3c8b5ca2cd 100644 --- a/cpp/src/qpid/broker/Exchange.h +++ b/cpp/src/qpid/broker/Exchange.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -39,7 +39,7 @@ namespace broker { class Broker; class ExchangeRegistry; -class QPID_BROKER_CLASS_EXTERN Exchange : public PersistableExchange, public management::Manageable { +class Exchange : public PersistableExchange, public management::Manageable { public: struct Binding : public management::Manageable { typedef boost::shared_ptr<Binding> shared_ptr; @@ -82,15 +82,15 @@ protected: private: Exchange* parent; }; - + typedef boost::shared_ptr<const std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> > > ConstBindingList; typedef boost::shared_ptr< std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> > > BindingList; void doRoute(Deliverable& msg, ConstBindingList b); void routeIVE(); - + struct MatchQueue { - const boost::shared_ptr<Queue> queue; + const boost::shared_ptr<Queue> queue; MatchQueue(boost::shared_ptr<Queue> q); bool operator()(Exchange::Binding::shared_ptr b); }; @@ -133,15 +133,15 @@ protected: /** Returns true if propagation is needed. */ bool delOrigin(const std::string& queueName, const std::string& origin){ - if (origin.empty()) { // no remote == local binding - if (localBindings > 0) - localBindings--; - return localBindings == 0; - } - size_t match = fedBindings[queueName].erase(origin); - if (fedBindings[queueName].empty()) - fedBindings.erase(queueName); - return match != 0; + fedBindings[queueName].erase(origin); + return true; + } + + /** Returns true if propagation is needed. */ + bool delOrigin() { + if (localBindings > 0) + localBindings--; + return localBindings == 0; } uint32_t count() { @@ -149,11 +149,7 @@ protected: } uint32_t countFedBindings(const std::string& queueName) { - // don't use '[]' - it may increase size of fedBindings! - std::map<std::string, originSet>::iterator i; - if ((i = fedBindings.find(queueName)) != fedBindings.end()) - return i->second.size(); - return 0; + return fedBindings[queueName].size(); } }; @@ -166,7 +162,7 @@ public: Broker* broker = 0); QPID_BROKER_EXTERN Exchange(const std::string& _name, bool _durable, const qpid::framing::FieldTable& _args, management::Manageable* parent = 0, Broker* broker = 0); - QPID_BROKER_INLINE_EXTERN virtual ~Exchange(); + QPID_BROKER_EXTERN virtual ~Exchange(); const std::string& getName() const { return name; } bool isDurable() { return durable; } @@ -195,7 +191,7 @@ public: virtual bool isBound(boost::shared_ptr<Queue> queue, const std::string* const routingKey, const qpid::framing::FieldTable* const args) = 0; QPID_BROKER_EXTERN virtual void setProperties(const boost::intrusive_ptr<Message>&); virtual void route(Deliverable& msg, const std::string& routingKey, const qpid::framing::FieldTable* args) = 0; - + //PersistableExchange: QPID_BROKER_EXTERN void setPersistenceId(uint64_t id) const; uint64_t getPersistenceId() const { return persistenceId; } @@ -226,20 +222,14 @@ public: */ void recoveryComplete(ExchangeRegistry& exchanges); - bool routeWithAlternate(Deliverable& message); - - void destroy() { destroyed = true; } - bool isDestroyed() const { return destroyed; } - protected: qpid::sys::Mutex bridgeLock; std::vector<DynamicBridge*> bridgeVector; Broker* broker; - bool destroyed; QPID_BROKER_EXTERN virtual void handleHelloRequest(); void propagateFedOp(const std::string& routingKey, const std::string& tags, - const std::string& op, const std::string& origin, + const std::string& op, const std::string& origin, qpid::framing::FieldTable* extra_args=0); }; diff --git a/cpp/src/qpid/broker/ExchangeRegistry.cpp b/cpp/src/qpid/broker/ExchangeRegistry.cpp index 1c8d26c4f7..99b121cbce 100644 --- a/cpp/src/qpid/broker/ExchangeRegistry.cpp +++ b/cpp/src/qpid/broker/ExchangeRegistry.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -39,7 +39,7 @@ pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, c return declare(name, type, false, FieldTable()); } -pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type, +pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, const string& type, bool durable, const FieldTable& args){ RWlock::ScopedWlock locker(lock); ExchangeMap::iterator i = exchanges.find(name); @@ -61,7 +61,7 @@ pair<Exchange::shared_ptr, bool> ExchangeRegistry::declare(const string& name, c }else{ FunctionMap::iterator i = factory.find(type); if (i == factory.end()) { - throw UnknownExchangeTypeException(); + throw UnknownExchangeTypeException(); } else { exchange = i->second(name, durable, args, parent, broker); } @@ -82,7 +82,6 @@ void ExchangeRegistry::destroy(const string& name){ RWlock::ScopedWlock locker(lock); ExchangeMap::iterator i = exchanges.find(name); if (i != exchanges.end()) { - i->second->destroy(); exchanges.erase(i); } } @@ -105,7 +104,7 @@ void ExchangeRegistry::registerType(const std::string& type, FactoryFunction f) } -namespace +namespace { const std::string empty; } diff --git a/cpp/src/qpid/broker/ExpiryPolicy.cpp b/cpp/src/qpid/broker/ExpiryPolicy.cpp index 62cb3fc116..64a12d918a 100644 --- a/cpp/src/qpid/broker/ExpiryPolicy.cpp +++ b/cpp/src/qpid/broker/ExpiryPolicy.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -27,12 +27,12 @@ namespace broker { ExpiryPolicy::~ExpiryPolicy() {} +void ExpiryPolicy::willExpire(Message&) {} + bool ExpiryPolicy::hasExpired(Message& m) { return m.getExpiration() < sys::AbsTime::now(); } -sys::AbsTime ExpiryPolicy::getCurrentTime() { - return sys::AbsTime::now(); -} +void ExpiryPolicy::forget(Message&) {} }} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/ExpiryPolicy.h b/cpp/src/qpid/broker/ExpiryPolicy.h index 2caf00ce00..40e793bf2c 100644 --- a/cpp/src/qpid/broker/ExpiryPolicy.h +++ b/cpp/src/qpid/broker/ExpiryPolicy.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -26,11 +26,6 @@ #include "qpid/broker/BrokerImportExport.h" namespace qpid { - -namespace sys { -class AbsTime; -} - namespace broker { class Message; @@ -38,12 +33,13 @@ class Message; /** * Default expiry policy. */ -class QPID_BROKER_CLASS_EXTERN ExpiryPolicy : public RefCounted +class ExpiryPolicy : public RefCounted { public: QPID_BROKER_EXTERN virtual ~ExpiryPolicy(); + QPID_BROKER_EXTERN virtual void willExpire(Message&); QPID_BROKER_EXTERN virtual bool hasExpired(Message&); - QPID_BROKER_EXTERN virtual qpid::sys::AbsTime getCurrentTime(); + QPID_BROKER_EXTERN virtual void forget(Message&); }; }} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/Fairshare.cpp b/cpp/src/qpid/broker/Fairshare.cpp index 313aa746f1..e6bbf86691 100644 --- a/cpp/src/qpid/broker/Fairshare.cpp +++ b/cpp/src/qpid/broker/Fairshare.cpp @@ -24,7 +24,6 @@ #include "qpid/log/Statement.h" #include <boost/format.hpp> #include <boost/lexical_cast.hpp> -#include <boost/assign/list_of.hpp> namespace qpid { namespace broker { @@ -105,80 +104,51 @@ bool Fairshare::setState(Messages& m, uint priority, uint count) return fairshare && fairshare->setState(priority, count); } -int getIntegerSetting(const qpid::framing::FieldTable& settings, const std::vector<std::string>& keys) +int getIntegerSetting(const qpid::framing::FieldTable& settings, const std::string& key) { - qpid::framing::FieldTable::ValuePtr v; - std::vector<std::string>::const_iterator i = keys.begin(); - while (!v && i != keys.end()) { - v = settings.get(*i++); - } - + qpid::framing::FieldTable::ValuePtr v = settings.get(key); if (!v) { return 0; } else if (v->convertsTo<int>()) { return v->get<int>(); } else if (v->convertsTo<std::string>()){ std::string s = v->get<std::string>(); - try { - return boost::lexical_cast<int>(s); + try { + return boost::lexical_cast<int>(s); } catch(const boost::bad_lexical_cast&) { - QPID_LOG(warning, "Ignoring invalid integer value for " << *i << ": " << s); + QPID_LOG(warning, "Ignoring invalid integer value for " << key << ": " << s); return 0; } } else { - QPID_LOG(warning, "Ignoring invalid integer value for " << *i << ": " << *v); + QPID_LOG(warning, "Ignoring invalid integer value for " << key << ": " << *v); return 0; } } -int getIntegerSettingForKey(const qpid::framing::FieldTable& settings, const std::string& key) -{ - return getIntegerSetting(settings, boost::assign::list_of<std::string>(key)); -} - -int getSetting(const qpid::framing::FieldTable& settings, const std::vector<std::string>& keys, int minvalue, int maxvalue) -{ - return std::max(minvalue,std::min(getIntegerSetting(settings, keys), maxvalue)); -} - -std::auto_ptr<Fairshare> getFairshareForKey(const qpid::framing::FieldTable& settings, uint levels, const std::string& key) -{ - uint defaultLimit = getIntegerSettingForKey(settings, key); - std::auto_ptr<Fairshare> fairshare(new Fairshare(levels, defaultLimit)); - for (uint i = 0; i < levels; i++) { - std::string levelKey = (boost::format("%1%-%2%") % key % i).str(); - if(settings.isSet(levelKey)) { - fairshare->setLimit(i, getIntegerSettingForKey(settings, levelKey)); - } - } - if (!fairshare->isNull()) { - return fairshare; - } else { - return std::auto_ptr<Fairshare>(); - } -} - -std::auto_ptr<Fairshare> getFairshare(const qpid::framing::FieldTable& settings, - uint levels, - const std::vector<std::string>& keys) +int getSetting(const qpid::framing::FieldTable& settings, const std::string& key, int minvalue, int maxvalue) { - std::auto_ptr<Fairshare> fairshare; - for (std::vector<std::string>::const_iterator i = keys.begin(); i != keys.end() && !fairshare.get(); ++i) { - fairshare = getFairshareForKey(settings, levels, *i); - } - return fairshare; + return std::max(minvalue,std::min(getIntegerSetting(settings, key), maxvalue)); } std::auto_ptr<Messages> Fairshare::create(const qpid::framing::FieldTable& settings) { - using boost::assign::list_of; std::auto_ptr<Messages> result; - size_t levels = getSetting(settings, list_of<std::string>("qpid.priorities")("x-qpid-priorities"), 0, 100); + size_t levels = getSetting(settings, "x-qpid-priorities", 1, 100); if (levels) { - std::auto_ptr<Fairshare> fairshare = - getFairshare(settings, levels, list_of<std::string>("qpid.fairshare")("x-qpid-fairshare")); - if (fairshare.get()) result = fairshare; - else result = std::auto_ptr<Messages>(new PriorityQueue(levels)); + uint defaultLimit = getIntegerSetting(settings, "x-qpid-fairshare"); + std::auto_ptr<Fairshare> fairshare(new Fairshare(levels, defaultLimit)); + for (uint i = 0; i < levels; i++) { + std::string key = (boost::format("x-qpid-fairshare-%1%") % i).str(); + if(settings.isSet(key)) { + fairshare->setLimit(i, getIntegerSetting(settings, key)); + } + } + + if (fairshare->isNull()) { + result = std::auto_ptr<Messages>(new PriorityQueue(levels)); + } else { + result = fairshare; + } } return result; } diff --git a/cpp/src/qpid/broker/Fairshare.h b/cpp/src/qpid/broker/Fairshare.h index 1b25721e0c..6c4b87f857 100644 --- a/cpp/src/qpid/broker/Fairshare.h +++ b/cpp/src/qpid/broker/Fairshare.h @@ -41,18 +41,18 @@ class Fairshare : public PriorityQueue bool getState(uint& priority, uint& count) const; bool setState(uint priority, uint count); void setLimit(size_t level, uint limit); - bool isNull(); static std::auto_ptr<Messages> create(const qpid::framing::FieldTable& settings); static bool getState(const Messages&, uint& priority, uint& count); static bool setState(Messages&, uint priority, uint count); private: std::vector<uint> limits; - + uint priority; uint count; - + uint currentLevel(); uint nextLevel(); + bool isNull(); bool limitReached(); bool findFrontLevel(uint& p, PriorityLevels&); }; diff --git a/cpp/src/qpid/broker/FanOutExchange.cpp b/cpp/src/qpid/broker/FanOutExchange.cpp index 5879fa0892..ac2c914a97 100644 --- a/cpp/src/qpid/broker/FanOutExchange.cpp +++ b/cpp/src/qpid/broker/FanOutExchange.cpp @@ -18,7 +18,6 @@ * under the License. * */ -#include "qpid/log/Statement.h" #include "qpid/broker/FanOutExchange.h" #include "qpid/broker/FedOps.h" #include <algorithm> @@ -66,7 +65,7 @@ bool FanOutExchange::bind(Queue::shared_ptr queue, const string& /*key*/, const } else if (fedOp == fedOpUnbind) { propagate = fedBinding.delOrigin(queue->getName(), fedOrigin); if (fedBinding.countFedBindings(queue->getName()) == 0) - unbind(queue, "", args); + unbind(queue, "", 0); } else if (fedOp == fedOpReorigin) { if (fedBinding.hasLocal()) { propagateFedOp(string(), string(), fedOpBind, string()); @@ -79,16 +78,12 @@ bool FanOutExchange::bind(Queue::shared_ptr queue, const string& /*key*/, const return true; } -bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*key*/, const FieldTable* args) +bool FanOutExchange::unbind(Queue::shared_ptr queue, const string& /*key*/, const FieldTable* /*args*/) { - string fedOrigin(args ? args->getAsString(qpidFedOrigin) : ""); bool propagate = false; - QPID_LOG(debug, "Unbinding queue " << queue->getName() - << " from exchange " << getName() << " origin=" << fedOrigin << ")" ); - if (bindings.remove_if(MatchQueue(queue))) { - propagate = fedBinding.delOrigin(queue->getName(), fedOrigin); + propagate = fedBinding.delOrigin(); if (mgmtExchange != 0) { mgmtExchange->dec_bindingCount(); } diff --git a/cpp/src/qpid/broker/FifoDistributor.cpp b/cpp/src/qpid/broker/FifoDistributor.cpp deleted file mode 100644 index cdb32d8c8c..0000000000 --- a/cpp/src/qpid/broker/FifoDistributor.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - - -#include "qpid/broker/Queue.h" -#include "qpid/broker/FifoDistributor.h" - -using namespace qpid::broker; - -FifoDistributor::FifoDistributor(Messages& container) - : messages(container) {} - -bool FifoDistributor::nextConsumableMessage( Consumer::shared_ptr&, QueuedMessage& next ) -{ - if (!messages.empty()) { - next = messages.front(); // by default, consume oldest msg - return true; - } - return false; -} - -bool FifoDistributor::allocate(const std::string&, const QueuedMessage& ) -{ - // by default, all messages present on the queue may be allocated as they have yet to - // be acquired. - return true; -} - -bool FifoDistributor::nextBrowsableMessage( Consumer::shared_ptr& c, QueuedMessage& next ) -{ - if (!messages.empty() && messages.next(c->position, next)) - return true; - return false; -} - -void FifoDistributor::query(qpid::types::Variant::Map&) const -{ - // nothing to see here.... -} - diff --git a/cpp/src/qpid/broker/HeadersExchange.cpp b/cpp/src/qpid/broker/HeadersExchange.cpp index 4bda70d313..82ac5911ee 100644 --- a/cpp/src/qpid/broker/HeadersExchange.cpp +++ b/cpp/src/qpid/broker/HeadersExchange.cpp @@ -112,14 +112,9 @@ bool HeadersExchange::bind(Queue::shared_ptr queue, const string& bindingKey, co { Mutex::ScopedLock l(lock); - //NOTE: do not include the fed op/tags/origin in the - //arguments as when x-match is 'all' these would prevent - //matching (they are internally added properties - //controlling binding propagation but not relevant to - //actual routing) - Binding::shared_ptr binding (new Binding (bindingKey, queue, this, extra_args)); + Binding::shared_ptr binding (new Binding (bindingKey, queue, this, *args)); BoundKey bk(binding); - if (bindings.add_unless(bk, MatchArgs(queue, &extra_args))) { + if (bindings.add_unless(bk, MatchArgs(queue, args))) { binding->startManagement(); propagate = bk.fedBinding.addOrigin(queue->getName(), fedOrigin); if (mgmtExchange != 0) { @@ -163,13 +158,12 @@ bool HeadersExchange::bind(Queue::shared_ptr queue, const string& bindingKey, co return true; } -bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable *args){ +bool HeadersExchange::unbind(Queue::shared_ptr queue, const string& bindingKey, const FieldTable*){ bool propagate = false; - string fedOrigin(args ? args->getAsString(qpidFedOrigin) : ""); { Mutex::ScopedLock l(lock); - FedUnbindModifier modifier(queue->getName(), fedOrigin); + FedUnbindModifier modifier; MatchKey match_key(queue, bindingKey); bindings.modify_if(match_key, modifier); propagate = modifier.shouldPropagate; @@ -336,7 +330,11 @@ HeadersExchange::FedUnbindModifier::FedUnbindModifier() : shouldUnbind(false), s bool HeadersExchange::FedUnbindModifier::operator()(BoundKey & bk) { - shouldPropagate = bk.fedBinding.delOrigin(queueName, fedOrigin); + if ("" == fedOrigin) { + shouldPropagate = bk.fedBinding.delOrigin(); + } else { + shouldPropagate = bk.fedBinding.delOrigin(queueName, fedOrigin); + } if (bk.fedBinding.countFedBindings(queueName) == 0) { shouldUnbind = true; diff --git a/cpp/src/qpid/broker/IncompleteMessageList.cpp b/cpp/src/qpid/broker/IncompleteMessageList.cpp new file mode 100644 index 0000000000..34d92fa752 --- /dev/null +++ b/cpp/src/qpid/broker/IncompleteMessageList.cpp @@ -0,0 +1,85 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/broker/IncompleteMessageList.h" + +namespace qpid { +namespace broker { + +IncompleteMessageList::IncompleteMessageList() : + callback(boost::bind(&IncompleteMessageList::enqueueComplete, this, _1)) +{} + +IncompleteMessageList::~IncompleteMessageList() +{ + // No lock here. We are relying on Messsag::reset*CompleteCallback + // to ensure no callbacks are in progress before they return. + for (Messages::iterator i = incomplete.begin(); i != incomplete.end(); ++i) { + (*i)->resetEnqueueCompleteCallback(); + (*i)->resetDequeueCompleteCallback(); + } +} + +void IncompleteMessageList::add(boost::intrusive_ptr<Message> msg) +{ + sys::Mutex::ScopedLock l(lock); + msg->setEnqueueCompleteCallback(callback); + incomplete.push_back(msg); +} + +void IncompleteMessageList::enqueueComplete(const boost::intrusive_ptr<Message>& ) { + sys::Mutex::ScopedLock l(lock); + lock.notify(); +} + +void IncompleteMessageList::process(const CompletionListener& listen, bool sync) +{ + sys::Mutex::ScopedLock l(lock); + while (!incomplete.empty()) { + boost::intrusive_ptr<Message>& msg = incomplete.front(); + if (!msg->isEnqueueComplete()) { + if (sync){ + { + sys::Mutex::ScopedUnlock u(lock); + msg->flush(); // Can re-enter IncompleteMessageList::enqueueComplete + } + while (!msg->isEnqueueComplete()) + lock.wait(); + } else { + //leave the message as incomplete for now + return; + } + } + listen(msg); + incomplete.pop_front(); + } +} + +void IncompleteMessageList::each(const CompletionListener& listen) { + Messages snapshot; + { + sys::Mutex::ScopedLock l(lock); + snapshot = incomplete; + } + std::for_each(incomplete.begin(), incomplete.end(), listen); +} + +}} diff --git a/cpp/src/qpid/broker/FifoDistributor.h b/cpp/src/qpid/broker/IncompleteMessageList.h index 245537ed12..a4debd1233 100644 --- a/cpp/src/qpid/broker/FifoDistributor.h +++ b/cpp/src/qpid/broker/IncompleteMessageList.h @@ -1,6 +1,3 @@ -#ifndef _broker_FifoDistributor_h -#define _broker_FifoDistributor_h - /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -10,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -21,38 +18,41 @@ * under the License. * */ +#ifndef _IncompleteMessageList_ +#define _IncompleteMessageList_ -/** Simple MessageDistributor for FIFO Queues - the HEAD message is always the next - * available message for consumption. - */ - -#include "qpid/broker/MessageDistributor.h" +#include "qpid/broker/BrokerImportExport.h" +#include "qpid/sys/Monitor.h" +#include "qpid/broker/Message.h" +#include <boost/intrusive_ptr.hpp> +#include <boost/function.hpp> +#include <list> namespace qpid { namespace broker { -class Messages; - -class FifoDistributor : public MessageDistributor +class IncompleteMessageList { - public: - FifoDistributor(Messages& container); + typedef std::list< boost::intrusive_ptr<Message> > Messages; - /** Locking Note: all methods assume the caller is holding the Queue::messageLock - * during the method call. - */ + void enqueueComplete(const boost::intrusive_ptr<Message>&); - /** MessageDistributor interface */ + sys::Monitor lock; + Messages incomplete; + Message::MessageCallback callback; - bool nextConsumableMessage( Consumer::shared_ptr& consumer, QueuedMessage& next ); - bool allocate(const std::string& consumer, const QueuedMessage& target); - bool nextBrowsableMessage( Consumer::shared_ptr& consumer, QueuedMessage& next ); - void query(qpid::types::Variant::Map&) const; +public: + typedef Message::MessageCallback CompletionListener; - private: - Messages& messages; + QPID_BROKER_EXTERN IncompleteMessageList(); + QPID_BROKER_EXTERN ~IncompleteMessageList(); + + 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); }; + }} #endif diff --git a/cpp/src/qpid/broker/LegacyLVQ.cpp b/cpp/src/qpid/broker/LegacyLVQ.cpp index 3262e343a3..a811a86492 100644 --- a/cpp/src/qpid/broker/LegacyLVQ.cpp +++ b/cpp/src/qpid/broker/LegacyLVQ.cpp @@ -93,7 +93,11 @@ void LegacyLVQ::removeIf(Predicate p) //purging of an LVQ is not enabled if the broker is clustered //(expired messages will be removed on delivery and consolidated //by key as part of normal LVQ operation). - if (!broker || !broker->isInCluster()) + + //TODO: Is there a neater way to check whether broker is + //clustered? Here we assume that if the clustered timer is the + //same as the regular timer, we are not clustered: + if (!broker || &(broker->getClusterTimer()) == &(broker->getTimer())) MessageMap::removeIf(p); } diff --git a/cpp/src/qpid/broker/Link.cpp b/cpp/src/qpid/broker/Link.cpp index 8010bf43e7..e1091df724 100644 --- a/cpp/src/qpid/broker/Link.cpp +++ b/cpp/src/qpid/broker/Link.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -30,6 +30,7 @@ #include "qpid/framing/enum.h" #include "qpid/framing/reply_exceptions.h" #include "qpid/broker/AclModule.h" +#include "qpid/sys/ClusterSafe.h" using namespace qpid::broker; using qpid::framing::Buffer; @@ -56,8 +57,8 @@ Link::Link(LinkRegistry* _links, string& _password, Broker* _broker, Manageable* parent) - : links(_links), store(_store), host(_host), port(_port), - transport(_transport), + : links(_links), store(_store), host(_host), port(_port), + transport(_transport), durable(_durable), authMechanism(_authMechanism), username(_username), password(_password), persistenceId(0), mgmtObject(0), broker(_broker), state(0), @@ -96,8 +97,7 @@ void Link::setStateLH (int newState) return; state = newState; - - if (hideManagement()) + if (mgmtObject == 0) return; switch (state) @@ -117,12 +117,12 @@ void Link::startConnectionLH () // Set the state before calling connect. It is possible that connect // will fail synchronously and call Link::closed before returning. setStateLH(STATE_CONNECTING); - broker->connect (host, boost::lexical_cast<std::string>(port), transport, + broker->connect (host, port, transport, boost::bind (&Link::closed, this, _1, _2)); QPID_LOG (debug, "Inter-broker link connecting to " << host << ":" << port); } catch(std::exception& e) { setStateLH(STATE_WAITING); - if (!hideManagement()) + if (mgmtObject != 0) mgmtObject->set_lastError (e.what()); } } @@ -133,7 +133,8 @@ void Link::established () addr << host << ":" << port; QPID_LOG (info, "Inter-broker link established to " << addr.str()); - if (!hideManagement() && agent) + // Don't raise the management event in a cluster, other members wont't get this call. + if (!sys::isCluster()) agent->raiseEvent(_qmf::EventBrokerLinkUp(addr.str())); { @@ -153,11 +154,12 @@ void Link::closed (int, std::string text) connection = 0; + // Don't raise the management event in a cluster, other members wont't get this call. if (state == STATE_OPERATIONAL) { stringstream addr; addr << host << ":" << port; QPID_LOG (warning, "Inter-broker link disconnected from " << addr.str()); - if (!hideManagement() && agent) + if (!sys::isCluster()) agent->raiseEvent(_qmf::EventBrokerLinkDown(addr.str())); } @@ -170,7 +172,7 @@ void Link::closed (int, std::string text) if (state != STATE_FAILED) { setStateLH(STATE_WAITING); - if (!hideManagement()) + if (mgmtObject != 0) mgmtObject->set_lastError (text); } @@ -219,7 +221,7 @@ 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); @@ -248,19 +250,6 @@ void Link::ioThreadProcessing() return; QPID_LOG(debug, "Link::ioThreadProcessing()"); - // check for bridge session errors and recover - if (!active.empty()) { - Bridges::iterator removed = std::remove_if( - active.begin(), active.end(), !boost::bind(&Bridge::isSessionReady, _1)); - for (Bridges::iterator i = removed; i != active.end(); ++i) { - Bridge::shared_ptr bridge = *i; - bridge->closed(); - bridge->cancel(*connection); - created.push_back(bridge); - } - active.erase(removed, active.end()); - } - //process any pending creates and/or cancellations if (!created.empty()) { for (Bridges::iterator i = created.begin(); i != created.end(); ++i) { @@ -288,9 +277,9 @@ void Link::maintenanceVisit () { Mutex::ScopedLock mutex(lock); - if (connection && updateUrls) { + if (connection && updateUrls) { urls.reset(connection->getKnownHosts()); - QPID_LOG(debug, "Known hosts for peer of inter-broker link: " << urls); + QPID_LOG(debug, "Known hosts for peer of inter-broker link: " << urls); updateUrls = false; } @@ -309,7 +298,7 @@ void Link::maintenanceVisit () } } } - else if (state == STATE_OPERATIONAL && (!active.empty() || !created.empty() || !cancellations.empty()) && connection != 0) + else if (state == STATE_OPERATIONAL && (!created.empty() || !cancellations.empty()) && connection != 0) connection->requestIOProcessing (boost::bind(&Link::ioThreadProcessing, this)); } @@ -320,7 +309,7 @@ void Link::reconnect(const qpid::Address& a) port = a.port; transport = a.protocol; startConnectionLH(); - if (!hideManagement()) { + if (mgmtObject != 0) { stringstream errorString; errorString << "Failed over to " << a; mgmtObject->set_lastError(errorString.str()); @@ -330,7 +319,7 @@ void Link::reconnect(const qpid::Address& a) bool Link::tryFailover() { Address next; - if (urls.next(next) && + if (urls.next(next) && (next.host != host || next.port != port || next.protocol != transport)) { links->changeAddress(Address(transport, host, port), next); QPID_LOG(debug, "Link failing over to " << host << ":" << port); @@ -340,12 +329,6 @@ bool Link::tryFailover() } } -// Management updates for a linke are inconsistent in a cluster, so they are -// suppressed. -bool Link::hideManagement() const { - return !mgmtObject || ( broker && broker->isInCluster()); -} - uint Link::nextChannel() { Mutex::ScopedLock mutex(lock); @@ -358,7 +341,7 @@ void Link::notifyConnectionForced(const string text) Mutex::ScopedLock mutex(lock); setStateLH(STATE_FAILED); - if (!hideManagement()) + if (mgmtObject != 0) mgmtObject->set_lastError(text); } @@ -380,7 +363,7 @@ Link::shared_ptr Link::decode(LinkRegistry& links, Buffer& buffer) string authMechanism; string username; string password; - + buffer.getShortString(host); port = buffer.getShort(); buffer.getShortString(transport); @@ -392,7 +375,7 @@ Link::shared_ptr Link::decode(LinkRegistry& links, Buffer& buffer) return links.declare(host, port, transport, durable, authMechanism, username, password).first; } -void Link::encode(Buffer& buffer) const +void Link::encode(Buffer& buffer) const { buffer.putShortString(string("link")); buffer.putShortString(host); @@ -404,8 +387,8 @@ void Link::encode(Buffer& buffer) const buffer.putShortString(password); } -uint32_t Link::encodedSize() const -{ +uint32_t Link::encodedSize() const +{ return host.size() + 1 // short-string (host) + 5 // short-string ("link") + 2 // port diff --git a/cpp/src/qpid/broker/Link.h b/cpp/src/qpid/broker/Link.h index 4badd8b3a1..75a680ff5d 100644 --- a/cpp/src/qpid/broker/Link.h +++ b/cpp/src/qpid/broker/Link.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -85,7 +85,6 @@ namespace qpid { void destroy(); // Called when mgmt deletes this link void ioThreadProcessing(); // Called on connection's IO thread by request bool tryFailover(); // Called during maintenance visit - bool hideManagement() const; public: typedef boost::shared_ptr<Link> shared_ptr; @@ -123,12 +122,12 @@ namespace qpid { void notifyConnectionForced(const std::string text); void setPassive(bool p); - + // PersistableConfig: void setPersistenceId(uint64_t id) const; uint64_t getPersistenceId() const { return persistenceId; } uint32_t encodedSize() const; - void encode(framing::Buffer& buffer) const; + void encode(framing::Buffer& buffer) const; const std::string& getName() const; static Link::shared_ptr decode(LinkRegistry& links, framing::Buffer& buffer); @@ -136,7 +135,6 @@ namespace qpid { // Manageable entry points management::ManagementObject* GetManagementObject(void) const; management::Manageable::status_t ManagementMethod(uint32_t, management::Args&, std::string&); - }; } } diff --git a/cpp/src/qpid/broker/LinkRegistry.cpp b/cpp/src/qpid/broker/LinkRegistry.cpp index e9885f5462..7b1c75db74 100644 --- a/cpp/src/qpid/broker/LinkRegistry.cpp +++ b/cpp/src/qpid/broker/LinkRegistry.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -381,7 +381,7 @@ std::string LinkRegistry::createKey(const std::string& host, uint16_t port) { return keystream.str(); } -void LinkRegistry::setPassive(bool p) +void LinkRegistry::setPassive(bool p) { Mutex::ScopedLock locker(lock); passiveChanged = p != passive; diff --git a/cpp/src/qpid/broker/Message.cpp b/cpp/src/qpid/broker/Message.cpp index d13109dad1..c589669e5a 100644 --- a/cpp/src/qpid/broker/Message.cpp +++ b/cpp/src/qpid/broker/Message.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -30,7 +30,6 @@ #include "qpid/framing/SendContent.h" #include "qpid/framing/SequenceNumber.h" #include "qpid/framing/TypeFilter.h" -#include "qpid/framing/reply_exceptions.h" #include "qpid/log/Statement.h" #include <time.h> @@ -50,16 +49,27 @@ TransferAdapter Message::TRANSFER; Message::Message(const framing::SequenceNumber& id) : frames(id), persistenceId(0), redelivered(false), loaded(false), - staged(false), forcePersistentPolicy(false), publisher(0), adapter(0), - expiration(FAR_FUTURE), dequeueCallback(0), - inCallback(false), requiredCredit(0), isManagementMessage(false), copyHeaderOnWrite(false) -{} + staged(false), forcePersistentPolicy(false), publisher(0), adapter(0), + expiration(FAR_FUTURE), enqueueCallback(0), dequeueCallback(0), + inCallback(false), requiredCredit(0) {} -Message::~Message() {} +Message::Message(const Message& original) : + PersistableMessage(), frames(original.frames), persistenceId(0), redelivered(false), loaded(false), + staged(false), forcePersistentPolicy(false), publisher(0), adapter(0), + expiration(original.expiration), enqueueCallback(0), dequeueCallback(0), + inCallback(false), requiredCredit(0) +{ + setExpiryPolicy(original.expiryPolicy); +} + +Message::~Message() +{ + if (expiryPolicy) + expiryPolicy->forget(*this); +} void Message::forcePersistent() { - sys::Mutex::ScopedLock l(lock); // only set forced bit if we actually need to force. if (! getAdapter().isPersistent(frames) ){ forcePersistentPolicy = true; @@ -76,7 +86,7 @@ std::string Message::getRoutingKey() const return getAdapter().getRoutingKey(frames); } -std::string Message::getExchangeName() const +std::string Message::getExchangeName() const { return getAdapter().getExchange(frames); } @@ -85,7 +95,7 @@ const boost::shared_ptr<Exchange> Message::getExchange(ExchangeRegistry& registr { if (!exchange) { exchange = registry.get(getExchangeName()); - } + } return exchange; } @@ -96,19 +106,16 @@ bool Message::isImmediate() const const FieldTable* Message::getApplicationHeaders() const { - sys::Mutex::ScopedLock l(lock); return getAdapter().getApplicationHeaders(frames); } std::string Message::getAppId() const { - sys::Mutex::ScopedLock l(lock); return getAdapter().getAppId(frames); } bool Message::isPersistent() const { - sys::Mutex::ScopedLock l(lock); return (getAdapter().isPersistent(frames) || forcePersistentPolicy); } @@ -188,7 +195,7 @@ void Message::decodeContent(framing::Buffer& buffer) } else { //adjust header flags MarkLastSegment f; - frames.map_if(f, TypeFilter<HEADER_BODY>()); + frames.map_if(f, TypeFilter<HEADER_BODY>()); } //mark content loaded loaded = true; @@ -240,7 +247,7 @@ void Message::destroy() bool Message::getContentFrame(const Queue& queue, AMQFrame& frame, uint16_t maxContentSize, uint64_t offset) const { intrusive_ptr<const PersistableMessage> pmsg(this); - + bool done = false; string& data = frame.castBody<AMQContentBody>()->getData(); store->loadContent(queue, pmsg, data, offset, maxContentSize); @@ -265,7 +272,7 @@ void Message::sendContent(const Queue& queue, framing::FrameHandler& out, uint16 uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead(); bool morecontent = true; for (uint64_t offset = 0; morecontent; offset += maxContentSize) - { + { AMQFrame frame((AMQContentBody())); morecontent = getContentFrame(queue, frame, maxContentSize, offset); out.handle(frame); @@ -283,10 +290,7 @@ void Message::sendHeader(framing::FrameHandler& out, uint16_t /*maxFrameSize*/) { sys::Mutex::ScopedLock l(lock); Relay f(out); - frames.map_if(f, TypeFilter<HEADER_BODY>()); - //as frame (and pointer to body) has now been passed to handler, - //subsequent modifications should use a copy - copyHeaderOnWrite = true; + frames.map_if(f, TypeFilter<HEADER_BODY>()); } // TODO aconway 2007-11-09: Obsolete, remove. Was used to cover over @@ -316,14 +320,13 @@ bool Message::isContentLoaded() const } -namespace +namespace { const std::string X_QPID_TRACE("x-qpid.trace"); } bool Message::isExcluded(const std::vector<std::string>& excludes) const { - sys::Mutex::ScopedLock l(lock); const FieldTable* headers = getApplicationHeaders(); if (headers) { std::string traceStr = headers->getAsString(X_QPID_TRACE); @@ -342,30 +345,11 @@ bool Message::isExcluded(const std::vector<std::string>& excludes) const return false; } -class CloneHeaderBody -{ -public: - void operator()(AMQFrame& f) - { - f.cloneBody(); - } -}; - -AMQHeaderBody* Message::getHeaderBody() -{ - if (copyHeaderOnWrite) { - CloneHeaderBody f; - frames.map_if(f, TypeFilter<HEADER_BODY>()); - copyHeaderOnWrite = false; - } - return frames.getHeaders(); -} - void Message::addTraceId(const std::string& id) { sys::Mutex::ScopedLock l(lock); if (isA<MessageTransferBody>()) { - FieldTable& headers = getModifiableProperties<MessageProperties>()->getApplicationHeaders(); + FieldTable& headers = getProperties<MessageProperties>()->getApplicationHeaders(); std::string trace = headers.getAsString(X_QPID_TRACE); if (trace.empty()) { headers.setString(X_QPID_TRACE, id); @@ -373,22 +357,13 @@ void Message::addTraceId(const std::string& id) trace += ","; trace += id; headers.setString(X_QPID_TRACE, trace); - } + } } } -void Message::setTimestamp() -{ - sys::Mutex::ScopedLock l(lock); - DeliveryProperties* props = getModifiableProperties<DeliveryProperties>(); - time_t now = ::time(0); - props->setTimestamp(now); // AMQP-0.10: posix time_t - secs since Epoch -} - -void Message::computeExpiration(const boost::intrusive_ptr<ExpiryPolicy>& e) +void Message::setTimestamp(const boost::intrusive_ptr<ExpiryPolicy>& e) { - sys::Mutex::ScopedLock l(lock); - DeliveryProperties* props = getModifiableProperties<DeliveryProperties>(); + DeliveryProperties* props = getProperties<DeliveryProperties>(); if (props->getTtl()) { // AMQP requires setting the expiration property to be posix // time_t in seconds. TTL is in milliseconds @@ -397,70 +372,26 @@ void Message::computeExpiration(const boost::intrusive_ptr<ExpiryPolicy>& e) time_t now = ::time(0); props->setExpiration(now + (props->getTtl()/1000)); } - if (e) { - // Use higher resolution time for the internal expiry calculation. - // Prevent overflow as a signed int64_t - Duration ttl(std::min(props->getTtl() * TIME_MSEC, - (uint64_t) std::numeric_limits<int64_t>::max())); - expiration = AbsTime(e->getCurrentTime(), ttl); - setExpiryPolicy(e); - } + // Use higher resolution time for the internal expiry calculation. + expiration = AbsTime(AbsTime::now(), Duration(props->getTtl() * TIME_MSEC)); + setExpiryPolicy(e); } } void Message::adjustTtl() { - sys::Mutex::ScopedLock l(lock); - DeliveryProperties* props = getModifiableProperties<DeliveryProperties>(); + DeliveryProperties* props = getProperties<DeliveryProperties>(); if (props->getTtl()) { - if (expiration < FAR_FUTURE) { - sys::AbsTime current( - expiryPolicy ? expiryPolicy->getCurrentTime() : sys::AbsTime::now()); - sys::Duration ttl(current, getExpiration()); - // convert from ns to ms; set to 1 if expired - props->setTtl(int64_t(ttl) >= 1000000 ? int64_t(ttl)/1000000 : 1); - } + sys::Mutex::ScopedLock l(lock); + sys::Duration d(sys::AbsTime::now(), getExpiration()); + props->setTtl(int64_t(d) > 0 ? int64_t(d)/1000000 : 1); // convert from ns to ms; set to 1 if expired } } -void Message::setRedelivered() -{ - sys::Mutex::ScopedLock l(lock); - getModifiableProperties<framing::DeliveryProperties>()->setRedelivered(true); -} - -void Message::insertCustomProperty(const std::string& key, int64_t value) -{ - sys::Mutex::ScopedLock l(lock); - getModifiableProperties<MessageProperties>()->getApplicationHeaders().setInt64(key,value); -} - -void Message::insertCustomProperty(const std::string& key, const std::string& value) -{ - sys::Mutex::ScopedLock l(lock); - getModifiableProperties<MessageProperties>()->getApplicationHeaders().setString(key,value); -} - -void Message::removeCustomProperty(const std::string& key) -{ - sys::Mutex::ScopedLock l(lock); - getModifiableProperties<MessageProperties>()->getApplicationHeaders().erase(key); -} - -void Message::setExchange(const std::string& exchange) -{ - sys::Mutex::ScopedLock l(lock); - getModifiableProperties<DeliveryProperties>()->setExchange(exchange); -} - -void Message::clearApplicationHeadersFlag() -{ - sys::Mutex::ScopedLock l(lock); - getModifiableProperties<MessageProperties>()->clearApplicationHeadersFlag(); -} - void Message::setExpiryPolicy(const boost::intrusive_ptr<ExpiryPolicy>& e) { expiryPolicy = e; + if (expiryPolicy) + expiryPolicy->willExpire(*this); } bool Message::hasExpired() @@ -484,12 +415,30 @@ struct ScopedSet { }; } +void Message::allEnqueuesComplete() { + ScopedSet ss(callbackLock, inCallback); + MessageCallback* cb = enqueueCallback; + if (cb && *cb) (*cb)(intrusive_ptr<Message>(this)); +} + void Message::allDequeuesComplete() { ScopedSet ss(callbackLock, inCallback); MessageCallback* cb = dequeueCallback; if (cb && *cb) (*cb)(intrusive_ptr<Message>(this)); } +void Message::setEnqueueCompleteCallback(MessageCallback& cb) { + sys::Mutex::ScopedLock l(callbackLock); + while (inCallback) callbackLock.wait(); + enqueueCallback = &cb; +} + +void Message::resetEnqueueCompleteCallback() { + sys::Mutex::ScopedLock l(callbackLock); + while (inCallback) callbackLock.wait(); + enqueueCallback = 0; +} + void Message::setDequeueCompleteCallback(MessageCallback& cb) { sys::Mutex::ScopedLock l(callbackLock); while (inCallback) callbackLock.wait(); @@ -503,11 +452,12 @@ void Message::resetDequeueCompleteCallback() { } uint8_t Message::getPriority() const { - sys::Mutex::ScopedLock l(lock); return getAdapter().getPriority(frames); } -bool Message::getIsManagementMessage() const { return isManagementMessage; } -void Message::setIsManagementMessage(bool b) { isManagementMessage = b; } +framing::FieldTable& Message::getOrInsertHeaders() +{ + return getProperties<MessageProperties>()->getApplicationHeaders(); +} }} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/Message.h b/cpp/src/qpid/broker/Message.h index dda45d73e6..f7dd2734b6 100644 --- a/cpp/src/qpid/broker/Message.h +++ b/cpp/src/qpid/broker/Message.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -29,21 +29,17 @@ #include "qpid/sys/Monitor.h" #include "qpid/sys/Time.h" #include <boost/function.hpp> -#include <boost/intrusive_ptr.hpp> #include <boost/shared_ptr.hpp> -#include <memory> #include <string> #include <vector> namespace qpid { - + namespace framing { -class AMQBody; -class AMQHeaderBody; class FieldTable; class SequenceNumber; } - + namespace broker { class ConnectionToken; class Exchange; @@ -55,10 +51,11 @@ class ExpiryPolicy; class Message : public PersistableMessage { public: typedef boost::function<void (const boost::intrusive_ptr<Message>&)> MessageCallback; - + QPID_BROKER_EXTERN Message(const framing::SequenceNumber& id = framing::SequenceNumber()); + QPID_BROKER_EXTERN Message(const Message&); QPID_BROKER_EXTERN ~Message(); - + uint64_t getPersistenceId() const { return persistenceId; } void setPersistenceId(uint64_t _persistenceId) const { persistenceId = _persistenceId; } @@ -78,31 +75,27 @@ public: bool isImmediate() const; QPID_BROKER_EXTERN const framing::FieldTable* getApplicationHeaders() const; QPID_BROKER_EXTERN std::string getAppId() const; + framing::FieldTable& getOrInsertHeaders(); QPID_BROKER_EXTERN bool isPersistent() const; bool requiresAccept(); - /** determine msg expiration time using the TTL value if present */ - QPID_BROKER_EXTERN void computeExpiration(const boost::intrusive_ptr<ExpiryPolicy>& e); + 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; } - void setExpiration(sys::AbsTime exp) { expiration = exp; } void adjustTtl(); - void setRedelivered(); - QPID_BROKER_EXTERN void insertCustomProperty(const std::string& key, int64_t value); - QPID_BROKER_EXTERN void insertCustomProperty(const std::string& key, const std::string& value); - QPID_BROKER_EXTERN void removeCustomProperty(const std::string& key); - void setExchange(const std::string&); - void clearApplicationHeadersFlag(); - /** set the timestamp delivery property to the current time-of-day */ - QPID_BROKER_EXTERN void setTimestamp(); - - framing::FrameSet& getFrames() { return frames; } - const framing::FrameSet& getFrames() const { return frames; } + + framing::FrameSet& getFrames() { return frames; } + const framing::FrameSet& getFrames() const { return frames; } + + template <class T> T* getProperties() { + qpid::framing::AMQHeaderBody* p = frames.getHeaders(); + return p->get<T>(true); + } template <class T> const T* getProperties() const { - const qpid::framing::AMQHeaderBody* p = frames.getHeaders(); - return p->get<T>(); + qpid::framing::AMQHeaderBody* p = frames.getHeaders(); + return p->get<T>(true); } template <class T> const T* hasProperties() const { @@ -110,11 +103,6 @@ public: return p->get<T>(); } - template <class T> void eraseProperties() { - qpid::framing::AMQHeaderBody* p = frames.getHeaders(); - p->erase<T>(); - } - template <class T> const T* getMethod() const { return frames.as<T>(); } @@ -147,7 +135,7 @@ public: QPID_BROKER_EXTERN void decodeHeader(framing::Buffer& buffer); QPID_BROKER_EXTERN void decodeContent(framing::Buffer& buffer); - + void QPID_BROKER_EXTERN tryReleaseContent(); void releaseContent(); void releaseContent(MessageStore* s);//deprecated, use 'setStore(store); releaseContent();' instead @@ -161,19 +149,24 @@ public: bool isExcluded(const std::vector<std::string>& excludes) const; void addTraceId(const std::string& id); + + void forcePersistent(); + bool isForcedPersistent(); + - void forcePersistent(); - bool isForcedPersistent(); + /** Call cb when enqueue is complete, may call immediately. Holds cb by reference. */ + void setEnqueueCompleteCallback(MessageCallback& cb); + void resetEnqueueCompleteCallback(); /** Call cb when dequeue is complete, may call immediately. Holds cb by reference. */ void setDequeueCompleteCallback(MessageCallback& cb); void resetDequeueCompleteCallback(); uint8_t getPriority() const; - bool getIsManagementMessage() const; - void setIsManagementMessage(bool b); + private: MessageAdapter& getAdapter() const; + void allEnqueuesComplete(); void allDequeuesComplete(); mutable sys::Mutex lock; @@ -183,7 +176,7 @@ public: bool redelivered; bool loaded; bool staged; - bool forcePersistentPolicy; // used to force message as durable, via a broker policy + bool forcePersistentPolicy; // used to force message as durable, via a broker policy ConnectionToken* publisher; mutable MessageAdapter* adapter; qpid::sys::AbsTime expiration; @@ -194,20 +187,11 @@ public: mutable boost::intrusive_ptr<Message> empty; sys::Monitor callbackLock; + MessageCallback* enqueueCallback; MessageCallback* dequeueCallback; bool inCallback; uint32_t requiredCredit; - bool isManagementMessage; - mutable bool copyHeaderOnWrite; - - /** - * Expects lock to be held - */ - template <class T> T* getModifiableProperties() { - return getHeaderBody()->get<T>(true); - } - qpid::framing::AMQHeaderBody* getHeaderBody(); }; }} diff --git a/cpp/src/qpid/broker/MessageBuilder.h b/cpp/src/qpid/broker/MessageBuilder.h index b99b8efee6..75dfd6781d 100644 --- a/cpp/src/qpid/broker/MessageBuilder.h +++ b/cpp/src/qpid/broker/MessageBuilder.h @@ -33,7 +33,7 @@ namespace qpid { class Message; class MessageStore; - class QPID_BROKER_CLASS_EXTERN MessageBuilder : public framing::FrameHandler{ + class MessageBuilder : public framing::FrameHandler{ public: QPID_BROKER_EXTERN MessageBuilder(MessageStore* const store); QPID_BROKER_EXTERN void handle(framing::AMQFrame& frame); diff --git a/cpp/src/qpid/broker/MessageDistributor.h b/cpp/src/qpid/broker/MessageDistributor.h deleted file mode 100644 index 090393c160..0000000000 --- a/cpp/src/qpid/broker/MessageDistributor.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef _broker_MessageDistributor_h -#define _broker_MessageDistributor_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. - * - */ - -/** Abstraction used by Queue to determine the next "most desirable" message to provide to - * a particular consuming client - */ - - -#include "qpid/broker/Consumer.h" - -namespace qpid { -namespace broker { - -struct QueuedMessage; - -class MessageDistributor -{ - public: - virtual ~MessageDistributor() {}; - - /** Locking Note: all methods assume the caller is holding the Queue::messageLock - * during the method call. - */ - - /** Determine the next message available for consumption by the consumer - * @param consumer the consumer that needs a message to consume - * @param next set to the next message that the consumer may consume. - * @return true if message is available and next is set - */ - virtual bool nextConsumableMessage( Consumer::shared_ptr& consumer, - QueuedMessage& next ) = 0; - - /** Allow the comsumer to take ownership of the given message. - * @param consumer the name of the consumer that is attempting to acquire the message - * @param qm the message to be acquired, previously returned from nextConsumableMessage() - * @return true if ownership is permitted, false if ownership cannot be assigned. - */ - virtual bool allocate( const std::string& consumer, - const QueuedMessage& target) = 0; - - /** Determine the next message available for browsing by the consumer - * @param consumer the consumer that is browsing the queue - * @param next set to the next message that the consumer may browse. - * @return true if a message is available and next is returned - */ - virtual bool nextBrowsableMessage( Consumer::shared_ptr& consumer, - QueuedMessage& next ) = 0; - - /** hook to add any interesting management state to the status map */ - virtual void query(qpid::types::Variant::Map&) const = 0; -}; - -}} - -#endif diff --git a/cpp/src/qpid/broker/MessageGroupManager.cpp b/cpp/src/qpid/broker/MessageGroupManager.cpp deleted file mode 100644 index 07b05f3b92..0000000000 --- a/cpp/src/qpid/broker/MessageGroupManager.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -#include "qpid/framing/FieldTable.h" -#include "qpid/types/Variant.h" -#include "qpid/log/Statement.h" -#include "qpid/broker/Queue.h" -#include "qpid/broker/MessageGroupManager.h" - -using namespace qpid::broker; - -namespace { - const std::string GROUP_QUERY_KEY("qpid.message_group_queue"); - const std::string GROUP_HEADER_KEY("group_header_key"); - const std::string GROUP_STATE_KEY("group_state"); - const std::string GROUP_ID_KEY("group_id"); - const std::string GROUP_MSG_COUNT("msg_count"); - const std::string GROUP_TIMESTAMP("timestamp"); - const std::string GROUP_CONSUMER("consumer"); -} - - -const std::string MessageGroupManager::qpidMessageGroupKey("qpid.group_header_key"); -const std::string MessageGroupManager::qpidSharedGroup("qpid.shared_msg_group"); -const std::string MessageGroupManager::qpidMessageGroupTimestamp("qpid.group_timestamp"); - - -void MessageGroupManager::unFree( const GroupState& state ) -{ - GroupFifo::iterator pos = freeGroups.find( state.members.front() ); - assert( pos != freeGroups.end() && pos->second == &state ); - freeGroups.erase( pos ); -} - -void MessageGroupManager::own( GroupState& state, const std::string& owner ) -{ - state.owner = owner; - unFree( state ); -} - -void MessageGroupManager::disown( GroupState& state ) -{ - state.owner.clear(); - assert(state.members.size()); - assert(freeGroups.find(state.members.front()) == freeGroups.end()); - freeGroups[state.members.front()] = &state; -} - -const std::string MessageGroupManager::getGroupId( const QueuedMessage& qm ) const -{ - const qpid::framing::FieldTable* headers = qm.payload->getApplicationHeaders(); - if (!headers) return defaultGroupId; - qpid::framing::FieldTable::ValuePtr id = headers->get( groupIdHeader ); - if (!id || !id->convertsTo<std::string>()) return defaultGroupId; - return id->get<std::string>(); -} - - -void MessageGroupManager::enqueued( const QueuedMessage& qm ) -{ - // @todo KAG optimization - store reference to group state in QueuedMessage - // issue: const-ness?? - std::string group( getGroupId(qm) ); - GroupState &state(messageGroups[group]); - state.members.push_back(qm.position); - uint32_t total = state.members.size(); - QPID_LOG( trace, "group queue " << qName << - ": added message to group id=" << group << " total=" << total ); - if (total == 1) { - // newly created group, no owner - state.group = group; - assert(freeGroups.find(qm.position) == freeGroups.end()); - freeGroups[qm.position] = &state; - } -} - - -void MessageGroupManager::acquired( const QueuedMessage& qm ) -{ - // @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage - // issue: const-ness?? - std::string group( getGroupId(qm) ); - GroupMap::iterator gs = messageGroups.find( group ); - assert( gs != messageGroups.end() ); - GroupState& state( gs->second ); - state.acquired += 1; - QPID_LOG( trace, "group queue " << qName << - ": acquired message in group id=" << group << " acquired=" << state.acquired ); -} - - -void MessageGroupManager::requeued( const QueuedMessage& qm ) -{ - // @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage - // issue: const-ness?? - std::string group( getGroupId(qm) ); - GroupMap::iterator gs = messageGroups.find( group ); - assert( gs != messageGroups.end() ); - GroupState& state( gs->second ); - assert( state.acquired != 0 ); - state.acquired -= 1; - if (state.acquired == 0 && state.owned()) { - QPID_LOG( trace, "group queue " << qName << - ": consumer name=" << state.owner << " released group id=" << gs->first); - disown(state); - } - QPID_LOG( trace, "group queue " << qName << - ": requeued message to group id=" << group << " acquired=" << state.acquired ); -} - - -void MessageGroupManager::dequeued( const QueuedMessage& qm ) -{ - // @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage - // issue: const-ness?? - std::string group( getGroupId(qm) ); - GroupMap::iterator gs = messageGroups.find( group ); - assert( gs != messageGroups.end() ); - GroupState& state( gs->second ); - assert( state.members.size() != 0 ); - assert( state.acquired != 0 ); - state.acquired -= 1; - - // likely to be at or near begin() if dequeued in order - bool reFreeNeeded = false; - if (state.members.front() == qm.position) { - if (!state.owned()) { - // will be on the freeGroups list if mgmt is dequeueing rather than a consumer! - // if on freelist, it is indexed by first member, which is about to be removed! - unFree(state); - reFreeNeeded = true; - } - state.members.pop_front(); - } else { - GroupState::PositionFifo::iterator pos = state.members.begin() + 1; - GroupState::PositionFifo::iterator end = state.members.end(); - while (pos != end) { - if (*pos == qm.position) { - state.members.erase(pos); - break; - } - ++pos; - } - } - - uint32_t total = state.members.size(); - if (total == 0) { - QPID_LOG( trace, "group queue " << qName << ": deleting group id=" << gs->first); - messageGroups.erase( gs ); - } else if (state.acquired == 0 && state.owned()) { - QPID_LOG( trace, "group queue " << qName << - ": consumer name=" << state.owner << " released group id=" << gs->first); - disown(state); - } else if (reFreeNeeded) { - disown(state); - } - QPID_LOG( trace, "group queue " << qName << - ": dequeued message from group id=" << group << " total=" << total ); -} - -bool MessageGroupManager::nextConsumableMessage( Consumer::shared_ptr& c, QueuedMessage& next ) -{ - if (messages.empty()) - return false; - - if (!freeGroups.empty()) { - framing::SequenceNumber nextFree = freeGroups.begin()->first; - if (nextFree < c->position) { // next free group's msg is older than current position - bool ok = messages.find(nextFree, next); - (void) ok; assert( ok ); - } else { - if (!messages.next( c->position, next )) - return false; // shouldn't happen - should find nextFree - } - } else { // no free groups available - if (!messages.next( c->position, next )) - return false; - } - - do { - // @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage - std::string group( getGroupId( next ) ); - GroupMap::iterator gs = messageGroups.find( group ); - assert( gs != messageGroups.end() ); - GroupState& state( gs->second ); - if (!state.owned() || state.owner == c->getName()) { - return true; - } - } while (messages.next( next.position, next )); - return false; -} - - -bool MessageGroupManager::allocate(const std::string& consumer, const QueuedMessage& qm) -{ - // @todo KAG avoid lookup: retrieve direct reference to group state from QueuedMessage - std::string group( getGroupId(qm) ); - GroupMap::iterator gs = messageGroups.find( group ); - assert( gs != messageGroups.end() ); - GroupState& state( gs->second ); - - if (!state.owned()) { - own( state, consumer ); - QPID_LOG( trace, "group queue " << qName << - ": consumer name=" << consumer << " has acquired group id=" << gs->first); - return true; - } - return state.owner == consumer; -} - -bool MessageGroupManager::nextBrowsableMessage( Consumer::shared_ptr& c, QueuedMessage& next ) -{ - // browse: allow access to any available msg, regardless of group ownership (?ok?) - if (!messages.empty() && messages.next(c->position, next)) - return true; - return false; -} - -void MessageGroupManager::query(qpid::types::Variant::Map& status) const -{ - /** Add a description of the current state of the message groups for this queue. - FORMAT: - { "qpid.message_group_queue": - { "group_header_key" : "<KEY>", - "group_state" : - [ { "group_id" : "<name>", - "msg_count" : <int>, - "timestamp" : <absTime>, - "consumer" : <consumer name> }, - {...} // one for each known group - ] - } - } - **/ - - assert(status.find(GROUP_QUERY_KEY) == status.end()); - qpid::types::Variant::Map state; - qpid::types::Variant::List groups; - - state[GROUP_HEADER_KEY] = groupIdHeader; - for (GroupMap::const_iterator g = messageGroups.begin(); - g != messageGroups.end(); ++g) { - qpid::types::Variant::Map info; - info[GROUP_ID_KEY] = g->first; - info[GROUP_MSG_COUNT] = g->second.members.size(); - info[GROUP_TIMESTAMP] = 0; /** @todo KAG - NEED HEAD MSG TIMESTAMP */ - info[GROUP_CONSUMER] = g->second.owner; - groups.push_back(info); - } - state[GROUP_STATE_KEY] = groups; - status[GROUP_QUERY_KEY] = state; -} - - -boost::shared_ptr<MessageGroupManager> MessageGroupManager::create( const std::string& qName, - Messages& messages, - const qpid::framing::FieldTable& settings ) -{ - boost::shared_ptr<MessageGroupManager> empty; - - if (settings.isSet(qpidMessageGroupKey)) { - - // @todo: remove once "sticky" consumers are supported - see QPID-3347 - if (!settings.isSet(qpidSharedGroup)) { - QPID_LOG( error, "Only shared groups are supported in this version of the broker. Use '--shared-groups' in qpid-config." ); - return empty; - } - - std::string headerKey = settings.getAsString(qpidMessageGroupKey); - if (headerKey.empty()) { - QPID_LOG( error, "A Message Group header key must be configured, queue=" << qName); - return empty; - } - unsigned int timestamp = settings.getAsInt(qpidMessageGroupTimestamp); - - boost::shared_ptr<MessageGroupManager> manager( new MessageGroupManager( headerKey, qName, messages, timestamp ) ); - - QPID_LOG( debug, "Configured Queue '" << qName << - "' for message grouping using header key '" << headerKey << "'" << - " (timestamp=" << timestamp << ")"); - return manager; - } - return empty; -} - -std::string MessageGroupManager::defaultGroupId; -void MessageGroupManager::setDefaults(const std::string& groupId) // static -{ - defaultGroupId = groupId; -} - -/** Cluster replication: - - state map format: - - { "group-state": [ {"name": <group-name>, - "owner": <consumer-name>-or-empty, - "acquired-ct": <acquired count>, - "positions": [Seqnumbers, ... ]}, - {...} - ] - } -*/ - -namespace { - const std::string GROUP_NAME("name"); - const std::string GROUP_OWNER("owner"); - const std::string GROUP_ACQUIRED_CT("acquired-ct"); - const std::string GROUP_POSITIONS("positions"); - const std::string GROUP_STATE("group-state"); -} - - -/** Runs on UPDATER to snapshot current state */ -void MessageGroupManager::getState(qpid::framing::FieldTable& state ) const -{ - using namespace qpid::framing; - state.clear(); - framing::Array groupState(TYPE_CODE_MAP); - for (GroupMap::const_iterator g = messageGroups.begin(); - g != messageGroups.end(); ++g) { - - framing::FieldTable group; - group.setString(GROUP_NAME, g->first); - group.setString(GROUP_OWNER, g->second.owner); - group.setInt(GROUP_ACQUIRED_CT, g->second.acquired); - framing::Array positions(TYPE_CODE_UINT32); - for (GroupState::PositionFifo::const_iterator p = g->second.members.begin(); - p != g->second.members.end(); ++p) - positions.push_back(framing::Array::ValuePtr(new IntegerValue( *p ))); - group.setArray(GROUP_POSITIONS, positions); - groupState.push_back(framing::Array::ValuePtr(new FieldTableValue(group))); - } - state.setArray(GROUP_STATE, groupState); - - QPID_LOG(debug, "Queue \"" << qName << "\": replicating message group state, key=" << groupIdHeader); -} - - -/** called on UPDATEE to set state from snapshot */ -void MessageGroupManager::setState(const qpid::framing::FieldTable& state) -{ - using namespace qpid::framing; - messageGroups.clear(); - //consumers.clear(); - freeGroups.clear(); - - framing::Array groupState(TYPE_CODE_MAP); - - bool ok = state.getArray(GROUP_STATE, groupState); - if (!ok) { - QPID_LOG(error, "Unable to find message group state information for queue \"" << - qName << "\": cluster inconsistency error!"); - return; - } - - for (framing::Array::const_iterator g = groupState.begin(); - g != groupState.end(); ++g) { - framing::FieldTable group; - ok = framing::getEncodedValue<FieldTable>(*g, group); - if (!ok) { - QPID_LOG(error, "Invalid message group state information for queue \"" << - qName << "\": table encoding error!"); - return; - } - MessageGroupManager::GroupState state; - if (!group.isSet(GROUP_NAME) || !group.isSet(GROUP_OWNER) || !group.isSet(GROUP_ACQUIRED_CT)) { - QPID_LOG(error, "Invalid message group state information for queue \"" << - qName << "\": fields missing error!"); - return; - } - state.group = group.getAsString(GROUP_NAME); - state.owner = group.getAsString(GROUP_OWNER); - state.acquired = group.getAsInt(GROUP_ACQUIRED_CT); - framing::Array positions(TYPE_CODE_UINT32); - ok = group.getArray(GROUP_POSITIONS, positions); - if (!ok) { - QPID_LOG(error, "Invalid message group state information for queue \"" << - qName << "\": position encoding error!"); - return; - } - - for (Array::const_iterator p = positions.begin(); p != positions.end(); ++p) - state.members.push_back((*p)->getIntegerValue<uint32_t, 4>()); - messageGroups[state.group] = state; - if (!state.owned()) { - assert(state.members.size()); - freeGroups[state.members.front()] = &messageGroups[state.group]; - } - } - - QPID_LOG(debug, "Queue \"" << qName << "\": message group state replicated, key =" << groupIdHeader) -} diff --git a/cpp/src/qpid/broker/MessageGroupManager.h b/cpp/src/qpid/broker/MessageGroupManager.h deleted file mode 100644 index 6c81ec14d1..0000000000 --- a/cpp/src/qpid/broker/MessageGroupManager.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef _broker_MessageGroupManager_h -#define _broker_MessageGroupManager_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. - * - */ - -/* for managing message grouping on Queues */ - -#include "qpid/broker/StatefulQueueObserver.h" -#include "qpid/broker/MessageDistributor.h" - - -namespace qpid { -namespace broker { - -class QueueObserver; -class MessageDistributor; - -class MessageGroupManager : public StatefulQueueObserver, public MessageDistributor -{ - static std::string defaultGroupId; // assigned if no group id header present - - const std::string groupIdHeader; // msg header holding group identifier - const unsigned int timestamp; // mark messages with timestamp if set - Messages& messages; // parent Queue's in memory message container - const std::string qName; // name of parent queue (for logs) - - struct GroupState { - // note: update getState()/setState() when changing this object's state implementation - typedef std::deque<framing::SequenceNumber> PositionFifo; - - std::string group; // group identifier - std::string owner; // consumer with outstanding acquired messages - uint32_t acquired; // count of outstanding acquired messages - PositionFifo members; // msgs belonging to this group - - GroupState() : acquired(0) {} - bool owned() const {return !owner.empty();} - }; - typedef std::map<std::string, struct GroupState> GroupMap; - typedef std::map<framing::SequenceNumber, struct GroupState *> GroupFifo; - - GroupMap messageGroups; // index: group name - GroupFifo freeGroups; // ordered by oldest free msg - //Consumers consumers; // index: consumer name - - static const std::string qpidMessageGroupKey; - static const std::string qpidSharedGroup; // if specified, one group can be consumed by multiple receivers - static const std::string qpidMessageGroupTimestamp; - - const std::string getGroupId( const QueuedMessage& qm ) const; - void unFree( const GroupState& state ); - void own( GroupState& state, const std::string& owner ); - void disown( GroupState& state ); - - public: - - static QPID_BROKER_EXTERN void setDefaults(const std::string& groupId); - static boost::shared_ptr<MessageGroupManager> create( const std::string& qName, - Messages& messages, - const qpid::framing::FieldTable& settings ); - - MessageGroupManager(const std::string& header, const std::string& _qName, - Messages& container, unsigned int _timestamp=0 ) - : StatefulQueueObserver(std::string("MessageGroupManager:") + header), - groupIdHeader( header ), timestamp(_timestamp), messages(container), qName(_qName) {} - - // QueueObserver iface - void enqueued( const QueuedMessage& qm ); - void acquired( const QueuedMessage& qm ); - void requeued( const QueuedMessage& qm ); - void dequeued( const QueuedMessage& qm ); - void consumerAdded( const Consumer& ) {}; - void consumerRemoved( const Consumer& ) {}; - void getState(qpid::framing::FieldTable& state ) const; - void setState(const qpid::framing::FieldTable&); - - // MessageDistributor iface - bool nextConsumableMessage(Consumer::shared_ptr& c, QueuedMessage& next); - bool allocate(const std::string& c, const QueuedMessage& qm); - bool nextBrowsableMessage(Consumer::shared_ptr& c, QueuedMessage& next); - void query(qpid::types::Variant::Map&) const; - - bool match(const qpid::types::Variant::Map*, const QueuedMessage&) const; -}; - -}} - -#endif diff --git a/cpp/src/qpid/broker/Messages.h b/cpp/src/qpid/broker/Messages.h index 448f17432a..0d75417640 100644 --- a/cpp/src/qpid/broker/Messages.h +++ b/cpp/src/qpid/broker/Messages.h @@ -32,8 +32,7 @@ struct QueuedMessage; /** * This interface abstracts out the access to the messages held for - * delivery by a Queue instance. Note the the assumption at present is - * that all locking is done in the Queue itself. + * delivery by a Queue instance. */ class Messages { @@ -76,6 +75,7 @@ class Messages * @return true if there is another message, false otherwise. */ virtual bool next(const framing::SequenceNumber&, QueuedMessage&) = 0; + /** * Note: Caller is responsible for ensuring that there is a front * (e.g. empty() returns false) diff --git a/cpp/src/qpid/broker/NullMessageStore.cpp b/cpp/src/qpid/broker/NullMessageStore.cpp index 43f600eaf1..dc8615d58b 100644 --- a/cpp/src/qpid/broker/NullMessageStore.cpp +++ b/cpp/src/qpid/broker/NullMessageStore.cpp @@ -126,25 +126,21 @@ std::auto_ptr<TPCTransactionContext> NullMessageStore::begin(const std::string& void NullMessageStore::prepare(TPCTransactionContext& ctxt) { - qpid::sys::ScopedLock<qpid::sys::Mutex> l(lock); prepared.insert(DummyCtxt::getXid(ctxt)); } void NullMessageStore::commit(TransactionContext& ctxt) { - qpid::sys::ScopedLock<qpid::sys::Mutex> l(lock); prepared.erase(DummyCtxt::getXid(ctxt)); } void NullMessageStore::abort(TransactionContext& ctxt) { - qpid::sys::ScopedLock<qpid::sys::Mutex> l(lock); prepared.erase(DummyCtxt::getXid(ctxt)); } void NullMessageStore::collectPreparedXids(std::set<std::string>& out) { - qpid::sys::ScopedLock<qpid::sys::Mutex> l(lock); out.insert(prepared.begin(), prepared.end()); } diff --git a/cpp/src/qpid/broker/NullMessageStore.h b/cpp/src/qpid/broker/NullMessageStore.h index c6f402662e..e148ec4d51 100644 --- a/cpp/src/qpid/broker/NullMessageStore.h +++ b/cpp/src/qpid/broker/NullMessageStore.h @@ -25,7 +25,6 @@ #include "qpid/broker/BrokerImportExport.h" #include "qpid/broker/MessageStore.h" #include "qpid/broker/Queue.h" -#include "qpid/sys/Mutex.h" #include <boost/intrusive_ptr.hpp> @@ -35,11 +34,10 @@ namespace broker { /** * A null implementation of the MessageStore interface */ -class QPID_BROKER_CLASS_EXTERN NullMessageStore : public MessageStore +class NullMessageStore : public MessageStore { std::set<std::string> prepared; uint64_t nextPersistenceId; - qpid::sys::Mutex lock; public: QPID_BROKER_EXTERN NullMessageStore(); diff --git a/cpp/src/qpid/broker/PersistableMessage.cpp b/cpp/src/qpid/broker/PersistableMessage.cpp index 7ba28eb293..e5fbb71cbd 100644 --- a/cpp/src/qpid/broker/PersistableMessage.cpp +++ b/cpp/src/qpid/broker/PersistableMessage.cpp @@ -34,6 +34,7 @@ class MessageStore; PersistableMessage::~PersistableMessage() {} PersistableMessage::PersistableMessage() : + asyncEnqueueCounter(0), asyncDequeueCounter(0), store(0) {} @@ -67,6 +68,24 @@ bool PersistableMessage::isContentReleased() const return contentReleaseState.released; } +bool PersistableMessage::isEnqueueComplete() { + sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock); + return asyncEnqueueCounter == 0; +} + +void PersistableMessage::enqueueComplete() { + bool notify = false; + { + sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock); + if (asyncEnqueueCounter > 0) { + if (--asyncEnqueueCounter == 0) { + notify = true; + } + } + } + if (notify) + allEnqueuesComplete(); +} bool PersistableMessage::isStoredOnQueue(PersistableQueue::shared_ptr queue){ if (store && (queue->getPersistenceId()!=0)) { @@ -90,7 +109,12 @@ void PersistableMessage::addToSyncList(PersistableQueue::shared_ptr queue, Messa void PersistableMessage::enqueueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store) { addToSyncList(queue, _store); - enqueueStart(); + enqueueAsync(); +} + +void PersistableMessage::enqueueAsync() { + sys::ScopedLock<sys::Mutex> l(asyncEnqueueLock); + asyncEnqueueCounter++; } bool PersistableMessage::isDequeueComplete() { diff --git a/cpp/src/qpid/broker/PersistableMessage.h b/cpp/src/qpid/broker/PersistableMessage.h index d29c2c45b4..96fb922c1a 100644 --- a/cpp/src/qpid/broker/PersistableMessage.h +++ b/cpp/src/qpid/broker/PersistableMessage.h @@ -31,7 +31,6 @@ #include "qpid/framing/amqp_types.h" #include "qpid/sys/Mutex.h" #include "qpid/broker/PersistableQueue.h" -#include "qpid/broker/AsyncCompletion.h" namespace qpid { namespace broker { @@ -44,19 +43,18 @@ class MessageStore; class PersistableMessage : public Persistable { typedef std::list< boost::weak_ptr<PersistableQueue> > syncList; + sys::Mutex asyncEnqueueLock; sys::Mutex asyncDequeueLock; sys::Mutex storeLock; - + /** - * "Ingress" messages == messages sent _to_ the broker. - * Tracks the number of outstanding asynchronous operations that must - * complete before an inbound message can be considered fully received by the - * broker. E.g. all enqueues have completed, the message has been written - * to store, credit has been replenished, etc. Once all outstanding - * operations have completed, the transfer of this message from the client - * may be considered complete. + * Tracks the number of outstanding asynchronous enqueue + * operations. When the message is enqueued asynchronously the + * count is incremented; when that enqueue completes it is + * decremented. Thus when it is 0, there are no outstanding + * enqueues. */ - AsyncCompletion ingressCompletion; + int asyncEnqueueCounter; /** * Tracks the number of outstanding asynchronous dequeue @@ -67,6 +65,7 @@ class PersistableMessage : public Persistable */ int asyncDequeueCounter; + void enqueueAsync(); void dequeueAsync(); syncList synclist; @@ -81,6 +80,8 @@ class PersistableMessage : public Persistable ContentReleaseState contentReleaseState; protected: + /** Called when all enqueues are complete for this message. */ + virtual void allEnqueuesComplete() = 0; /** Called when all dequeues are complete for this message. */ virtual void allDequeuesComplete() = 0; @@ -114,12 +115,9 @@ class PersistableMessage : public Persistable virtual QPID_BROKER_EXTERN bool isPersistent() const = 0; - /** track the progress of a message received by the broker - see ingressCompletion above */ - QPID_BROKER_INLINE_EXTERN bool isIngressComplete() { return ingressCompletion.isDone(); } - QPID_BROKER_INLINE_EXTERN AsyncCompletion& getIngressCompletion() { return ingressCompletion; } + QPID_BROKER_EXTERN bool isEnqueueComplete(); - QPID_BROKER_INLINE_EXTERN void enqueueStart() { ingressCompletion.startCompleter(); } - QPID_BROKER_INLINE_EXTERN void enqueueComplete() { ingressCompletion.finishCompleter(); } + QPID_BROKER_EXTERN void enqueueComplete(); QPID_BROKER_EXTERN void enqueueAsync(PersistableQueue::shared_ptr queue, MessageStore* _store); @@ -135,6 +133,7 @@ class PersistableMessage : public Persistable bool isStoredOnQueue(PersistableQueue::shared_ptr queue); void addToSyncList(PersistableQueue::shared_ptr queue, MessageStore* _store); + }; }} diff --git a/cpp/src/qpid/broker/Queue.cpp b/cpp/src/qpid/broker/Queue.cpp index 4627b1409a..27c1cc4ad7 100644 --- a/cpp/src/qpid/broker/Queue.cpp +++ b/cpp/src/qpid/broker/Queue.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -31,10 +31,7 @@ #include "qpid/broker/MessageStore.h" #include "qpid/broker/NullMessageStore.h" #include "qpid/broker/QueueRegistry.h" -#include "qpid/broker/QueueFlowLimit.h" #include "qpid/broker/ThresholdAlerts.h" -#include "qpid/broker/FifoDistributor.h" -#include "qpid/broker/MessageGroupManager.h" #include "qpid/StringUtils.h" #include "qpid/log/Statement.h" @@ -44,7 +41,6 @@ #include "qpid/sys/ClusterSafe.h" #include "qpid/sys/Monitor.h" #include "qpid/sys/Time.h" -#include "qpid/types/Variant.h" #include "qmf/org/apache/qpid/broker/ArgsQueuePurge.h" #include "qmf/org/apache/qpid/broker/ArgsQueueReroute.h" @@ -68,7 +64,7 @@ using std::mem_fun; namespace _qmf = qmf::org::apache::qpid::broker; -namespace +namespace { const std::string qpidMaxSize("qpid.max_size"); const std::string qpidMaxCount("qpid.max_count"); @@ -90,16 +86,16 @@ const int ENQUEUE_ONLY=1; const int ENQUEUE_AND_DEQUEUE=2; } -Queue::Queue(const string& _name, bool _autodelete, +Queue::Queue(const string& _name, bool _autodelete, MessageStore* const _store, const OwnershipToken* const _owner, Manageable* parent, Broker* b) : - name(_name), + name(_name), autodelete(_autodelete), store(_store), - owner(_owner), + owner(_owner), consumerCount(0), exclusive(0), noLocal(false), @@ -114,8 +110,7 @@ Queue::Queue(const string& _name, bool _autodelete, broker(b), deleted(false), barrier(*this), - autoDeleteTimeout(0), - allocator(new FifoDistributor( *messages )) + autoDeleteTimeout(0) { if (parent != 0 && broker != 0) { ManagementAgent* agent = broker->getManagementAgent(); @@ -168,8 +163,13 @@ void Queue::deliver(boost::intrusive_ptr<Message> msg){ //drop message QPID_LOG(info, "Dropping excluded message from " << getName()); } else { - enqueue(0, msg); - push(msg); + // if no store then mark as enqueued + if (!enqueue(0, msg)){ + push(msg); + msg->enqueueComplete(); + }else { + push(msg); + } QPID_LOG(debug, "Message " << msg << " enqueued on " << name); } } @@ -183,10 +183,11 @@ void Queue::recover(boost::intrusive_ptr<Message>& msg){ if (policy.get()) policy->recoverEnqueued(msg); push(msg, true); - if (store){ + if (store){ // setup synclist for recovered messages, so they don't get re-stored on lastNodeFailure - msg->addToSyncList(shared_from_this(), store); + msg->addToSyncList(shared_from_this(), store); } + msg->enqueueComplete(); // mark the message as enqueued if (store && (!msg->isContentLoaded() || msg->checkContentReleasable())) { //content has not been loaded, need to ensure that lazy loading mode is set: @@ -210,13 +211,14 @@ void Queue::process(boost::intrusive_ptr<Message>& msg){ void Queue::requeue(const QueuedMessage& msg){ assertClusterSafe(); QueueListeners::NotificationSet copy; - { + { Mutex::ScopedLock locker(messageLock); if (!isEnqueued(msg)) return; + msg.payload->enqueueComplete(); // mark the message as enqueued messages->reinsert(msg); listeners.populate(copy); - // for persistLastNode - don't force a message twice to disk, but force it if no force before + // for persistLastNode - don't force a message twice to disk, but force it if no force before if(inLastNodeFailure && persistLastNode && !msg.payload->isStoredOnQueue(shared_from_this())) { msg.payload->forcePersistent(); if (msg.payload->isForcedPersistent() ){ @@ -224,17 +226,16 @@ void Queue::requeue(const QueuedMessage& msg){ enqueue(0, payload); } } - observeRequeue(msg, locker); } copy.notify(); } -bool Queue::acquireMessageAt(const SequenceNumber& position, QueuedMessage& message) +bool Queue::acquireMessageAt(const SequenceNumber& position, QueuedMessage& message) { Mutex::ScopedLock locker(messageLock); assertClusterSafe(); QPID_LOG(debug, "Attempting to acquire message at " << position); - if (acquire(position, message, locker)) { + if (messages->remove(position, message)) { QPID_LOG(debug, "Acquired message at " << position << " from " << name); return true; } else { @@ -243,24 +244,9 @@ bool Queue::acquireMessageAt(const SequenceNumber& position, QueuedMessage& mess } } -bool Queue::acquire(const QueuedMessage& msg, const std::string& consumer) -{ - Mutex::ScopedLock locker(messageLock); - assertClusterSafe(); - QPID_LOG(debug, consumer << " attempting to acquire message at " << msg.position); - - if (!allocator->allocate( consumer, msg )) { - QPID_LOG(debug, "Not permitted to acquire msg at " << msg.position << " from '" << name); - return false; - } - - QueuedMessage copy(msg); - if (acquire( msg.position, copy, locker)) { - QPID_LOG(debug, "Acquired message at " << msg.position << " from " << name); - return true; - } - QPID_LOG(debug, "Could not acquire message at " << msg.position << " from " << name << "; no message at that position"); - return false; +bool Queue::acquire(const QueuedMessage& msg) { + QueuedMessage copy = msg; + return acquireMessageAt(msg.position, copy); } void Queue::notifyListener() @@ -276,7 +262,7 @@ void Queue::notifyListener() set.notify(); } -bool Queue::getNextMessage(QueuedMessage& m, Consumer::shared_ptr& c) +bool Queue::getNextMessage(QueuedMessage& m, Consumer::shared_ptr c) { checkNotDeleted(); if (c->preAcquires()) { @@ -288,71 +274,52 @@ bool Queue::getNextMessage(QueuedMessage& m, Consumer::shared_ptr& c) case NO_MESSAGES: default: return false; - } + } } else { return browseNextMessage(m, c); } } -Queue::ConsumeCode Queue::consumeNextMessage(QueuedMessage& m, Consumer::shared_ptr& c) +Queue::ConsumeCode Queue::consumeNextMessage(QueuedMessage& m, Consumer::shared_ptr c) { while (true) { Mutex::ScopedLock locker(messageLock); - QueuedMessage msg; - - if (!allocator->nextConsumableMessage(c, msg)) { // no next available - QPID_LOG(debug, "No messages available to dispatch to consumer " << - c->getName() << " on queue '" << name << "'"); + if (messages->empty()) { + QPID_LOG(debug, "No messages to dispatch on queue '" << name << "'"); listeners.addListener(c); return NO_MESSAGES; - } - - if (msg.payload->hasExpired()) { - QPID_LOG(debug, "Message expired from queue '" << name << "'"); - c->position = msg.position; - acquire( msg.position, msg, locker); - dequeue( 0, msg ); - continue; - } - - // a message is available for this consumer - can the consumer use it? + } else { + QueuedMessage msg = messages->front(); + if (msg.payload->hasExpired()) { + QPID_LOG(debug, "Message expired from queue '" << name << "'"); + popAndDequeue(); + continue; + } - if (c->filter(msg.payload)) { - if (c->accept(msg.payload)) { - bool ok = allocator->allocate( c->getName(), msg ); // inform allocator - (void) ok; assert(ok); - ok = acquire( msg.position, msg, locker); - (void) ok; assert(ok); - m = msg; - c->position = m.position; - return CONSUMED; + if (c->filter(msg.payload)) { + if (c->accept(msg.payload)) { + m = msg; + pop(); + return CONSUMED; + } else { + //message(s) are available but consumer hasn't got enough credit + QPID_LOG(debug, "Consumer can't currently accept message from '" << name << "'"); + return CANT_CONSUME; + } } else { - //message(s) are available but consumer hasn't got enough credit - QPID_LOG(debug, "Consumer can't currently accept message from '" << name << "'"); + //consumer will never want this message + QPID_LOG(debug, "Consumer doesn't want message from '" << name << "'"); return CANT_CONSUME; - } - } else { - //consumer will never want this message - QPID_LOG(debug, "Consumer doesn't want message from '" << name << "'"); - c->position = msg.position; - return CANT_CONSUME; + } } } } -bool Queue::browseNextMessage(QueuedMessage& m, Consumer::shared_ptr& c) -{ - while (true) { - Mutex::ScopedLock locker(messageLock); - QueuedMessage msg; - - if (!allocator->nextBrowsableMessage(c, msg)) { // no next available - QPID_LOG(debug, "No browsable messages available for consumer " << - c->getName() << " on queue '" << name << "'"); - listeners.addListener(c); - return false; - } +bool Queue::browseNextMessage(QueuedMessage& m, Consumer::shared_ptr c) +{ + QueuedMessage msg(this); + while (seek(msg, c)) { if (c->filter(msg.payload) && !msg.payload->hasExpired()) { if (c->accept(msg.payload)) { //consumer wants the message @@ -366,8 +333,8 @@ bool Queue::browseNextMessage(QueuedMessage& m, Consumer::shared_ptr& c) } } else { //consumer will never want this message, continue seeking - QPID_LOG(debug, "Browser skipping message from '" << name << "'"); c->position = msg.position; + QPID_LOG(debug, "Browser skipping message from '" << name << "'"); } } return false; @@ -397,71 +364,61 @@ bool Queue::dispatch(Consumer::shared_ptr c) } } -bool Queue::find(SequenceNumber pos, QueuedMessage& msg) const { - +// Find the next message +bool Queue::seek(QueuedMessage& msg, Consumer::shared_ptr c) { Mutex::ScopedLock locker(messageLock); - if (messages->find(pos, msg)) + if (messages->next(c->position, msg)) { return true; - return false; + } else { + listeners.addListener(c); + return false; + } +} + +QueuedMessage Queue::find(SequenceNumber pos) const { + + Mutex::ScopedLock locker(messageLock); + QueuedMessage msg; + messages->find(pos, msg); + return msg; } void Queue::consume(Consumer::shared_ptr c, bool requestExclusive){ assertClusterSafe(); - { - Mutex::ScopedLock locker(consumerLock); - if(exclusive) { + Mutex::ScopedLock locker(consumerLock); + if(exclusive) { + throw ResourceLockedException( + QPID_MSG("Queue " << getName() << " has an exclusive consumer. No more consumers allowed.")); + } else if(requestExclusive) { + if(consumerCount) { throw ResourceLockedException( - QPID_MSG("Queue " << getName() << " has an exclusive consumer. No more consumers allowed.")); - } else if(requestExclusive) { - if(consumerCount) { - throw ResourceLockedException( - QPID_MSG("Queue " << getName() << " already has consumers. Exclusive access denied.")); - } else { - exclusive = c->getSession(); - } - } - consumerCount++; - if (mgmtObject != 0) - mgmtObject->inc_consumerCount (); - //reset auto deletion timer if necessary - if (autoDeleteTimeout && autoDeleteTask) { - autoDeleteTask->cancel(); + QPID_MSG("Queue " << getName() << " already has consumers. Exclusive access denied.")); + } else { + exclusive = c->getSession(); } } - Mutex::ScopedLock locker(messageLock); - for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) { - try{ - (*i)->consumerAdded(*c); - } catch (const std::exception& e) { - QPID_LOG(warning, "Exception on notification of new consumer for queue " << getName() << ": " << e.what()); - } + consumerCount++; + if (mgmtObject != 0) + mgmtObject->inc_consumerCount (); + //reset auto deletion timer if necessary + if (autoDeleteTimeout && autoDeleteTask) { + autoDeleteTask->cancel(); } } void Queue::cancel(Consumer::shared_ptr c){ removeListener(c); - { - Mutex::ScopedLock locker(consumerLock); - consumerCount--; - if(exclusive) exclusive = 0; - if (mgmtObject != 0) - mgmtObject->dec_consumerCount (); - } - Mutex::ScopedLock locker(messageLock); - for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) { - try{ - (*i)->consumerRemoved(*c); - } catch (const std::exception& e) { - QPID_LOG(warning, "Exception on notification of removed consumer for queue " << getName() << ": " << e.what()); - } - } + Mutex::ScopedLock locker(consumerLock); + consumerCount--; + if(exclusive) exclusive = 0; + if (mgmtObject != 0) + mgmtObject->dec_consumerCount (); } QueuedMessage Queue::get(){ Mutex::ScopedLock locker(messageLock); QueuedMessage msg(this); - if (messages->pop(msg)) - observeAcquire(msg, locker); + messages->pop(msg); return msg; } @@ -475,135 +432,22 @@ bool collect_if_expired(std::deque<QueuedMessage>& expired, QueuedMessage& messa } } -/** - *@param lapse: time since the last purgeExpired - */ -void Queue::purgeExpired(qpid::sys::Duration lapse) +void Queue::purgeExpired() { //As expired messages are discarded during dequeue also, only //bother explicitly expiring if the rate of dequeues since last - //attempt is less than one per second. - int count = dequeueSincePurge.get(); - dequeueSincePurge -= count; - int seconds = int64_t(lapse)/qpid::sys::TIME_SEC; - if (seconds == 0 || count / seconds < 1) { + //attempt is less than one per second. + + if (dequeueTracker.sampleRatePerSecond() < 1) { std::deque<QueuedMessage> expired; { Mutex::ScopedLock locker(messageLock); - messages->removeIf(boost::bind(&collect_if_expired, boost::ref(expired), _1)); - } - - for (std::deque<QueuedMessage>::const_iterator i = expired.begin(); - i != expired.end(); ++i) { - { - Mutex::ScopedLock locker(messageLock); - observeAcquire(*i, locker); - } - dequeue( 0, *i ); + messages->removeIf(boost::bind(&collect_if_expired, expired, _1)); } + for_each(expired.begin(), expired.end(), bind(&Queue::dequeue, this, (TransactionContext*) 0, _1)); } } - -namespace { - // for use with purge/move below - collect messages that match a given filter - // - class MessageFilter - { - public: - static const std::string typeKey; - static const std::string paramsKey; - static MessageFilter *create( const ::qpid::types::Variant::Map *filter ); - virtual bool match( const QueuedMessage& ) const { return true; } - virtual ~MessageFilter() {} - protected: - MessageFilter() {}; - }; - const std::string MessageFilter::typeKey("filter_type"); - const std::string MessageFilter::paramsKey("filter_params"); - - // filter by message header string value exact match - class HeaderMatchFilter : public MessageFilter - { - public: - /* Config: - { 'filter_type' : 'header_match_str', - 'filter_params' : { 'header_key' : "<header name>", - 'header_value' : "<value to match>" - } - } - */ - static const std::string typeKey; - static const std::string headerKey; - static const std::string valueKey; - HeaderMatchFilter( const std::string& _header, const std::string& _value ) - : MessageFilter (), header(_header), value(_value) {} - bool match( const QueuedMessage& msg ) const - { - const qpid::framing::FieldTable* headers = msg.payload->getApplicationHeaders(); - if (!headers) return false; - FieldTable::ValuePtr h = headers->get(header); - if (!h || !h->convertsTo<std::string>()) return false; - return h->get<std::string>() == value; - } - private: - const std::string header; - const std::string value; - }; - const std::string HeaderMatchFilter::typeKey("header_match_str"); - const std::string HeaderMatchFilter::headerKey("header_key"); - const std::string HeaderMatchFilter::valueKey("header_value"); - - // factory to create correct filter based on map - MessageFilter* MessageFilter::create( const ::qpid::types::Variant::Map *filter ) - { - using namespace qpid::types; - if (filter && !filter->empty()) { - Variant::Map::const_iterator i = filter->find(MessageFilter::typeKey); - if (i != filter->end()) { - - if (i->second.asString() == HeaderMatchFilter::typeKey) { - Variant::Map::const_iterator p = filter->find(MessageFilter::paramsKey); - if (p != filter->end() && p->second.getType() == VAR_MAP) { - Variant::Map::const_iterator k = p->second.asMap().find(HeaderMatchFilter::headerKey); - Variant::Map::const_iterator v = p->second.asMap().find(HeaderMatchFilter::valueKey); - if (k != p->second.asMap().end() && v != p->second.asMap().end()) { - std::string headerKey(k->second.asString()); - std::string value(v->second.asString()); - QPID_LOG(debug, "Message filtering by header value configured. key: " << headerKey << " value: " << value ); - return new HeaderMatchFilter( headerKey, value ); - } - } - } - } - QPID_LOG(error, "Ignoring unrecognized message filter: '" << *filter << "'"); - } - return new MessageFilter(); - } - - // used by removeIf() to collect all messages matching a filter, maximum match count is - // optional. - struct Collector { - const uint32_t maxMatches; - MessageFilter& filter; - std::deque<QueuedMessage> matches; - Collector(MessageFilter& filter, uint32_t max) - : maxMatches(max), filter(filter) {} - bool operator() (QueuedMessage& qm) - { - if (maxMatches == 0 || matches.size() < maxMatches) { - if (filter.match( qm )) { - matches.push_back(qm); - return true; - } - } - return false; - } - }; - -} // end namespace - - /** * purge - for purging all or some messages on a queue * depending on the purge_request @@ -615,77 +459,63 @@ namespace { * The dest exchange may be supplied to re-route messages through the exchange. * It is safe to re-route messages such that they arrive back on the same queue, * even if the queue is ordered by priority. - * - * An optional filter can be supplied that will be applied against each message. The - * message is purged only if the filter matches. See MessageDistributor for more detail. */ -uint32_t Queue::purge(const uint32_t purge_request, boost::shared_ptr<Exchange> dest, - const qpid::types::Variant::Map *filter) +uint32_t Queue::purge(const uint32_t purge_request, boost::shared_ptr<Exchange> dest) { - std::auto_ptr<MessageFilter> mf(MessageFilter::create(filter)); - Collector c(*mf.get(), purge_request); - Mutex::ScopedLock locker(messageLock); - messages->removeIf( boost::bind<bool>(boost::ref(c), _1) ); - for (std::deque<QueuedMessage>::iterator qmsg = c.matches.begin(); - qmsg != c.matches.end(); ++qmsg) { - // Update observers and message state: - observeAcquire(*qmsg, locker); - dequeue(0, *qmsg); - // now reroute if necessary + uint32_t purge_count = purge_request; // only comes into play if >0 + std::deque<DeliverableMessage> rerouteQueue; + + uint32_t count = 0; + // Either purge them all or just the some (purge_count) while the queue isn't empty. + while((!purge_request || purge_count--) && !messages->empty()) { if (dest.get()) { - assert(qmsg->payload); - DeliverableMessage dmsg(qmsg->payload); - dest->routeWithAlternate(dmsg); + // + // If there is a destination exchange, stage the messages onto a reroute queue + // so they don't wind up getting purged more than once. + // + DeliverableMessage msg(messages->front().payload); + rerouteQueue.push_back(msg); } + popAndDequeue(); + count++; } - return c.matches.size(); -} - -uint32_t Queue::move(const Queue::shared_ptr destq, uint32_t qty, - const qpid::types::Variant::Map *filter) -{ - std::auto_ptr<MessageFilter> mf(MessageFilter::create(filter)); - Collector c(*mf.get(), qty); - Mutex::ScopedLock locker(messageLock); - messages->removeIf( boost::bind<bool>(boost::ref(c), _1) ); - - for (std::deque<QueuedMessage>::iterator qmsg = c.matches.begin(); - qmsg != c.matches.end(); ++qmsg) { - // Update observers and message state: - observeAcquire(*qmsg, locker); - dequeue(0, *qmsg); - // and move to destination Queue. - assert(qmsg->payload); - destq->deliver(qmsg->payload); + // + // Re-route purged messages into the destination exchange. Note that there's no need + // to test dest.get() here because if it is NULL, the rerouteQueue will be empty. + // + while (!rerouteQueue.empty()) { + DeliverableMessage msg(rerouteQueue.front()); + rerouteQueue.pop_front(); + dest->route(msg, msg.getMessage().getRoutingKey(), + msg.getMessage().getApplicationHeaders()); } - return c.matches.size(); + + return count; } -/** Acquire the front (oldest) message from the in-memory queue. - * assumes messageLock held by caller - */ -void Queue::pop(const Mutex::ScopedLock& locker) -{ - assertClusterSafe(); - QueuedMessage msg; - if (messages->pop(msg)) { - observeAcquire(msg, locker); - ++dequeueSincePurge; +uint32_t Queue::move(const Queue::shared_ptr destq, uint32_t qty) { + Mutex::ScopedLock locker(messageLock); + uint32_t move_count = qty; // only comes into play if qty >0 + uint32_t count = 0; // count how many were moved for returning + + while((!qty || move_count--) && !messages->empty()) { + QueuedMessage qmsg = messages->front(); + boost::intrusive_ptr<Message> msg = qmsg.payload; + destq->deliver(msg); // deliver message to the destination queue + pop(); + dequeue(0, qmsg); + count++; } + return count; } -/** Acquire the message at the given position, return true and msg if acquire succeeds */ -bool Queue::acquire(const qpid::framing::SequenceNumber& position, QueuedMessage& msg, - const Mutex::ScopedLock& locker) +void Queue::pop() { - if (messages->remove(position, msg)) { - observeAcquire(msg, locker); - ++dequeueSincePurge; - return true; - } - return false; + assertClusterSafe(); + messages->pop(); + ++dequeueTracker; } void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){ @@ -694,15 +524,13 @@ void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){ QueuedMessage removed; bool dequeueRequired = false; { - Mutex::ScopedLock locker(messageLock); + Mutex::ScopedLock locker(messageLock); QueuedMessage qm(this, msg, ++sequence); - if (insertSeqNo) msg->insertCustomProperty(seqNoKey, sequence); - + if (insertSeqNo) msg->getOrInsertHeaders().setInt64(seqNoKey, sequence); + dequeueRequired = messages->push(qm, removed); - if (dequeueRequired) - observeAcquire(removed, locker); listeners.populate(copy); - observeEnqueue(qm, locker); + enqueued(qm); } copy.notify(); if (dequeueRequired) { @@ -718,7 +546,7 @@ void Queue::push(boost::intrusive_ptr<Message>& msg, bool isRecovery){ void isEnqueueComplete(uint32_t* result, const QueuedMessage& message) { - if (message.payload->isIngressComplete()) (*result)++; + if (message.payload->isEnqueueComplete()) (*result)++; } /** function only provided for unit tests, or code not in critical message path */ @@ -778,7 +606,7 @@ void Queue::setLastNodeFailure() } -// return true if store exists, +// return true if store exists, bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg, bool suppressPolicyCheck) { ScopedUse u(barrier); @@ -792,21 +620,24 @@ bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg policy->getPendingDequeues(dequeues); } //depending on policy, may have some dequeues that need to performed without holding the lock - for_each(dequeues.begin(), dequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1)); + for_each(dequeues.begin(), dequeues.end(), boost::bind(&Queue::dequeue, this, (TransactionContext*) 0, _1)); } if (inLastNodeFailure && persistLastNode){ msg->forcePersistent(); } - + if (traceId.size()) { + //copy on write: take deep copy of message before modifying it + //as the frames may already be available for delivery on other + //threads + boost::intrusive_ptr<Message> copy(new Message(*msg)); + msg = copy; msg->addTraceId(traceId); } if ((msg->isPersistent() || msg->checkContentReleasable()) && store) { - // mark the message as being enqueued - the store MUST CALL msg->enqueueComplete() - // when it considers the message stored. - msg->enqueueAsync(shared_from_this(), store); + 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); return true; @@ -823,10 +654,10 @@ bool Queue::enqueue(TransactionContext* ctxt, boost::intrusive_ptr<Message>& msg void Queue::enqueueAborted(boost::intrusive_ptr<Message> msg) { Mutex::ScopedLock locker(messageLock); - if (policy.get()) policy->enqueueAborted(msg); + if (policy.get()) policy->enqueueAborted(msg); } -// return true if store exists, +// return true if store exists, bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg) { ScopedUse u(barrier); @@ -835,8 +666,8 @@ bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg) { Mutex::ScopedLock locker(messageLock); if (!isEnqueued(msg)) return false; - if (!ctxt) { - observeDequeue(msg, locker); + if (!ctxt) { + dequeued(msg); } } // This check prevents messages which have been forced persistent on one queue from dequeuing @@ -856,7 +687,7 @@ bool Queue::dequeue(TransactionContext* ctxt, const QueuedMessage& msg) void Queue::dequeueCommitted(const QueuedMessage& msg) { Mutex::ScopedLock locker(messageLock); - observeDequeue(msg, locker); + dequeued(msg); if (mgmtObject != 0) { mgmtObject->inc_msgTxnDequeues(); mgmtObject->inc_byteTxnDequeues(msg.payload->contentSize()); @@ -864,23 +695,21 @@ void Queue::dequeueCommitted(const QueuedMessage& msg) } /** - * Removes the first (oldest) message from the in-memory delivery queue as well dequeing - * it from the logical (and persistent if applicable) queue + * Removes a message from the in-memory delivery queue as well + * dequeing it from the logical (and persistent if applicable) queue */ -void Queue::popAndDequeue(const Mutex::ScopedLock& held) +void Queue::popAndDequeue() { - if (!messages->empty()) { - QueuedMessage msg = messages->front(); - pop(held); - dequeue(0, msg); - } + QueuedMessage msg = messages->front(); + pop(); + dequeue(0, msg); } /** * Updates policy and management when a message has been dequeued, * expects messageLock to be held */ -void Queue::observeDequeue(const QueuedMessage& msg, const Mutex::ScopedLock&) +void Queue::dequeued(const QueuedMessage& msg) { if (policy.get()) policy->dequeued(msg); mgntDeqStats(msg.payload); @@ -893,33 +722,6 @@ void Queue::observeDequeue(const QueuedMessage& msg, const Mutex::ScopedLock&) } } -/** updates queue observers when a message has become unavailable for transfer, - * expects messageLock to be held - */ -void Queue::observeAcquire(const QueuedMessage& msg, const Mutex::ScopedLock&) -{ - for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) { - try{ - (*i)->acquired(msg); - } catch (const std::exception& e) { - QPID_LOG(warning, "Exception on notification of message removal for queue " << getName() << ": " << e.what()); - } - } -} - -/** updates queue observers when a message has become re-available for transfer, - * expects messageLock to be held - */ -void Queue::observeRequeue(const QueuedMessage& msg, const Mutex::ScopedLock&) -{ - for (Observers::const_iterator i = observers.begin(); i != observers.end(); ++i) { - try{ - (*i)->requeued(msg); - } catch (const std::exception& e) { - QPID_LOG(warning, "Exception on notification of message requeue for queue " << getName() << ": " << e.what()); - } - } -} void Queue::create(const FieldTable& _settings) { @@ -927,7 +729,7 @@ void Queue::create(const FieldTable& _settings) if (store) { store->create(*this, _settings); } - configureImpl(_settings); + configure(_settings); } @@ -940,8 +742,8 @@ int getIntegerSetting(const qpid::framing::FieldTable& settings, const std::stri return v->get<int>(); } else if (v->convertsTo<std::string>()){ std::string s = v->get<std::string>(); - try { - return boost::lexical_cast<int>(s); + try { + return boost::lexical_cast<int>(s); } catch(const boost::bad_lexical_cast&) { QPID_LOG(warning, "Ignoring invalid integer value for " << key << ": " << s); return 0; @@ -952,45 +754,15 @@ int getIntegerSetting(const qpid::framing::FieldTable& settings, const std::stri } } -bool getBoolSetting(const qpid::framing::FieldTable& settings, const std::string& key) +void Queue::configure(const FieldTable& _settings, bool recovering) { - qpid::framing::FieldTable::ValuePtr v = settings.get(key); - if (!v) { - return false; - } else if (v->convertsTo<int>()) { - return v->get<int>() != 0; - } else if (v->convertsTo<std::string>()){ - std::string s = v->get<std::string>(); - if (s == "True") return true; - if (s == "true") return true; - if (s == "False") return false; - if (s == "false") return false; - try { - return boost::lexical_cast<bool>(s); - } catch(const boost::bad_lexical_cast&) { - QPID_LOG(warning, "Ignoring invalid boolean value for " << key << ": " << s); - return false; - } - } else { - QPID_LOG(warning, "Ignoring invalid boolean value for " << key << ": " << *v); - return false; - } -} - -void Queue::configure(const FieldTable& _settings) -{ - settings = _settings; - configureImpl(settings); -} -void Queue::configureImpl(const FieldTable& _settings) -{ eventMode = _settings.getAsInt(qpidQueueEventGeneration); if (eventMode && broker) { broker->getQueueEvents().observe(*this, eventMode == ENQUEUE_ONLY); } - if (QueuePolicy::getType(_settings) == QueuePolicy::FLOW_TO_DISK && + if (QueuePolicy::getType(_settings) == QueuePolicy::FLOW_TO_DISK && (!store || NullMessageStore::isNullStore(store) || (broker && !(broker->getQueueEvents().isSync())) )) { if ( NullMessageStore::isNullStore(store)) { QPID_LOG(warning, "Flow to disk not valid for non-persisted queue:" << getName()); @@ -1004,43 +776,32 @@ void Queue::configureImpl(const FieldTable& _settings) setPolicy(QueuePolicy::createQueuePolicy(getName(), _settings)); } if (broker && broker->getManagementAgent()) { - ThresholdAlerts::observe(*this, *(broker->getManagementAgent()), _settings, broker->getOptions().queueThresholdEventRatio); + ThresholdAlerts::observe(*this, *(broker->getManagementAgent()), _settings); } //set this regardless of owner to allow use of no-local with exclusive consumers also - noLocal = getBoolSetting(_settings, qpidNoLocal); + noLocal = _settings.get(qpidNoLocal); QPID_LOG(debug, "Configured queue " << getName() << " with no-local=" << noLocal); std::string lvqKey = _settings.getAsString(qpidLastValueQueueKey); if (lvqKey.size()) { QPID_LOG(debug, "Configured queue " << getName() << " as Last Value Queue with key " << lvqKey); messages = std::auto_ptr<Messages>(new MessageMap(lvqKey)); - allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *messages )); - } else if (getBoolSetting(_settings, qpidLastValueQueueNoBrowse)) { + } else if (_settings.get(qpidLastValueQueueNoBrowse)) { QPID_LOG(debug, "Configured queue " << getName() << " as Legacy Last Value Queue with 'no-browse' on"); messages = LegacyLVQ::updateOrReplace(messages, qpidVQMatchProperty, true, broker); - allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *messages )); - } else if (getBoolSetting(_settings, qpidLastValueQueue)) { + } else if (_settings.get(qpidLastValueQueue)) { QPID_LOG(debug, "Configured queue " << getName() << " as Legacy Last Value Queue"); messages = LegacyLVQ::updateOrReplace(messages, qpidVQMatchProperty, false, broker); - allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *messages )); } else { std::auto_ptr<Messages> m = Fairshare::create(_settings); if (m.get()) { messages = m; - allocator = boost::shared_ptr<MessageDistributor>(new FifoDistributor( *messages )); QPID_LOG(debug, "Configured queue " << getName() << " as priority queue."); - } else { // default (FIFO) queue type - // override default message allocator if message groups configured. - boost::shared_ptr<MessageGroupManager> mgm(MessageGroupManager::create( getName(), *messages, _settings)); - if (mgm) { - allocator = mgm; - addObserver(mgm); - } } } - - persistLastNode = getBoolSetting(_settings, qpidPersistLastNode); + + persistLastNode= _settings.get(qpidPersistLastNode); if (persistLastNode) QPID_LOG(debug, "Configured queue to Persist data if cluster fails to one node for: " << getName()); traceId = _settings.getAsString(qpidTraceIdentity); @@ -1048,32 +809,32 @@ void Queue::configureImpl(const FieldTable& _settings) if (excludeList.size()) { split(traceExclude, excludeList, ", "); } - QPID_LOG(debug, "Configured queue " << getName() << " with qpid.trace.id='" << traceId + QPID_LOG(debug, "Configured queue " << getName() << " with qpid.trace.id='" << traceId << "' and qpid.trace.exclude='"<< excludeList << "' i.e. " << traceExclude.size() << " elements"); FieldTable::ValuePtr p =_settings.get(qpidInsertSequenceNumbers); if (p && p->convertsTo<std::string>()) insertSequenceNumbers(p->get<std::string>()); autoDeleteTimeout = getIntegerSetting(_settings, qpidAutoDeleteTimeout); - if (autoDeleteTimeout) - QPID_LOG(debug, "Configured queue " << getName() << " with qpid.auto_delete_timeout=" << autoDeleteTimeout); + if (autoDeleteTimeout) + QPID_LOG(debug, "Configured queue " << getName() << " with qpid.auto_delete_timeout=" << autoDeleteTimeout); - if (mgmtObject != 0) { + if (mgmtObject != 0) mgmtObject->set_arguments(ManagementAgent::toMap(_settings)); - } - QueueFlowLimit::observe(*this, _settings); + if ( isDurable() && ! getPersistenceId() && ! recovering ) + store->create(*this, _settings); } -void Queue::destroyed() +void Queue::destroy() { - unbind(broker->getExchanges()); if (alternateExchange.get()) { Mutex::ScopedLock locker(messageLock); while(!messages->empty()){ DeliverableMessage msg(messages->front().payload); - alternateExchange->routeWithAlternate(msg); - popAndDequeue(locker); + alternateExchange->route(msg, msg.getMessage().getRoutingKey(), + msg.getMessage().getApplicationHeaders()); + popAndDequeue(); } alternateExchange->decAlternateUsers(); } @@ -1085,7 +846,6 @@ void Queue::destroyed() store = 0;//ensure we make no more calls to the store for this queue } if (autoDeleteTask) autoDeleteTask = boost::intrusive_ptr<TimerTask>(); - notifyDeleted(); } void Queue::notifyDeleted() @@ -1105,9 +865,9 @@ void Queue::bound(const string& exchange, const string& key, bindings.add(exchange, key, args); } -void Queue::unbind(ExchangeRegistry& exchanges) +void Queue::unbind(ExchangeRegistry& exchanges, Queue::shared_ptr shared_ref) { - bindings.unbind(exchanges, shared_from_this()); + bindings.unbind(exchanges, shared_ref); } void Queue::setPolicy(std::auto_ptr<QueuePolicy> _policy) @@ -1120,9 +880,9 @@ const QueuePolicy* Queue::getPolicy() return policy.get(); } -uint64_t Queue::getPersistenceId() const -{ - return persistenceId; +uint64_t Queue::getPersistenceId() const +{ + return persistenceId; } void Queue::setPersistenceId(uint64_t _persistenceId) const @@ -1136,11 +896,11 @@ void Queue::setPersistenceId(uint64_t _persistenceId) const persistenceId = _persistenceId; } -void Queue::encode(Buffer& buffer) const +void Queue::encode(Buffer& buffer) const { buffer.putShortString(name); buffer.put(settings); - if (policy.get()) { + if (policy.get()) { buffer.put(*policy); } buffer.putShortString(alternateExchange.get() ? alternateExchange->getName() : std::string("")); @@ -1154,14 +914,13 @@ uint32_t Queue::encodedSize() const + (policy.get() ? (*policy).encodedSize() : 0); } -Queue::shared_ptr Queue::restore( QueueRegistry& queues, Buffer& buffer ) +Queue::shared_ptr Queue::decode ( QueueRegistry& queues, Buffer& buffer, bool recovering ) { string name; buffer.getShortString(name); - FieldTable settings; - buffer.get(settings); - boost::shared_ptr<Exchange> alternate; - std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true, false, 0, alternate, settings, true); + std::pair<Queue::shared_ptr, bool> result = queues.declare(name, true); + buffer.get(result.first->settings); + result.first->configure(result.first->settings, recovering ); if (result.first->policy.get() && buffer.available() >= result.first->policy->encodedSize()) { buffer.get ( *(result.first->policy) ); } @@ -1193,10 +952,11 @@ boost::shared_ptr<Exchange> Queue::getAlternateExchange() void tryAutoDeleteImpl(Broker& broker, Queue::shared_ptr queue) { - if (broker.getQueues().destroyIf(queue->getName(), + if (broker.getQueues().destroyIf(queue->getName(), boost::bind(boost::mem_fn(&Queue::canAutoDelete), queue))) { QPID_LOG(debug, "Auto-deleting " << queue->getName()); - queue->destroyed(); + queue->unbind(broker.getExchanges(), queue); + queue->destroy(); } } @@ -1205,7 +965,7 @@ struct AutoDeleteTask : qpid::sys::TimerTask Broker& broker; Queue::shared_ptr queue; - AutoDeleteTask(Broker& b, Queue::shared_ptr q, AbsTime fireTime) + AutoDeleteTask(Broker& b, Queue::shared_ptr q, AbsTime fireTime) : qpid::sys::TimerTask(fireTime, "DelayedAutoDeletion"), broker(b), queue(q) {} void fire() @@ -1223,27 +983,27 @@ void Queue::tryAutoDelete(Broker& broker, Queue::shared_ptr queue) if (queue->autoDeleteTimeout && queue->canAutoDelete()) { AbsTime time(now(), Duration(queue->autoDeleteTimeout * TIME_SEC)); queue->autoDeleteTask = boost::intrusive_ptr<qpid::sys::TimerTask>(new AutoDeleteTask(broker, queue, time)); - broker.getClusterTimer().add(queue->autoDeleteTask); + broker.getClusterTimer().add(queue->autoDeleteTask); QPID_LOG(debug, "Timed auto-delete for " << queue->getName() << " initiated"); } else { tryAutoDeleteImpl(broker, queue); } } -bool Queue::isExclusiveOwner(const OwnershipToken* const o) const -{ +bool Queue::isExclusiveOwner(const OwnershipToken* const o) const +{ Mutex::ScopedLock locker(ownershipLock); - return o == owner; + return o == owner; } -void Queue::releaseExclusiveOwnership() -{ +void Queue::releaseExclusiveOwnership() +{ Mutex::ScopedLock locker(ownershipLock); - owner = 0; + owner = 0; } -bool Queue::setExclusiveOwner(const OwnershipToken* const o) -{ +bool Queue::setExclusiveOwner(const OwnershipToken* const o) +{ //reset auto deletion timer if necessary if (autoDeleteTimeout && autoDeleteTask) { autoDeleteTask->cancel(); @@ -1252,25 +1012,25 @@ bool Queue::setExclusiveOwner(const OwnershipToken* const o) if (owner) { return false; } else { - owner = o; + owner = o; return true; } } -bool Queue::hasExclusiveOwner() const -{ +bool Queue::hasExclusiveOwner() const +{ Mutex::ScopedLock locker(ownershipLock); - return owner != 0; + return owner != 0; } -bool Queue::hasExclusiveConsumer() const -{ - return exclusive; +bool Queue::hasExclusiveConsumer() const +{ + return exclusive; } void Queue::setExternalQueueStore(ExternalQueueStore* inst) { - if (externalQueueStore!=inst && externalQueueStore) - delete externalQueueStore; + if (externalQueueStore!=inst && externalQueueStore) + delete externalQueueStore; externalQueueStore = inst; if (inst) { @@ -1295,7 +1055,7 @@ Manageable::status_t Queue::ManagementMethod (uint32_t methodId, Args& args, str case _qmf::Queue::METHOD_PURGE : { _qmf::ArgsQueuePurge& purgeArgs = (_qmf::ArgsQueuePurge&) args; - purge(purgeArgs.i_request, boost::shared_ptr<Exchange>(), &purgeArgs.i_filter); + purge(purgeArgs.i_request); status = Manageable::STATUS_OK; } break; @@ -1316,7 +1076,7 @@ Manageable::status_t Queue::ManagementMethod (uint32_t methodId, Args& args, str } } - purge(rerouteArgs.i_request, dest, &rerouteArgs.i_filter); + purge(rerouteArgs.i_request, dest); status = Manageable::STATUS_OK; } break; @@ -1325,14 +1085,6 @@ Manageable::status_t Queue::ManagementMethod (uint32_t methodId, Args& args, str return status; } - -void Queue::query(qpid::types::Variant::Map& results) const -{ - Mutex::ScopedLock locker(messageLock); - /** @todo add any interesting queue state into results */ - if (allocator) allocator->query(results); -} - void Queue::setPosition(SequenceNumber n) { Mutex::ScopedLock locker(messageLock); sequence = n; @@ -1367,10 +1119,7 @@ void Queue::insertSequenceNumbers(const std::string& key) QPID_LOG(debug, "Inserting sequence numbers as " << key); } -/** updates queue observers and state when a message has become available for transfer, - * expects messageLock to be held - */ -void Queue::observeEnqueue(const QueuedMessage& m, const Mutex::ScopedLock&) +void Queue::enqueued(const QueuedMessage& m) { for (Observers::iterator i = observers.begin(); i != observers.end(); ++i) { try { @@ -1393,8 +1142,7 @@ void Queue::updateEnqueued(const QueuedMessage& m) if (policy.get()) { policy->recoverEnqueued(payload); } - Mutex::ScopedLock locker(messageLock); - observeEnqueue(m, locker); + enqueued(m); } else { QPID_LOG(warning, "Queue informed of enqueued message that has no payload"); } @@ -1418,7 +1166,6 @@ void Queue::checkNotDeleted() void Queue::addObserver(boost::shared_ptr<QueueObserver> observer) { - Mutex::ScopedLock locker(messageLock); observers.insert(observer); } @@ -1428,32 +1175,6 @@ void Queue::flush() if (u.acquired && store) store->flush(*this); } - -bool Queue::bind(boost::shared_ptr<Exchange> exchange, const std::string& key, - const qpid::framing::FieldTable& arguments) -{ - if (exchange->bind(shared_from_this(), key, &arguments)) { - bound(exchange->getName(), key, arguments); - if (exchange->isDurable() && isDurable()) { - store->bind(*exchange, *this, key, arguments); - } - return true; - } else { - return false; - } -} - - -const Broker* Queue::getBroker() -{ - return broker; -} - -void Queue::setDequeueSincePurge(uint32_t value) { - dequeueSincePurge = value; -} - - Queue::UsageBarrier::UsageBarrier(Queue& q) : parent(q), count(0) {} bool Queue::UsageBarrier::acquire() diff --git a/cpp/src/qpid/broker/Queue.h b/cpp/src/qpid/broker/Queue.h index 59ae41e768..12a3d273be 100644 --- a/cpp/src/qpid/broker/Queue.h +++ b/cpp/src/qpid/broker/Queue.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -32,9 +32,9 @@ #include "qpid/broker/QueueBindings.h" #include "qpid/broker/QueueListeners.h" #include "qpid/broker/QueueObserver.h" +#include "qpid/broker/RateTracker.h" #include "qpid/framing/FieldTable.h" -#include "qpid/sys/AtomicValue.h" #include "qpid/sys/Monitor.h" #include "qpid/sys/Timer.h" #include "qpid/management/Manageable.h" @@ -59,7 +59,7 @@ class MessageStore; class QueueEvents; class QueueRegistry; class TransactionContext; -class MessageDistributor; +class Exchange; /** * The brokers representation of an amqp queue. Messages are @@ -74,13 +74,13 @@ class Queue : public boost::enable_shared_from_this<Queue>, { Queue& parent; uint count; - + UsageBarrier(Queue&); bool acquire(); void release(); void destroy(); }; - + struct ScopedUse { UsageBarrier& barrier; @@ -88,7 +88,7 @@ class Queue : public boost::enable_shared_from_this<Queue>, ScopedUse(UsageBarrier& b) : barrier(b), acquired(barrier.acquire()) {} ~ScopedUse() { if (acquired) barrier.release(); } }; - + typedef std::set< boost::shared_ptr<QueueObserver> > Observers; enum ConsumeCode {NO_MESSAGES=0, CANT_CONSUME=1, CONSUMED=2}; @@ -119,7 +119,7 @@ class Queue : public boost::enable_shared_from_this<Queue>, boost::shared_ptr<Exchange> alternateExchange; framing::SequenceNumber sequence; qmf::org::apache::qpid::broker::Queue* mgmtObject; - sys::AtomicValue<uint32_t> dequeueSincePurge; // Count dequeues since last purge. + RateTracker dequeueTracker; int eventMode; Observers observers; bool insertSeqNo; @@ -129,36 +129,26 @@ class Queue : public boost::enable_shared_from_this<Queue>, UsageBarrier barrier; int autoDeleteTimeout; boost::intrusive_ptr<qpid::sys::TimerTask> autoDeleteTask; - boost::shared_ptr<MessageDistributor> allocator; void push(boost::intrusive_ptr<Message>& msg, bool isRecovery=false); void setPolicy(std::auto_ptr<QueuePolicy> policy); - bool getNextMessage(QueuedMessage& msg, Consumer::shared_ptr& c); - ConsumeCode consumeNextMessage(QueuedMessage& msg, Consumer::shared_ptr& c); - bool browseNextMessage(QueuedMessage& msg, Consumer::shared_ptr& c); + bool seek(QueuedMessage& msg, Consumer::shared_ptr position); + bool getNextMessage(QueuedMessage& msg, Consumer::shared_ptr c); + ConsumeCode consumeNextMessage(QueuedMessage& msg, Consumer::shared_ptr c); + bool browseNextMessage(QueuedMessage& msg, Consumer::shared_ptr c); void notifyListener(); void removeListener(Consumer::shared_ptr); bool isExcluded(boost::intrusive_ptr<Message>& msg); - /** update queue observers, stats, policy, etc when the messages' state changes. Lock - * must be held by caller */ - void observeEnqueue(const QueuedMessage& msg, const sys::Mutex::ScopedLock& lock); - void observeAcquire(const QueuedMessage& msg, const sys::Mutex::ScopedLock& lock); - void observeRequeue(const QueuedMessage& msg, const sys::Mutex::ScopedLock& lock); - void observeDequeue(const QueuedMessage& msg, const sys::Mutex::ScopedLock& lock); - - /** modify the Queue's message container - assumes messageLock held */ - void pop(const sys::Mutex::ScopedLock& held); // acquire front msg - void popAndDequeue(const sys::Mutex::ScopedLock& held); // acquire and dequeue front msg - // acquire message @ position, return true and set msg if acquire succeeds - bool acquire(const qpid::framing::SequenceNumber& position, QueuedMessage& msg, - const sys::Mutex::ScopedLock& held); - + void enqueued(const QueuedMessage& msg); + void dequeued(const QueuedMessage& msg); + void pop(); + void popAndDequeue(); + QueuedMessage getFront(); void forcePersistent(QueuedMessage& msg); int getEventMode(); - void configureImpl(const qpid::framing::FieldTable& settings); inline void mgntEnqStats(const boost::intrusive_ptr<Message>& msg) { @@ -182,9 +172,8 @@ class Queue : public boost::enable_shared_from_this<Queue>, } } } - + void checkNotDeleted(); - void notifyDeleted(); public: @@ -193,50 +182,29 @@ class Queue : public boost::enable_shared_from_this<Queue>, typedef std::vector<shared_ptr> vector; QPID_BROKER_EXTERN Queue(const std::string& name, - bool autodelete = false, - MessageStore* const store = 0, + bool autodelete = false, + MessageStore* const store = 0, const OwnershipToken* const owner = 0, management::Manageable* parent = 0, Broker* broker = 0); QPID_BROKER_EXTERN ~Queue(); - /** allow the Consumer to consume or browse the next available message */ QPID_BROKER_EXTERN bool dispatch(Consumer::shared_ptr); - /** allow the Consumer to acquire a message that it has browsed. - * @param msg - message to be acquired. - * @return false if message is no longer available for acquire. - */ - QPID_BROKER_EXTERN bool acquire(const QueuedMessage& msg, const std::string& consumer); + void create(const qpid::framing::FieldTable& settings); - /** - * Used to configure a new queue and create a persistent record - * for it in store if required. - */ - QPID_BROKER_EXTERN void create(const qpid::framing::FieldTable& settings); - - /** - * Used to reconfigure a recovered queue (does not create - * persistent record in store). - */ - QPID_BROKER_EXTERN void configure(const qpid::framing::FieldTable& settings); - void destroyed(); + // "recovering" means we are doing a MessageStore recovery. + QPID_BROKER_EXTERN void configure(const qpid::framing::FieldTable& settings, + bool recovering = false); + void destroy(); + void notifyDeleted(); QPID_BROKER_EXTERN void bound(const std::string& exchange, const std::string& key, const qpid::framing::FieldTable& args); - //TODO: get unbind out of the public interface; only there for purposes of one unit test - QPID_BROKER_EXTERN void unbind(ExchangeRegistry& exchanges); - /** - * Bind self to specified exchange, and record that binding for unbinding on delete. - */ - bool bind(boost::shared_ptr<Exchange> exchange, const std::string& key, - const qpid::framing::FieldTable& arguments=qpid::framing::FieldTable()); + QPID_BROKER_EXTERN void unbind(ExchangeRegistry& exchanges, + Queue::shared_ptr shared_ref); - /** Acquire the message at the given position if it is available for acquire. Not to - * be used by clients, but used by the broker for queue management. - * @param message - set to the acquired message if true returned. - * @return true if the message has been acquired. - */ + QPID_BROKER_EXTERN bool acquire(const QueuedMessage& msg); QPID_BROKER_EXTERN bool acquireMessageAt(const qpid::framing::SequenceNumber& position, QueuedMessage& message); /** @@ -265,14 +233,11 @@ class Queue : public boost::enable_shared_from_this<Queue>, bool exclusive = false); QPID_BROKER_EXTERN void cancel(Consumer::shared_ptr c); - uint32_t purge(const uint32_t purge_request=0, //defaults to all messages - boost::shared_ptr<Exchange> dest=boost::shared_ptr<Exchange>(), - const ::qpid::types::Variant::Map *filter=0); - QPID_BROKER_EXTERN void purgeExpired(sys::Duration); + uint32_t purge(const uint32_t purge_request=0, boost::shared_ptr<Exchange> dest=boost::shared_ptr<Exchange>()); //defaults to all messages + QPID_BROKER_EXTERN void purgeExpired(); //move qty # of messages to destination Queue destq - uint32_t move(const Queue::shared_ptr destq, uint32_t qty, - const qpid::types::Variant::Map *filter=0); + uint32_t move(const Queue::shared_ptr destq, uint32_t qty); QPID_BROKER_EXTERN uint32_t getMessageCount() const; QPID_BROKER_EXTERN uint32_t getEnqueueCompleteMessageCount() const; @@ -311,8 +276,8 @@ class Queue : public boost::enable_shared_from_this<Queue>, * Inform queue of messages that were enqueued, have since * been acquired but not yet accepted or released (and * thus are still logically on the queue) - used in - * clustered broker. - */ + * clustered broker. + */ void updateEnqueued(const QueuedMessage& msg); /** @@ -323,14 +288,14 @@ class Queue : public boost::enable_shared_from_this<Queue>, * accepted it). */ bool isEnqueued(const QueuedMessage& msg); - + /** - * Acquires the next available (oldest) message + * Gets the next available message */ QPID_BROKER_EXTERN QueuedMessage get(); - /** Get the message at position pos, returns true if found and sets msg */ - QPID_BROKER_EXTERN bool find(framing::SequenceNumber pos, QueuedMessage& msg ) const; + /** Get the message at position pos */ + QPID_BROKER_EXTERN QueuedMessage find(framing::SequenceNumber pos) const; const QueuePolicy* getPolicy(); @@ -344,13 +309,8 @@ class Queue : public boost::enable_shared_from_this<Queue>, void encode(framing::Buffer& buffer) const; uint32_t encodedSize() const; - /** - * Restores a queue from encoded data (used in recovery) - * - * Note: restored queue will be neither auto-deleted or have an - * exclusive owner - */ - static Queue::shared_ptr restore(QueueRegistry& queues, framing::Buffer& buffer); + // "recovering" means we are doing a MessageStore recovery. + static Queue::shared_ptr decode(QueueRegistry& queues, framing::Buffer& buffer, bool recovering = false ); static void tryAutoDelete(Broker& broker, Queue::shared_ptr); virtual void setExternalQueueStore(ExternalQueueStore* inst); @@ -359,7 +319,6 @@ class Queue : public boost::enable_shared_from_this<Queue>, management::ManagementObject* GetManagementObject (void) const; management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text); - void query(::qpid::types::Variant::Map&) const; /** Apply f to each Message on the queue. */ template <class F> void eachMessage(F f) { @@ -372,11 +331,6 @@ class Queue : public boost::enable_shared_from_this<Queue>, bindings.eachBinding(f); } - /** Apply f to each Observer on the queue */ - template <class F> void eachObserver(F f) { - std::for_each<Observers::iterator, F>(observers.begin(), observers.end(), f); - } - /** Set the position sequence number for the next message on the queue. * Must be >= the current sequence number. * Used by cluster to replicate queues. @@ -404,11 +358,6 @@ class Queue : public boost::enable_shared_from_this<Queue>, void recoverPrepared(boost::intrusive_ptr<Message>& msg); void flush(); - - const Broker* getBroker(); - - uint32_t getDequeueSincePurge() { return dequeueSincePurge.get(); } - void setDequeueSincePurge(uint32_t value); }; } } diff --git a/cpp/src/qpid/broker/QueueCleaner.cpp b/cpp/src/qpid/broker/QueueCleaner.cpp index 838bc28be8..3499ea8a4d 100644 --- a/cpp/src/qpid/broker/QueueCleaner.cpp +++ b/cpp/src/qpid/broker/QueueCleaner.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -27,7 +27,7 @@ namespace qpid { namespace broker { -QueueCleaner::QueueCleaner(QueueRegistry& q, sys::Timer* t) : queues(q), timer(t) {} +QueueCleaner::QueueCleaner(QueueRegistry& q, sys::Timer& t) : queues(q), timer(t) {} QueueCleaner::~QueueCleaner() { @@ -36,16 +36,10 @@ QueueCleaner::~QueueCleaner() void QueueCleaner::start(qpid::sys::Duration p) { - period = p; task = new Task(*this, p); - timer->add(task); + timer.add(task); } -void QueueCleaner::setTimer(qpid::sys::Timer* timer) { - this->timer = timer; -} - - QueueCleaner::Task::Task(QueueCleaner& p, qpid::sys::Duration d) : sys::TimerTask(d,"QueueCleaner"), parent(p) {} void QueueCleaner::Task::fire() @@ -71,9 +65,9 @@ void QueueCleaner::fired() std::vector<Queue::shared_ptr> copy; CollectQueues collect(©); queues.eachQueue(collect); - std::for_each(copy.begin(), copy.end(), boost::bind(&Queue::purgeExpired, _1, period)); + std::for_each(copy.begin(), copy.end(), boost::bind(&Queue::purgeExpired, _1)); task->setupNextFire(); - timer->add(task); + timer.add(task); } diff --git a/cpp/src/qpid/broker/QueueCleaner.h b/cpp/src/qpid/broker/QueueCleaner.h index ffebfe3e1b..11c2d180ac 100644 --- a/cpp/src/qpid/broker/QueueCleaner.h +++ b/cpp/src/qpid/broker/QueueCleaner.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -35,15 +35,14 @@ class QueueRegistry; class QueueCleaner { public: - QPID_BROKER_EXTERN QueueCleaner(QueueRegistry& queues, sys::Timer* timer); + QPID_BROKER_EXTERN QueueCleaner(QueueRegistry& queues, sys::Timer& timer); QPID_BROKER_EXTERN ~QueueCleaner(); - QPID_BROKER_EXTERN void start(sys::Duration period); - QPID_BROKER_EXTERN void setTimer(sys::Timer* timer); + QPID_BROKER_EXTERN void start(qpid::sys::Duration period); private: class Task : public sys::TimerTask { public: - Task(QueueCleaner& parent, sys::Duration duration); + Task(QueueCleaner& parent, qpid::sys::Duration duration); void fire(); private: QueueCleaner& parent; @@ -51,8 +50,7 @@ class QueueCleaner boost::intrusive_ptr<sys::TimerTask> task; QueueRegistry& queues; - sys::Timer* timer; - sys::Duration period; + sys::Timer& timer; void fired(); }; diff --git a/cpp/src/qpid/broker/QueueEvents.cpp b/cpp/src/qpid/broker/QueueEvents.cpp index c66bdabf0f..2c540ff1ad 100644 --- a/cpp/src/qpid/broker/QueueEvents.cpp +++ b/cpp/src/qpid/broker/QueueEvents.cpp @@ -129,10 +129,6 @@ class EventGenerator : public QueueObserver { if (!enqueueOnly) manager.dequeued(m); } - - void acquired(const QueuedMessage&) {}; - void requeued(const QueuedMessage&) {}; - private: QueueEvents& manager; const bool enqueueOnly; diff --git a/cpp/src/qpid/broker/QueueFlowLimit.cpp b/cpp/src/qpid/broker/QueueFlowLimit.cpp deleted file mode 100644 index f15bb45c01..0000000000 --- a/cpp/src/qpid/broker/QueueFlowLimit.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -#include "qpid/broker/QueueFlowLimit.h" -#include "qpid/broker/Broker.h" -#include "qpid/broker/Queue.h" -#include "qpid/Exception.h" -#include "qpid/framing/FieldValue.h" -#include "qpid/framing/reply_exceptions.h" -#include "qpid/log/Statement.h" -#include "qpid/sys/Mutex.h" -#include "qpid/broker/SessionState.h" -#include "qpid/sys/ClusterSafe.h" - -#include "qmf/org/apache/qpid/broker/Queue.h" - -#include <sstream> - -using namespace qpid::broker; -using namespace qpid::framing; - -namespace { - /** ensure that the configured flow control stop and resume values are - * valid with respect to the maximum queue capacity, and each other - */ - template <typename T> - void validateFlowConfig(T max, T& stop, T& resume, const std::string& type, const std::string& queue) - { - if (resume > stop) { - throw InvalidArgumentException(QPID_MSG("Queue \"" << queue << "\": qpid.flow_resume_" << type - << "=" << resume - << " must be less than qpid.flow_stop_" << type - << "=" << stop)); - } - if (resume == 0) resume = stop; - if (max != 0 && (max < stop)) { - throw InvalidArgumentException(QPID_MSG("Queue \"" << queue << "\": qpid.flow_stop_" << type - << "=" << stop - << " must be less than qpid.max_" << type - << "=" << max)); - } - } - - /** extract a capacity value as passed in an argument map - */ - uint64_t getCapacity(const FieldTable& settings, const std::string& key, uint64_t defaultValue) - { - FieldTable::ValuePtr v = settings.get(key); - - int64_t result = 0; - - if (!v) return defaultValue; - if (v->getType() == 0x23) { - QPID_LOG(debug, "Value for " << key << " specified as float: " << v->get<float>()); - } else if (v->getType() == 0x33) { - QPID_LOG(debug, "Value for " << key << " specified as double: " << v->get<double>()); - } else if (v->convertsTo<int64_t>()) { - result = v->get<int64_t>(); - QPID_LOG(debug, "Got integer value for " << key << ": " << result); - if (result >= 0) return result; - } else if (v->convertsTo<string>()) { - string s(v->get<string>()); - QPID_LOG(debug, "Got string value for " << key << ": " << s); - std::istringstream convert(s); - if (convert >> result && result >= 0) return result; - } - - QPID_LOG(warning, "Cannot convert " << key << " to unsigned integer, using default (" << defaultValue << ")"); - return defaultValue; - } -} - - - -QueueFlowLimit::QueueFlowLimit(Queue *_queue, - uint32_t _flowStopCount, uint32_t _flowResumeCount, - uint64_t _flowStopSize, uint64_t _flowResumeSize) - : StatefulQueueObserver(std::string("QueueFlowLimit")), queue(_queue), queueName("<unknown>"), - flowStopCount(_flowStopCount), flowResumeCount(_flowResumeCount), - flowStopSize(_flowStopSize), flowResumeSize(_flowResumeSize), - flowStopped(false), count(0), size(0), queueMgmtObj(0), broker(0) -{ - uint32_t maxCount(0); - uint64_t maxSize(0); - - if (queue) { - queueName = _queue->getName(); - if (queue->getPolicy()) { - maxSize = _queue->getPolicy()->getMaxSize(); - maxCount = _queue->getPolicy()->getMaxCount(); - } - broker = queue->getBroker(); - queueMgmtObj = dynamic_cast<_qmfBroker::Queue*> (queue->GetManagementObject()); - if (queueMgmtObj) { - queueMgmtObj->set_flowStopped(isFlowControlActive()); - } - } - validateFlowConfig( maxCount, flowStopCount, flowResumeCount, "count", queueName ); - validateFlowConfig( maxSize, flowStopSize, flowResumeSize, "size", queueName ); - QPID_LOG(info, "Queue \"" << queueName << "\": Flow limit created: flowStopCount=" << flowStopCount - << ", flowResumeCount=" << flowResumeCount - << ", flowStopSize=" << flowStopSize << ", flowResumeSize=" << flowResumeSize ); -} - - -QueueFlowLimit::~QueueFlowLimit() -{ - sys::Mutex::ScopedLock l(indexLock); - if (!index.empty()) { - // we're gone - release all pending msgs - for (std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> >::iterator itr = index.begin(); - itr != index.end(); ++itr) - if (itr->second) - try { - itr->second->getIngressCompletion().finishCompleter(); - } catch (...) {} // ignore - not safe for a destructor to throw. - index.clear(); - } -} - - -void QueueFlowLimit::enqueued(const QueuedMessage& msg) -{ - sys::Mutex::ScopedLock l(indexLock); - - ++count; - size += msg.payload->contentSize(); - - if (!flowStopped) { - if (flowStopCount && count > flowStopCount) { - flowStopped = true; - QPID_LOG(info, "Queue \"" << queueName << "\": has reached " << flowStopCount << " enqueued messages. Producer flow control activated." ); - } else if (flowStopSize && size > flowStopSize) { - flowStopped = true; - QPID_LOG(info, "Queue \"" << queueName << "\": has reached " << flowStopSize << " enqueued bytes. Producer flow control activated." ); - } - if (flowStopped && queueMgmtObj) { - queueMgmtObj->set_flowStopped(true); - queueMgmtObj->inc_flowStoppedCount(); - } - } - - if (flowStopped || !index.empty()) { - // ignore flow control if we are populating the queue due to cluster replication: - if (broker && broker->isClusterUpdatee()) { - QPID_LOG(trace, "Queue \"" << queueName << "\": ignoring flow control for msg pos=" << msg.position); - return; - } - QPID_LOG(trace, "Queue \"" << queueName << "\": setting flow control for msg pos=" << msg.position); - msg.payload->getIngressCompletion().startCompleter(); // don't complete until flow resumes - bool unique; - unique = index.insert(std::pair<framing::SequenceNumber, boost::intrusive_ptr<Message> >(msg.position, msg.payload)).second; - // Like this to avoid tripping up unused variable warning when NDEBUG set - if (!unique) assert(unique); - } -} - - - -void QueueFlowLimit::dequeued(const QueuedMessage& msg) -{ - sys::Mutex::ScopedLock l(indexLock); - - if (count > 0) { - --count; - } else { - throw Exception(QPID_MSG("Flow limit count underflow on dequeue. Queue=" << queueName)); - } - - uint64_t _size = msg.payload->contentSize(); - if (_size <= size) { - size -= _size; - } else { - throw Exception(QPID_MSG("Flow limit size underflow on dequeue. Queue=" << queueName)); - } - - if (flowStopped && - (flowResumeSize == 0 || size < flowResumeSize) && - (flowResumeCount == 0 || count < flowResumeCount)) { - flowStopped = false; - if (queueMgmtObj) - queueMgmtObj->set_flowStopped(false); - QPID_LOG(info, "Queue \"" << queueName << "\": has drained below the flow control resume level. Producer flow control deactivated." ); - } - - if (!index.empty()) { - if (!flowStopped) { - // flow enabled - release all pending msgs - for (std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> >::iterator itr = index.begin(); - itr != index.end(); ++itr) - if (itr->second) - itr->second->getIngressCompletion().finishCompleter(); - index.clear(); - } else { - // even if flow controlled, we must release this msg as it is being dequeued - std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> >::iterator itr = index.find(msg.position); - if (itr != index.end()) { // this msg is flow controlled, release it: - msg.payload->getIngressCompletion().finishCompleter(); - index.erase(itr); - } - } - } -} - - -void QueueFlowLimit::encode(Buffer& buffer) const -{ - buffer.putLong(flowStopCount); - buffer.putLong(flowResumeCount); - buffer.putLongLong(flowStopSize); - buffer.putLongLong(flowResumeSize); - buffer.putLong(count); - buffer.putLongLong(size); -} - - -void QueueFlowLimit::decode ( Buffer& buffer ) -{ - flowStopCount = buffer.getLong(); - flowResumeCount = buffer.getLong(); - flowStopSize = buffer.getLongLong(); - flowResumeSize = buffer.getLongLong(); - count = buffer.getLong(); - size = buffer.getLongLong(); -} - - -uint32_t QueueFlowLimit::encodedSize() const { - return sizeof(uint32_t) + // flowStopCount - sizeof(uint32_t) + // flowResumecount - sizeof(uint64_t) + // flowStopSize - sizeof(uint64_t) + // flowResumeSize - sizeof(uint32_t) + // count - sizeof(uint64_t); // size -} - - -const std::string QueueFlowLimit::flowStopCountKey("qpid.flow_stop_count"); -const std::string QueueFlowLimit::flowResumeCountKey("qpid.flow_resume_count"); -const std::string QueueFlowLimit::flowStopSizeKey("qpid.flow_stop_size"); -const std::string QueueFlowLimit::flowResumeSizeKey("qpid.flow_resume_size"); -uint64_t QueueFlowLimit::defaultMaxSize; -uint QueueFlowLimit::defaultFlowStopRatio; -uint QueueFlowLimit::defaultFlowResumeRatio; - - -void QueueFlowLimit::setDefaults(uint64_t maxQueueSize, uint flowStopRatio, uint flowResumeRatio) -{ - defaultMaxSize = maxQueueSize; - defaultFlowStopRatio = flowStopRatio; - defaultFlowResumeRatio = flowResumeRatio; - - /** @todo KAG: Verify valid range on Broker::Options instead of here */ - if (flowStopRatio > 100 || flowResumeRatio > 100) - throw InvalidArgumentException(QPID_MSG("Default queue flow ratios must be between 0 and 100, inclusive:" - << " flowStopRatio=" << flowStopRatio - << " flowResumeRatio=" << flowResumeRatio)); - if (flowResumeRatio > flowStopRatio) - throw InvalidArgumentException(QPID_MSG("Default queue flow stop ratio must be >= flow resume ratio:" - << " flowStopRatio=" << flowStopRatio - << " flowResumeRatio=" << flowResumeRatio)); -} - - -void QueueFlowLimit::observe(Queue& queue, const qpid::framing::FieldTable& settings) -{ - QueueFlowLimit *ptr = createLimit( &queue, settings ); - if (ptr) { - boost::shared_ptr<QueueFlowLimit> observer(ptr); - queue.addObserver(observer); - } -} - -/** returns ptr to a QueueFlowLimit, else 0 if no limit */ -QueueFlowLimit *QueueFlowLimit::createLimit(Queue *queue, const qpid::framing::FieldTable& settings) -{ - std::string type(QueuePolicy::getType(settings)); - - if (type == QueuePolicy::RING || type == QueuePolicy::RING_STRICT) { - // The size of a RING queue is limited by design - no need for flow control. - return 0; - } - - if (settings.get(flowStopCountKey) || settings.get(flowStopSizeKey) || - settings.get(flowResumeCountKey) || settings.get(flowResumeSizeKey)) { - // user provided (some) flow settings manually... - uint32_t flowStopCount = getCapacity(settings, flowStopCountKey, 0); - uint32_t flowResumeCount = getCapacity(settings, flowResumeCountKey, 0); - uint64_t flowStopSize = getCapacity(settings, flowStopSizeKey, 0); - uint64_t flowResumeSize = getCapacity(settings, flowResumeSizeKey, 0); - if (flowStopCount == 0 && flowStopSize == 0) { // disable flow control - return 0; - } - return new QueueFlowLimit(queue, flowStopCount, flowResumeCount, flowStopSize, flowResumeSize); - } - - if (defaultFlowStopRatio) { // broker has a default ratio setup... - uint64_t maxByteCount = getCapacity(settings, QueuePolicy::maxSizeKey, defaultMaxSize); - uint64_t flowStopSize = (uint64_t)(maxByteCount * (defaultFlowStopRatio/100.0) + 0.5); - uint64_t flowResumeSize = (uint64_t)(maxByteCount * (defaultFlowResumeRatio/100.0)); - uint32_t maxMsgCount = getCapacity(settings, QueuePolicy::maxCountKey, 0); // no size by default - uint32_t flowStopCount = (uint32_t)(maxMsgCount * (defaultFlowStopRatio/100.0) + 0.5); - uint32_t flowResumeCount = (uint32_t)(maxMsgCount * (defaultFlowResumeRatio/100.0)); - - return new QueueFlowLimit(queue, flowStopCount, flowResumeCount, flowStopSize, flowResumeSize); - } - return 0; -} - -/* Cluster replication */ - -namespace { - /** pack a set of sequence number ranges into a framing::Array */ - void buildSeqRangeArray(qpid::framing::Array *seqs, - const qpid::framing::SequenceNumber& first, - const qpid::framing::SequenceNumber& last) - { - seqs->push_back(qpid::framing::Array::ValuePtr(new Unsigned32Value(first))); - seqs->push_back(qpid::framing::Array::ValuePtr(new Unsigned32Value(last))); - } -} - -/** Runs on UPDATER to snapshot current state */ -void QueueFlowLimit::getState(qpid::framing::FieldTable& state ) const -{ - sys::Mutex::ScopedLock l(indexLock); - state.clear(); - - framing::SequenceSet ss; - if (!index.empty()) { - /* replicate the set of messages pending flow control */ - for (std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> >::const_iterator itr = index.begin(); - itr != index.end(); ++itr) { - ss.add(itr->first); - } - framing::Array seqs(TYPE_CODE_UINT32); - typedef boost::function<void(framing::SequenceNumber, framing::SequenceNumber)> arrayBuilder; - ss.for_each((arrayBuilder)boost::bind(&buildSeqRangeArray, &seqs, _1, _2)); - state.setArray("pendingMsgSeqs", seqs); - } - QPID_LOG(debug, "Queue \"" << queueName << "\": flow limit replicating pending msgs, range=" << ss); -} - - -/** called on UPDATEE to set state from snapshot */ -void QueueFlowLimit::setState(const qpid::framing::FieldTable& state) -{ - sys::Mutex::ScopedLock l(indexLock); - index.clear(); - - framing::SequenceSet fcmsg; - framing::Array seqArray(TYPE_CODE_UINT32); - if (state.getArray("pendingMsgSeqs", seqArray)) { - assert((seqArray.count() & 0x01) == 0); // must be even since they are sequence ranges - framing::Array::const_iterator i = seqArray.begin(); - while (i != seqArray.end()) { - framing::SequenceNumber first((*i)->getIntegerValue<uint32_t, 4>()); - ++i; - framing::SequenceNumber last((*i)->getIntegerValue<uint32_t, 4>()); - ++i; - fcmsg.add(first, last); - for (SequenceNumber seq = first; seq <= last; ++seq) { - QueuedMessage msg; - queue->find(seq, msg); // fyi: may not be found if msg is acquired & unacked - bool unique; - unique = index.insert(std::pair<framing::SequenceNumber, boost::intrusive_ptr<Message> >(seq, msg.payload)).second; - // Like this to avoid tripping up unused variable warning when NDEBUG set - if (!unique) assert(unique); - } - } - } - - flowStopped = index.size() != 0; - if (queueMgmtObj) { - queueMgmtObj->set_flowStopped(isFlowControlActive()); - } - QPID_LOG(debug, "Queue \"" << queueName << "\": flow limit replicated the pending msgs, range=" << fcmsg) -} - - -namespace qpid { - namespace broker { - -std::ostream& operator<<(std::ostream& out, const QueueFlowLimit& f) -{ - out << "; flowStopCount=" << f.flowStopCount << ", flowResumeCount=" << f.flowResumeCount; - out << "; flowStopSize=" << f.flowStopSize << ", flowResumeSize=" << f.flowResumeSize; - return out; -} - - } -} - diff --git a/cpp/src/qpid/broker/QueueFlowLimit.h b/cpp/src/qpid/broker/QueueFlowLimit.h deleted file mode 100644 index ad8a2720ef..0000000000 --- a/cpp/src/qpid/broker/QueueFlowLimit.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -#ifndef _QueueFlowLimit_ -#define _QueueFlowLimit_ - -#include <list> -#include <set> -#include <iostream> -#include <memory> -#include "qpid/broker/BrokerImportExport.h" -#include "qpid/broker/QueuedMessage.h" -#include "qpid/broker/StatefulQueueObserver.h" -#include "qpid/framing/FieldTable.h" -#include "qpid/sys/AtomicValue.h" -#include "qpid/sys/Mutex.h" - -namespace qmf { -namespace org { -namespace apache { -namespace qpid { -namespace broker { - class Queue; -}}}}} -namespace _qmfBroker = qmf::org::apache::qpid::broker; - -namespace qpid { -namespace broker { - -class Broker; - -/** - * Producer flow control: when level is > flowStop*, flow control is ON. - * then level is < flowResume*, flow control is OFF. If == 0, flow control - * is not used. If both byte and msg count thresholds are set, then - * passing _either_ level may turn flow control ON, but _both_ must be - * below level before flow control will be turned OFF. - */ - class QueueFlowLimit : public StatefulQueueObserver -{ - static uint64_t defaultMaxSize; - static uint defaultFlowStopRatio; - static uint defaultFlowResumeRatio; - - Queue *queue; - std::string queueName; - - uint32_t flowStopCount; - uint32_t flowResumeCount; - uint64_t flowStopSize; - uint64_t flowResumeSize; - bool flowStopped; // true = producers held in flow control - - // current queue utilization - uint32_t count; - uint64_t size; - - public: - static QPID_BROKER_EXTERN const std::string flowStopCountKey; - static QPID_BROKER_EXTERN const std::string flowResumeCountKey; - static QPID_BROKER_EXTERN const std::string flowStopSizeKey; - static QPID_BROKER_EXTERN const std::string flowResumeSizeKey; - - QPID_BROKER_EXTERN virtual ~QueueFlowLimit(); - - /** the queue has added QueuedMessage. Returns true if flow state changes */ - QPID_BROKER_EXTERN void enqueued(const QueuedMessage&); - /** the queue has removed QueuedMessage. Returns true if flow state changes */ - QPID_BROKER_EXTERN void dequeued(const QueuedMessage&); - /** ignored */ - QPID_BROKER_EXTERN void acquired(const QueuedMessage&) {}; - QPID_BROKER_EXTERN void requeued(const QueuedMessage&) {}; - - /** for clustering: */ - QPID_BROKER_EXTERN void getState(qpid::framing::FieldTable&) const; - QPID_BROKER_EXTERN void setState(const qpid::framing::FieldTable&); - - uint32_t getFlowStopCount() const { return flowStopCount; } - uint32_t getFlowResumeCount() const { return flowResumeCount; } - uint64_t getFlowStopSize() const { return flowStopSize; } - uint64_t getFlowResumeSize() const { return flowResumeSize; } - - uint32_t getFlowCount() const { return count; } - uint64_t getFlowSize() const { return size; } - bool isFlowControlActive() const { return flowStopped; } - bool monitorFlowControl() const { return flowStopCount || flowStopSize; } - - void encode(framing::Buffer& buffer) const; - void decode(framing::Buffer& buffer); - uint32_t encodedSize() const; - - static QPID_BROKER_EXTERN void observe(Queue& queue, const qpid::framing::FieldTable& settings); - static QPID_BROKER_EXTERN void setDefaults(uint64_t defaultMaxSize, uint defaultFlowStopRatio, uint defaultFlowResumeRatio); - - friend QPID_BROKER_EXTERN std::ostream& operator<<(std::ostream&, const QueueFlowLimit&); - - protected: - // msgs waiting for flow to become available. - std::map<framing::SequenceNumber, boost::intrusive_ptr<Message> > index; - mutable qpid::sys::Mutex indexLock; - - _qmfBroker::Queue *queueMgmtObj; - - const Broker *broker; - - QPID_BROKER_EXTERN QueueFlowLimit(Queue *queue, - uint32_t flowStopCount, uint32_t flowResumeCount, - uint64_t flowStopSize, uint64_t flowResumeSize); - static QPID_BROKER_EXTERN QueueFlowLimit *createLimit(Queue *queue, const qpid::framing::FieldTable& settings); -}; - -}} - - -#endif diff --git a/cpp/src/qpid/broker/QueueListeners.cpp b/cpp/src/qpid/broker/QueueListeners.cpp index 591f4443bb..4d2c57d6b4 100644 --- a/cpp/src/qpid/broker/QueueListeners.cpp +++ b/cpp/src/qpid/broker/QueueListeners.cpp @@ -26,25 +26,19 @@ namespace broker { void QueueListeners::addListener(Consumer::shared_ptr c) { - if (!c->inListeners) { - if (c->acquires) { - add(consumers, c); - } else { - add(browsers, c); - } - c->inListeners = true; + if (c->preAcquires()) { + add(consumers, c); + } else { + add(browsers, c); } } void QueueListeners::removeListener(Consumer::shared_ptr c) { - if (c->inListeners) { - if (c->acquires) { - remove(consumers, c); - } else { - remove(browsers, c); - } - c->inListeners = false; + if (c->preAcquires()) { + remove(consumers, c); + } else { + remove(browsers, c); } } @@ -52,20 +46,18 @@ void QueueListeners::populate(NotificationSet& set) { if (consumers.size()) { set.consumer = consumers.front(); - consumers.pop_front(); - set.consumer->inListeners = false; + consumers.erase(consumers.begin()); } else { - // Don't swap the deques, hang on to the memory allocated. + // Don't swap the vectors, hang on to the memory allocated. set.browsers = browsers; browsers.clear(); - for (Listeners::iterator i = set.browsers.begin(); i != set.browsers.end(); i++) - (*i)->inListeners = false; } } void QueueListeners::add(Listeners& listeners, Consumer::shared_ptr c) { - listeners.push_back(c); + Listeners::iterator i = std::find(listeners.begin(), listeners.end(), c); + if (i == listeners.end()) listeners.push_back(c); } void QueueListeners::remove(Listeners& listeners, Consumer::shared_ptr c) @@ -81,7 +73,9 @@ void QueueListeners::NotificationSet::notify() } bool QueueListeners::contains(Consumer::shared_ptr c) const { - return c->inListeners; + return + std::find(browsers.begin(), browsers.end(), c) != browsers.end() || + std::find(consumers.begin(), consumers.end(), c) != consumers.end(); } void QueueListeners::ListenerSet::notifyAll() diff --git a/cpp/src/qpid/broker/QueueListeners.h b/cpp/src/qpid/broker/QueueListeners.h index 0659499253..59d1c84ca4 100644 --- a/cpp/src/qpid/broker/QueueListeners.h +++ b/cpp/src/qpid/broker/QueueListeners.h @@ -22,7 +22,7 @@ * */ #include "qpid/broker/Consumer.h" -#include <deque> +#include <vector> namespace qpid { namespace broker { @@ -40,7 +40,7 @@ namespace broker { class QueueListeners { public: - typedef std::deque<Consumer::shared_ptr> Listeners; + typedef std::vector<Consumer::shared_ptr> Listeners; class NotificationSet { diff --git a/cpp/src/qpid/broker/QueueObserver.h b/cpp/src/qpid/broker/QueueObserver.h index b58becd2ae..a711213dee 100644 --- a/cpp/src/qpid/broker/QueueObserver.h +++ b/cpp/src/qpid/broker/QueueObserver.h @@ -24,52 +24,18 @@ namespace qpid { namespace broker { -struct QueuedMessage; -class Consumer; - +class QueuedMessage; /** - * Interface for notifying classes who want to act as 'observers' of a queue of particular - * events. - * - * The events that are monitored reflect the relationship between a particular message and - * the queue it has been delivered to. A message can be considered in one of three states - * with respect to the queue: - * - * 1) "Available" - available for transfer to consumers (i.e. for browse or acquire), - * - * 2) "Acquired" - owned by a particular consumer, no longer available to other consumers - * (by either browse or acquire), but still considered on the queue. - * - * 3) "Dequeued" - removed from the queue and no longer available to any consumer. - * - * The queue events that are observable are: - * - * "Enqueued" - the message is "Available" - on the queue for transfer to any consumer - * (e.g. browse or acquire) - * - * "Acquired" - - a consumer has claimed exclusive access to it. It is no longer available - * for other consumers to browse or acquire, but it is not yet considered dequeued as it - * may be requeued by the consumer. - * - * "Requeued" - a previously-acquired message is released by its owner: it is put back on - * the queue at its original position and returns to the "Available" state. - * - * "Dequeued" - a message is no longer queued. At this point, the queue no longer tracks - * the message, and the broker considers the consumer's transaction complete. + * Interface for notifying classes who want to act as 'observers' of a + * queue of particular events. */ class QueueObserver { public: virtual ~QueueObserver() {} - - // note: the Queue will hold the messageLock while calling these methods! virtual void enqueued(const QueuedMessage&) = 0; virtual void dequeued(const QueuedMessage&) = 0; - virtual void acquired(const QueuedMessage&) = 0; - virtual void requeued(const QueuedMessage&) = 0; - virtual void consumerAdded( const Consumer& ) {}; - virtual void consumerRemoved( const Consumer& ) {}; - private: + private: }; }} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/QueuePolicy.cpp b/cpp/src/qpid/broker/QueuePolicy.cpp index 0c245700af..4168221ad0 100644 --- a/cpp/src/qpid/broker/QueuePolicy.cpp +++ b/cpp/src/qpid/broker/QueuePolicy.cpp @@ -117,30 +117,30 @@ void QueuePolicy::update(FieldTable& settings) settings.setString(typeKey, type); } -template <typename T> -T getCapacity(const FieldTable& settings, const std::string& key, T defaultValue) +uint32_t QueuePolicy::getCapacity(const FieldTable& settings, const std::string& key, uint32_t defaultValue) { FieldTable::ValuePtr v = settings.get(key); - T result = 0; + int32_t result = 0; if (!v) return defaultValue; if (v->getType() == 0x23) { QPID_LOG(debug, "Value for " << key << " specified as float: " << v->get<float>()); } else if (v->getType() == 0x33) { QPID_LOG(debug, "Value for " << key << " specified as double: " << v->get<double>()); - } else if (v->convertsTo<T>()) { - result = v->get<T>(); + } else if (v->convertsTo<int>()) { + result = v->get<int>(); QPID_LOG(debug, "Got integer value for " << key << ": " << result); if (result >= 0) return result; } else if (v->convertsTo<string>()) { string s(v->get<string>()); QPID_LOG(debug, "Got string value for " << key << ": " << s); std::istringstream convert(s); - if (convert >> result && result >= 0 && convert.eof()) return result; + if (convert >> result && result >= 0) return result; } - throw IllegalArgumentException(QPID_MSG("Cannot convert " << key << " to unsigned integer: " << *v)); + QPID_LOG(warning, "Cannot convert " << key << " to unsigned integer, using default (" << defaultValue << ")"); + return defaultValue; } std::string QueuePolicy::getType(const FieldTable& settings) @@ -247,7 +247,7 @@ bool RingQueuePolicy::checkLimit(boost::intrusive_ptr<Message> m) { // If the message is bigger than the queue size, give up - if (getMaxSize() && m->contentSize() > getMaxSize()) { + if (m->contentSize() > getMaxSize()) { QPID_LOG(debug, "Message too large for ring queue " << name << " [" << *this << "] " << ": message size = " << m->contentSize() << " bytes" @@ -269,7 +269,8 @@ bool RingQueuePolicy::checkLimit(boost::intrusive_ptr<Message> m) do { QueuedMessage oldest = queue.front(); - if (oldest.queue->acquireMessageAt(oldest.position, oldest) || !strict) { + + if (oldest.queue->acquire(oldest) || !strict) { queue.pop_front(); pendingDequeues.push_back(oldest); QPID_LOG(debug, "Ring policy triggered in " << name @@ -319,8 +320,8 @@ std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const qpid::framing::F std::auto_ptr<QueuePolicy> QueuePolicy::createQueuePolicy(const std::string& name, const qpid::framing::FieldTable& settings) { - uint32_t maxCount = getCapacity<int32_t>(settings, maxCountKey, 0); - uint64_t maxSize = getCapacity<int64_t>(settings, maxSizeKey, defaultMaxSize); + uint32_t maxCount = getCapacity(settings, maxCountKey, 0); + uint32_t maxSize = getCapacity(settings, maxSizeKey, defaultMaxSize); if (maxCount || maxSize) { return createQueuePolicy(name, maxCount, maxSize, getType(settings)); } else { diff --git a/cpp/src/qpid/broker/QueuePolicy.h b/cpp/src/qpid/broker/QueuePolicy.h index ec7f846704..3cdd63784d 100644 --- a/cpp/src/qpid/broker/QueuePolicy.h +++ b/cpp/src/qpid/broker/QueuePolicy.h @@ -43,7 +43,8 @@ class QueuePolicy uint32_t count; uint64_t size; bool policyExceeded; - + + static uint32_t getCapacity(const qpid::framing::FieldTable& settings, const std::string& key, uint32_t defaultValue); protected: uint64_t getCurrentQueueSize() const { return size; } diff --git a/cpp/src/qpid/broker/QueueRegistry.cpp b/cpp/src/qpid/broker/QueueRegistry.cpp index 135a3543d9..ea2531dae7 100644 --- a/cpp/src/qpid/broker/QueueRegistry.cpp +++ b/cpp/src/qpid/broker/QueueRegistry.cpp @@ -21,7 +21,6 @@ #include "qpid/broker/Queue.h" #include "qpid/broker/QueueRegistry.h" #include "qpid/broker/QueueEvents.h" -#include "qpid/broker/Exchange.h" #include "qpid/log/Statement.h" #include <sstream> #include <assert.h> @@ -37,13 +36,7 @@ QueueRegistry::~QueueRegistry(){} std::pair<Queue::shared_ptr, bool> QueueRegistry::declare(const string& declareName, bool durable, - bool autoDelete, const OwnershipToken* owner, - boost::shared_ptr<Exchange> alternate, - const qpid::framing::FieldTable& arguments, - bool recovering/*true if this declare is a - result of recovering queue - definition from persistente - record*/) + bool autoDelete, const OwnershipToken* owner) { RWlock::ScopedWlock locker(lock); string name = declareName.empty() ? generateName() : declareName; @@ -52,17 +45,6 @@ QueueRegistry::declare(const string& declareName, bool durable, if (i == queues.end()) { Queue::shared_ptr queue(new Queue(name, autoDelete, durable ? store : 0, owner, parent, broker)); - if (alternate) { - queue->setAlternateExchange(alternate);//need to do this *before* create - alternate->incAlternateUsers(); - } - if (!recovering) { - //apply settings & create persistent record if required - queue->create(arguments); - } else { - //i.e. recovering a queue for which we already have a persistent record - queue->configure(arguments); - } queues[name] = queue; if (lastNode) queue->setLastNodeFailure(); diff --git a/cpp/src/qpid/broker/QueueRegistry.h b/cpp/src/qpid/broker/QueueRegistry.h index 8a32a64f05..57859fe639 100644 --- a/cpp/src/qpid/broker/QueueRegistry.h +++ b/cpp/src/qpid/broker/QueueRegistry.h @@ -24,7 +24,6 @@ #include "qpid/broker/BrokerImportExport.h" #include "qpid/sys/Mutex.h" #include "qpid/management/Manageable.h" -#include "qpid/framing/FieldTable.h" #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <algorithm> @@ -35,7 +34,6 @@ namespace broker { class Queue; class QueueEvents; -class Exchange; class OwnershipToken; class Broker; class MessageStore; @@ -62,10 +60,7 @@ class QueueRegistry { const std::string& name, bool durable = false, bool autodelete = false, - const OwnershipToken* owner = 0, - boost::shared_ptr<Exchange> alternateExchange = boost::shared_ptr<Exchange>(), - const qpid::framing::FieldTable& args = framing::FieldTable(), - bool recovering = false); + const OwnershipToken* owner = 0); /** * Destroy the named queue. diff --git a/cpp/src/qpid/sys/windows/mingw32_compat.h b/cpp/src/qpid/broker/RateTracker.cpp index 51f613cc25..048349b658 100644 --- a/cpp/src/qpid/sys/windows/mingw32_compat.h +++ b/cpp/src/qpid/broker/RateTracker.cpp @@ -1,5 +1,3 @@ -#ifndef _sys_windows_mingw32_compat -#define _sys_windows_mingw32_compat /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -20,20 +18,34 @@ * under the License. * */ +#include "qpid/broker/RateTracker.h" -#ifdef WIN32 -#ifndef _MSC_VER +using qpid::sys::AbsTime; +using qpid::sys::Duration; +using qpid::sys::TIME_SEC; -// -// The following definitions for extension function GUIDs and signatures are taken from -// MswSock.h in the Windows32 SDK. These rightfully belong in the mingw32 version of -// mswsock.h, but are not included presently. -// +namespace qpid { +namespace broker { -#define WSAID_ACCEPTEX {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} -typedef BOOL (PASCAL *LPFN_ACCEPTEX)(SOCKET,SOCKET,PVOID,DWORD,DWORD,DWORD,LPDWORD,LPOVERLAPPED); +RateTracker::RateTracker() : currentCount(0), lastCount(0), lastTime(AbsTime::now()) {} -#endif -#endif +RateTracker& RateTracker::operator++() +{ + ++currentCount; + return *this; +} -#endif +double RateTracker::sampleRatePerSecond() +{ + int32_t increment = currentCount - lastCount; + AbsTime now = AbsTime::now(); + Duration interval(lastTime, now); + lastCount = currentCount; + lastTime = now; + //if sampling at higher frequency than supported, will just return the number of increments + if (interval < TIME_SEC) return increment; + else if (increment == 0) return 0; + else return increment / (interval / TIME_SEC); +} + +}} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/RateTracker.h b/cpp/src/qpid/broker/RateTracker.h new file mode 100644 index 0000000000..0c20b37312 --- /dev/null +++ b/cpp/src/qpid/broker/RateTracker.h @@ -0,0 +1,57 @@ +#ifndef QPID_BROKER_RATETRACKER_H +#define QPID_BROKER_RATETRACKER_H + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "qpid/sys/Time.h" + +namespace qpid { +namespace broker { + +/** + * Simple rate tracker: represents some value that can be incremented, + * then can periodcially sample the rate of increments. + */ +class RateTracker +{ + public: + RateTracker(); + /** + * Increments the count being tracked. Can be called concurrently + * with other calls to this operator as well as with calls to + * sampleRatePerSecond(). + */ + RateTracker& operator++(); + /** + * Returns the rate of increments per second since last + * called. Calls to this method should be serialised, but can be + * called concurrently with the increment operator + */ + double sampleRatePerSecond(); + private: + volatile int32_t currentCount; + int32_t lastCount; + qpid::sys::AbsTime lastTime; +}; +}} // namespace qpid::broker + +#endif /*!QPID_BROKER_RATETRACKER_H*/ diff --git a/cpp/src/qpid/broker/RecoveredDequeue.cpp b/cpp/src/qpid/broker/RecoveredDequeue.cpp index cd6735328f..38cb8043c9 100644 --- a/cpp/src/qpid/broker/RecoveredDequeue.cpp +++ b/cpp/src/qpid/broker/RecoveredDequeue.cpp @@ -43,6 +43,7 @@ void RecoveredDequeue::commit() throw() void RecoveredDequeue::rollback() throw() { + msg->enqueueComplete(); queue->process(msg); } diff --git a/cpp/src/qpid/broker/RecoveredEnqueue.cpp b/cpp/src/qpid/broker/RecoveredEnqueue.cpp index 6d2eaee6c4..6263c63e3d 100644 --- a/cpp/src/qpid/broker/RecoveredEnqueue.cpp +++ b/cpp/src/qpid/broker/RecoveredEnqueue.cpp @@ -36,6 +36,7 @@ bool RecoveredEnqueue::prepare(TransactionContext*) throw(){ } void RecoveredEnqueue::commit() throw(){ + msg->enqueueComplete(); queue->process(msg); } diff --git a/cpp/src/qpid/broker/RecoveryManagerImpl.cpp b/cpp/src/qpid/broker/RecoveryManagerImpl.cpp index d08409695e..2f04943581 100644 --- a/cpp/src/qpid/broker/RecoveryManagerImpl.cpp +++ b/cpp/src/qpid/broker/RecoveryManagerImpl.cpp @@ -113,7 +113,7 @@ RecoverableExchange::shared_ptr RecoveryManagerImpl::recoverExchange(framing::Bu RecoverableQueue::shared_ptr RecoveryManagerImpl::recoverQueue(framing::Buffer& buffer) { - Queue::shared_ptr queue = Queue::restore(queues, buffer); + Queue::shared_ptr queue = Queue::decode(queues, buffer, true); try { Exchange::shared_ptr exchange = exchanges.getDefault(); if (exchange) { @@ -252,6 +252,7 @@ void RecoverableMessageImpl::dequeue(DtxBuffer::shared_ptr buffer, Queue::shared void RecoverableMessageImpl::enqueue(DtxBuffer::shared_ptr buffer, Queue::shared_ptr queue) { + msg->enqueueComplete(); // recoved nmessage to enqueued in store already buffer->enlist(TxOp::shared_ptr(new RecoveredEnqueue(queue, msg))); } diff --git a/cpp/src/qpid/broker/SaslAuthenticator.cpp b/cpp/src/qpid/broker/SaslAuthenticator.cpp index d7adbd68ab..acdb4934d4 100644 --- a/cpp/src/qpid/broker/SaslAuthenticator.cpp +++ b/cpp/src/qpid/broker/SaslAuthenticator.cpp @@ -30,7 +30,6 @@ #include <boost/format.hpp> #if HAVE_SASL -#include <sys/stat.h> #include <sasl/sasl.h> #include "qpid/sys/cyrus/CyrusSecurityLayer.h" using qpid::sys::cyrus::CyrusSecurityLayer; @@ -58,7 +57,7 @@ public: NullAuthenticator(Connection& connection, bool encrypt); ~NullAuthenticator(); void getMechanisms(framing::Array& mechanisms); - void start(const std::string& mechanism, const std::string* response); + void start(const std::string& mechanism, const std::string& response); void step(const std::string&) {} std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize); }; @@ -82,7 +81,7 @@ public: ~CyrusAuthenticator(); void init(); void getMechanisms(framing::Array& mechanisms); - void start(const std::string& mechanism, const std::string* response); + void start(const std::string& mechanism, const std::string& response); void step(const std::string& response); void getError(std::string& error); void getUid(std::string& uid) { getUsername(uid); } @@ -99,33 +98,11 @@ void SaslAuthenticator::init(const std::string& saslName, std::string const & sa // Check if we have a version of SASL that supports sasl_set_path() #if (SASL_VERSION_FULL >= ((2<<16)|(1<<8)|22)) // If we are not given a sasl path, do nothing and allow the default to be used. - if ( saslConfigPath.empty() ) { - QPID_LOG ( info, "SASL: no config path set - using default." ); - } - else { - struct stat st; - - // Make sure the directory exists and we can read up to it. - if ( ::stat ( saslConfigPath.c_str(), & st) ) { - // Note: not using strerror() here because I think its messages are a little too hazy. - if ( errno == ENOENT ) - throw Exception ( QPID_MSG ( "SASL: sasl_set_path failed: no such directory: " << saslConfigPath ) ); - if ( errno == EACCES ) - throw Exception ( QPID_MSG ( "SASL: sasl_set_path failed: cannot read parent of: " << saslConfigPath ) ); - // catch-all stat failure - throw Exception ( QPID_MSG ( "SASL: sasl_set_path failed: cannot stat: " << saslConfigPath ) ); - } - - // Make sure the directory is readable. - if ( ::access ( saslConfigPath.c_str(), R_OK ) ) { - throw Exception ( QPID_MSG ( "SASL: sasl_set_path failed: directory not readable:" << saslConfigPath ) ); - } - - // This shouldn't fail now, but check anyway. - int code = sasl_set_path(SASL_PATH_TYPE_CONFIG, const_cast<char *>(saslConfigPath.c_str())); + if ( ! saslConfigPath.empty() ) { + int code = sasl_set_path(SASL_PATH_TYPE_CONFIG, + const_cast<char *>(saslConfigPath.c_str())); if(SASL_OK != code) throw Exception(QPID_MSG("SASL: sasl_set_path failed [" << code << "] " )); - QPID_LOG(info, "SASL: config path set to " << saslConfigPath ); } #endif @@ -187,7 +164,7 @@ void NullAuthenticator::getMechanisms(Array& mechanisms) mechanisms.add(boost::shared_ptr<FieldValue>(new Str16Value("PLAIN")));//useful for testing } -void NullAuthenticator::start(const string& mechanism, const string* response) +void NullAuthenticator::start(const string& mechanism, const string& response) { if (encrypt) { #if HAVE_SASL @@ -203,16 +180,16 @@ void NullAuthenticator::start(const string& mechanism, const string* response) } } if (mechanism == "PLAIN") { // Old behavior - if (response && response->size() > 0) { + if (response.size() > 0) { string uid; - string::size_type i = response->find((char)0); - if (i == 0 && response->size() > 1) { + 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); + 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); + 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 @@ -399,22 +376,18 @@ void CyrusAuthenticator::getMechanisms(Array& mechanisms) } } -void CyrusAuthenticator::start(const string& mechanism, const string* response) +void CyrusAuthenticator::start(const string& mechanism, const string& response) { const char *challenge; unsigned int challenge_len; - // This should be at same debug level as mech list in getMechanisms(). - QPID_LOG(info, "SASL: Starting authentication with mechanism: " << mechanism); + QPID_LOG(debug, "SASL: Starting authentication with mechanism: " << mechanism); int code = sasl_server_start(sasl_conn, mechanism.c_str(), - (response ? response->c_str() : 0), (response ? response->size() : 0), + response.c_str(), response.length(), &challenge, &challenge_len); processAuthenticationStep(code, challenge, challenge_len); - qmf::org::apache::qpid::broker::Connection* cnxMgmt = connection.getMgmtObject(); - if ( cnxMgmt ) - cnxMgmt->set_saslMechanism(mechanism); } void CyrusAuthenticator::step(const string& response) @@ -451,12 +424,10 @@ void CyrusAuthenticator::processAuthenticationStep(int code, const char *challen client.secure(challenge_str); } else { std::string uid; - //save error detail before trying to retrieve username as error in doing so will overwrite it - std::string errordetail = sasl_errdetail(sasl_conn); if (!getUsername(uid)) { - QPID_LOG(info, "SASL: Authentication failed (no username available yet):" << errordetail); + QPID_LOG(info, "SASL: Authentication failed (no username available):" << sasl_errdetail(sasl_conn)); } else { - QPID_LOG(info, "SASL: Authentication failed for " << uid << ":" << errordetail); + QPID_LOG(info, "SASL: Authentication failed for " << uid << ":" << sasl_errdetail(sasl_conn)); } // TODO: Change to more specific exceptions, when they are @@ -488,9 +459,6 @@ std::auto_ptr<SecurityLayer> CyrusAuthenticator::getSecurityLayer(uint16_t maxFr if (ssf) { securityLayer = std::auto_ptr<SecurityLayer>(new CyrusSecurityLayer(sasl_conn, maxFrameSize)); } - qmf::org::apache::qpid::broker::Connection* cnxMgmt = connection.getMgmtObject(); - if ( cnxMgmt ) - cnxMgmt->set_saslSsf(ssf); return securityLayer; } diff --git a/cpp/src/qpid/broker/SaslAuthenticator.h b/cpp/src/qpid/broker/SaslAuthenticator.h index 4e5d43214c..cfbe1a0cd1 100644 --- a/cpp/src/qpid/broker/SaslAuthenticator.h +++ b/cpp/src/qpid/broker/SaslAuthenticator.h @@ -41,7 +41,7 @@ class SaslAuthenticator public: virtual ~SaslAuthenticator() {} virtual void getMechanisms(framing::Array& mechanisms) = 0; - virtual void start(const std::string& mechanism, const std::string* response) = 0; + virtual void start(const std::string& mechanism, const std::string& response) = 0; virtual void step(const std::string& response) = 0; virtual void getUid(std::string&) {} virtual bool getUsername(std::string&) { return false; }; diff --git a/cpp/src/qpid/broker/SemanticState.cpp b/cpp/src/qpid/broker/SemanticState.cpp index fbcb21eab9..c91cfba2f8 100644 --- a/cpp/src/qpid/broker/SemanticState.cpp +++ b/cpp/src/qpid/broker/SemanticState.cpp @@ -70,12 +70,14 @@ SemanticState::SemanticState(DeliveryAdapter& da, SessionContext& ss) deliveryAdapter(da), tagGenerator("sgen"), dtxSelected(false), - authMsg(getSession().getBroker().getOptions().auth && !getSession().getConnection().isUserProxyAuth()), + authMsg(getSession().getBroker().getOptions().auth && !getSession().getConnection().isFederationLink()), userID(getSession().getConnection().getUserId()), userName(getSession().getConnection().getUserId().substr(0,getSession().getConnection().getUserId().find('@'))), isDefaultRealm(userID.find('@') != std::string::npos && getSession().getBroker().getOptions().realm == userID.substr(userID.find('@')+1,userID.size())), closeComplete(false) -{} +{ + acl = getSession().getBroker().getAcl(); +} SemanticState::~SemanticState() { closed(); @@ -86,7 +88,7 @@ void SemanticState::closed() { //prevent requeued messages being redelivered to consumers for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) { disable(i->second); - } + } if (dtxBuffer.get()) { dtxBuffer->fail(); } @@ -105,24 +107,16 @@ bool SemanticState::exists(const string& consumerTag){ return consumers.find(consumerTag) != consumers.end(); } -namespace { - const std::string SEPARATOR("::"); -} - -void SemanticState::consume(const string& tag, +void SemanticState::consume(const string& tag, Queue::shared_ptr queue, bool ackRequired, bool acquire, bool exclusive, const string& resumeId, uint64_t resumeTtl, const FieldTable& arguments) { - // "tag" is only guaranteed to be unique to this session (see AMQP 0-10 Message.subscribe, destination). - // Create a globally unique name so the broker can identify individual consumers - std::string name = session.getSessionId().str() + SEPARATOR + tag; - ConsumerImpl::shared_ptr c(new ConsumerImpl(this, name, queue, ackRequired, acquire, exclusive, tag, resumeId, resumeTtl, arguments)); + ConsumerImpl::shared_ptr c(new ConsumerImpl(this, tag, queue, ackRequired, acquire, exclusive, resumeId, resumeTtl, arguments)); queue->consume(c, exclusive);//may throw exception consumers[tag] = c; } -bool SemanticState::cancel(const string& tag) -{ +void SemanticState::cancel(const string& tag){ ConsumerImplMap::iterator i = consumers.find(tag); if (i != consumers.end()) { cancel(i->second); @@ -130,13 +124,7 @@ bool SemanticState::cancel(const string& tag) //should cancel all unacked messages for this consumer so that //they are not redelivered on recovery for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::cancel, _1, tag)); - //can also remove any records that are now redundant - DeliveryRecords::iterator removed = - remove_if(unacked.begin(), unacked.end(), bind(&DeliveryRecord::isRedundant, _1)); - unacked.erase(removed, unacked.end()); - return true; - } else { - return false; + } } @@ -179,8 +167,8 @@ void SemanticState::startDtx(const std::string& xid, DtxManager& mgr, bool join) if (!dtxSelected) { throw CommandInvalidException(QPID_MSG("Session has not been selected for use with dtx")); } - dtxBuffer.reset(new DtxBuffer(xid)); - txBuffer = dtxBuffer; + dtxBuffer = DtxBuffer::shared_ptr(new DtxBuffer(xid)); + txBuffer = boost::static_pointer_cast<TxBuffer>(dtxBuffer); if (join) { mgr.join(xid, dtxBuffer); } else { @@ -206,7 +194,7 @@ void SemanticState::endDtx(const std::string& xid, bool fail) dtxBuffer->fail(); } else { dtxBuffer->markEnded(); - } + } dtxBuffer.reset(); } @@ -248,7 +236,7 @@ void SemanticState::resumeDtx(const std::string& xid) checkDtxTimeout(); dtxBuffer->setSuspended(false); - txBuffer = dtxBuffer; + txBuffer = boost::static_pointer_cast<TxBuffer>(dtxBuffer); } void SemanticState::checkDtxTimeout() @@ -266,33 +254,31 @@ void SemanticState::record(const DeliveryRecord& delivery) const std::string QPID_SYNC_FREQUENCY("qpid.sync_frequency"); -SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent, - const string& _name, - Queue::shared_ptr _queue, +SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent, + const string& _name, + Queue::shared_ptr _queue, bool ack, bool _acquire, bool _exclusive, - const string& _tag, const string& _resumeId, uint64_t _resumeTtl, const framing::FieldTable& _arguments -) : - Consumer(_name, _acquire), - parent(_parent), - queue(_queue), - ackExpected(ack), +) : + Consumer(_acquire), + parent(_parent), + name(_name), + queue(_queue), + ackExpected(ack), acquire(_acquire), - blocked(true), + blocked(true), windowing(true), - windowActive(false), exclusive(_exclusive), resumeId(_resumeId), - tag(_tag), resumeTtl(_resumeTtl), arguments(_arguments), - msgCredit(0), + msgCredit(0), byteCredit(0), notifyEnabled(true), syncFrequency(_arguments.getAsInt(QPID_SYNC_FREQUENCY)), @@ -303,10 +289,10 @@ SemanticState::ConsumerImpl::ConsumerImpl(SemanticState* _parent, { ManagementAgent* agent = parent->session.getBroker().getManagementAgent(); qpid::management::Manageable* ms = dynamic_cast<qpid::management::Manageable*> (&(parent->session)); - + if (agent != 0) { - mgmtObject = new _qmf::Subscription(agent, this, ms , queue->GetManagementObject()->getObjectId(), getTag(), + mgmtObject = new _qmf::Subscription(agent, this, ms , queue->GetManagementObject()->getObjectId() ,name, !acquire, ackExpected, exclusive, ManagementAgent::toMap(arguments)); agent->addObject (mgmtObject); mgmtObject->set_creditMode("WINDOW"); @@ -338,16 +324,16 @@ bool SemanticState::ConsumerImpl::deliver(QueuedMessage& msg) { assertClusterSafe(); allocateCredit(msg.payload); - DeliveryRecord record(msg, queue, getTag(), acquire, !ackExpected, windowing); + DeliveryRecord record(msg, queue, name, acquire, !ackExpected, windowing); bool sync = syncFrequency && ++deliveryCount >= syncFrequency; if (sync) deliveryCount = 0;//reset parent->deliver(record, sync); + if (!ackExpected && acquire) record.setEnded();//allows message to be released now its been delivered if (windowing || ackExpected || !acquire) { parent->record(record); - } - if (acquire && !ackExpected) { // auto acquire && auto accept - queue->dequeue(0 /*ctxt*/, msg); - record.setEnded(); + } + if (acquire && !ackExpected) { + queue->dequeue(0, msg); } if (mgmtObject) { mgmtObject->inc_delivered(); } return true; @@ -365,7 +351,7 @@ bool SemanticState::ConsumerImpl::accept(intrusive_ptr<Message> msg) // checkCredit fails because the message is to big, we should // remain on queue's listener list for possible smaller messages // in future. - // + // blocked = !(filter(msg) && checkCredit(msg)); return !blocked; } @@ -377,7 +363,7 @@ struct ConsumerName { }; ostream& operator<<(ostream& o, const ConsumerName& pc) { - return o << pc.consumer.getTag() << " on " + return o << pc.consumer.getName() << " on " << pc.consumer.getParent().getSession().getSessionId(); } } @@ -386,7 +372,7 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg) { assertClusterSafe(); uint32_t originalMsgCredit = msgCredit; - uint32_t originalByteCredit = byteCredit; + uint32_t originalByteCredit = byteCredit; if (msgCredit != 0xFFFFFFFF) { msgCredit--; } @@ -396,7 +382,7 @@ void SemanticState::ConsumerImpl::allocateCredit(intrusive_ptr<Message>& msg) QPID_LOG(debug, "Credit allocated for " << ConsumerName(*this) << ", was " << " bytes: " << originalByteCredit << " msgs: " << originalMsgCredit << " now bytes: " << byteCredit << " msgs: " << msgCredit); - + } bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg) @@ -410,7 +396,7 @@ bool SemanticState::ConsumerImpl::checkCredit(intrusive_ptr<Message>& msg) return enoughCredit; } -SemanticState::ConsumerImpl::~ConsumerImpl() +SemanticState::ConsumerImpl::~ConsumerImpl() { if (mgmtObject != 0) mgmtObject->resourceDestroy (); @@ -428,7 +414,7 @@ void SemanticState::unsubscribe(ConsumerImpl::shared_ptr c) Queue::shared_ptr queue = c->getQueue(); if(queue) { queue->cancel(c); - if (queue->canAutoDelete() && !queue->hasExclusiveOwner()) { + if (queue->canAutoDelete() && !queue->hasExclusiveOwner()) { Queue::tryAutoDelete(session.getBroker(), queue); } } @@ -470,23 +456,23 @@ const std::string nullstring; } void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) { - msg->computeExpiration(getSession().getBroker().getExpiryPolicy()); - + msg->setTimestamp(getSession().getBroker().getExpiryPolicy()); + std::string exchangeName = msg->getExchangeName(); - if (!cacheExchange || cacheExchange->getName() != exchangeName || cacheExchange->isDestroyed()) + if (!cacheExchange || cacheExchange->getName() != exchangeName) cacheExchange = session.getBroker().getExchanges().get(exchangeName); cacheExchange->setProperties(msg); /* verify the userid if specified: */ std::string id = msg->hasProperties<MessageProperties>() ? msg->getProperties<MessageProperties>()->getUserId() : nullstring; + if (authMsg && !id.empty() && !(id == userID || (isDefaultRealm && id == userName))) { QPID_LOG(debug, "authorised user id : " << userID << " but user id in message declared as " << id); throw UnauthorizedAccessException(QPID_MSG("authorised user id : " << userID << " but user id in message declared as " << id)); } - AclModule* acl = getSession().getBroker().getAcl(); if (acl && acl->doTransferAcl()) { if (!acl->authorise(getSession().getConnection().getUserId(),acl::ACT_PUBLISH,acl::OBJ_EXCHANGE,exchangeName, msg->getRoutingKey() )) @@ -498,7 +484,7 @@ void SemanticState::route(intrusive_ptr<Message> msg, Deliverable& strategy) { if (!strategy.delivered) { //TODO:if discard-unroutable, just drop it - //TODO:else if accept-mode is explicit, reject it + //TODO:else if accept-mode is explicit, reject it //else route it to alternate exchange if (cacheExchange->getAlternate()) { cacheExchange->getAlternate()->route(strategy, msg->getRoutingKey(), msg->getApplicationHeaders()); @@ -527,7 +513,7 @@ void SemanticState::ConsumerImpl::requestDispatch() } bool SemanticState::complete(DeliveryRecord& delivery) -{ +{ ConsumerImplMap::iterator i = consumers.find(delivery.getTag()); if (i != consumers.end()) { i->second->complete(delivery); @@ -539,7 +525,7 @@ void SemanticState::ConsumerImpl::complete(DeliveryRecord& delivery) { if (!delivery.isComplete()) { delivery.complete(); - if (windowing && windowActive) { + if (windowing) { if (msgCredit != 0xFFFFFFFF) msgCredit++; if (byteCredit != 0xFFFFFFFF) byteCredit += delivery.getCredit(); } @@ -555,7 +541,7 @@ void SemanticState::recover(bool requeue) unacked.clear(); for_each(copy.rbegin(), copy.rend(), mem_fun_ref(&DeliveryRecord::requeue)); }else{ - for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::redeliver, _1, this)); + for_each(unacked.begin(), unacked.end(), boost::bind(&DeliveryRecord::redeliver, _1, this)); //unconfirmed messages re redelivered and therefore have their //id adjusted, confirmed messages are not and so the ordering //w.r.t id is lost @@ -568,61 +554,50 @@ void SemanticState::deliver(DeliveryRecord& msg, bool sync) return deliveryAdapter.deliver(msg, sync); } -const SemanticState::ConsumerImpl::shared_ptr SemanticState::find(const std::string& destination) const -{ - ConsumerImpl::shared_ptr consumer; - if (!find(destination, consumer)) { - throw NotFoundException(QPID_MSG("Unknown destination " << destination << " session=" << session.getSessionId())); - } else { - return consumer; - } -} - -bool SemanticState::find(const std::string& destination, ConsumerImpl::shared_ptr& consumer) const +SemanticState::ConsumerImpl& SemanticState::find(const std::string& destination) { - // @todo KAG gsim: shouldn't the consumers map be locked???? - ConsumerImplMap::const_iterator i = consumers.find(destination); + ConsumerImplMap::iterator i = consumers.find(destination); if (i == consumers.end()) { - return false; + throw NotFoundException(QPID_MSG("Unknown destination " << destination)); + } else { + return *(i->second); } - consumer = i->second; - return true; } void SemanticState::setWindowMode(const std::string& destination) { - find(destination)->setWindowMode(); + find(destination).setWindowMode(); } void SemanticState::setCreditMode(const std::string& destination) { - find(destination)->setCreditMode(); + find(destination).setCreditMode(); } void SemanticState::addByteCredit(const std::string& destination, uint32_t value) { - ConsumerImpl::shared_ptr c = find(destination); - c->addByteCredit(value); - c->requestDispatch(); + ConsumerImpl& c = find(destination); + c.addByteCredit(value); + c.requestDispatch(); } void SemanticState::addMessageCredit(const std::string& destination, uint32_t value) { - ConsumerImpl::shared_ptr c = find(destination); - c->addMessageCredit(value); - c->requestDispatch(); + ConsumerImpl& c = find(destination); + c.addMessageCredit(value); + c.requestDispatch(); } void SemanticState::flush(const std::string& destination) { - find(destination)->flush(); + find(destination).flush(); } void SemanticState::stop(const std::string& destination) { - find(destination)->stop(); + find(destination).stop(); } void SemanticState::ConsumerImpl::setWindowMode() @@ -646,7 +621,6 @@ void SemanticState::ConsumerImpl::setCreditMode() void SemanticState::ConsumerImpl::addByteCredit(uint32_t value) { assertClusterSafe(); - if (windowing) windowActive = true; if (byteCredit != 0xFFFFFFFF) { if (value == 0xFFFFFFFF) byteCredit = value; else byteCredit += value; @@ -656,7 +630,6 @@ void SemanticState::ConsumerImpl::addByteCredit(uint32_t value) void SemanticState::ConsumerImpl::addMessageCredit(uint32_t value) { assertClusterSafe(); - if (windowing) windowActive = true; if (msgCredit != 0xFFFFFFFF) { if (value == 0xFFFFFFFF) msgCredit = value; else msgCredit += value; @@ -677,8 +650,7 @@ void SemanticState::ConsumerImpl::flush() { while(haveCredit() && queue->dispatch(shared_from_this())) ; - msgCredit = 0; - byteCredit = 0; + stop(); } void SemanticState::ConsumerImpl::stop() @@ -686,7 +658,6 @@ void SemanticState::ConsumerImpl::stop() assertClusterSafe(); msgCredit = 0; byteCredit = 0; - windowActive = false; } Queue::shared_ptr SemanticState::getQueue(const string& name) const { @@ -702,7 +673,7 @@ Queue::shared_ptr SemanticState::getQueue(const string& name) const { } AckRange SemanticState::findRange(DeliveryId first, DeliveryId last) -{ +{ return DeliveryRecord::findRange(unacked, first, last); } @@ -720,21 +691,14 @@ void SemanticState::release(DeliveryId first, DeliveryId last, bool setRedeliver DeliveryRecords::reverse_iterator start(range.end); DeliveryRecords::reverse_iterator end(range.start); for_each(start, end, boost::bind(&DeliveryRecord::release, _1, setRedelivered)); - - DeliveryRecords::iterator removed = - remove_if(range.start, range.end, bind(&DeliveryRecord::isRedundant, _1)); - unacked.erase(removed, range.end); } void SemanticState::reject(DeliveryId first, DeliveryId last) { AckRange range = findRange(first, last); for_each(range.start, range.end, mem_fun_ref(&DeliveryRecord::reject)); - //may need to remove the delivery records as well - for (DeliveryRecords::iterator i = range.start; i != unacked.end() && i->getId() <= last; ) { - if (i->isRedundant()) i = unacked.erase(i); - else i++; - } + //need to remove the delivery records as well + unacked.erase(range.start, range.end); } bool SemanticState::ConsumerImpl::doOutput() @@ -797,13 +761,13 @@ void SemanticState::accepted(const SequenceSet& commands) { //in transactional mode, don't dequeue or remove, just //maintain set of acknowledged messages: accumulatedAck.add(commands); - + if (dtxBuffer.get()) { //if enlisted in a dtx, copy the relevant slice from //unacked and record it against that transaction TxOp::shared_ptr txAck(new DtxAck(accumulatedAck, unacked)); accumulatedAck.clear(); - dtxBuffer->enlist(txAck); + dtxBuffer->enlist(txAck); //mark the relevant messages as 'ended' in unacked //if the messages are already completed, they can be @@ -825,6 +789,7 @@ void SemanticState::accepted(const SequenceSet& commands) { } void SemanticState::completed(const SequenceSet& commands) { + assertClusterSafe(); DeliveryRecords::iterator removed = remove_if(unacked.begin(), unacked.end(), isInSequenceSetAnd(commands, @@ -835,6 +800,7 @@ void SemanticState::completed(const SequenceSet& commands) { void SemanticState::attached() { + assertClusterSafe(); for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) { i->second->enableNotify(); session.getConnection().outputTasks.addOutputTask(i->second.get()); @@ -844,6 +810,7 @@ void SemanticState::attached() void SemanticState::detached() { + assertClusterSafe(); for (ConsumerImplMap::iterator i = consumers.begin(); i != consumers.end(); i++) { i->second->disableNotify(); session.getConnection().outputTasks.removeOutputTask(i->second.get()); diff --git a/cpp/src/qpid/broker/SemanticState.h b/cpp/src/qpid/broker/SemanticState.h index 6d88dd56d9..b2e648410a 100644 --- a/cpp/src/qpid/broker/SemanticState.h +++ b/cpp/src/qpid/broker/SemanticState.h @@ -65,7 +65,7 @@ class SessionContext; * * Message delivery is driven by ConsumerImpl::doOutput(), which is * called when a client's socket is ready to write data. - * + * */ class SemanticState : private boost::noncopyable { public: @@ -75,15 +75,14 @@ class SemanticState : private boost::noncopyable { { mutable qpid::sys::Mutex lock; SemanticState* const parent; + const std::string name; const boost::shared_ptr<Queue> queue; const bool ackExpected; const bool acquire; bool blocked; bool windowing; - bool windowActive; bool exclusive; std::string resumeId; - const std::string tag; // <destination> from AMQP 0-10 Message.subscribe command uint64_t resumeTtl; framing::FieldTable arguments; uint32_t msgCredit; @@ -100,16 +99,15 @@ class SemanticState : private boost::noncopyable { public: typedef boost::shared_ptr<ConsumerImpl> shared_ptr; - ConsumerImpl(SemanticState* parent, + ConsumerImpl(SemanticState* parent, const std::string& name, boost::shared_ptr<Queue> queue, bool ack, bool acquire, bool exclusive, - const std::string& tag, const std::string& resumeId, - uint64_t resumeTtl, const framing::FieldTable& arguments); + const std::string& resumeId, uint64_t resumeTtl, const framing::FieldTable& arguments); ~ConsumerImpl(); OwnershipToken* getSession(); - bool deliver(QueuedMessage& msg); - bool filter(boost::intrusive_ptr<Message> msg); - bool accept(boost::intrusive_ptr<Message> msg); + bool deliver(QueuedMessage& msg); + bool filter(boost::intrusive_ptr<Message> msg); + bool accept(boost::intrusive_ptr<Message> msg); void disableNotify(); void enableNotify(); @@ -124,13 +122,15 @@ class SemanticState : private boost::noncopyable { void addMessageCredit(uint32_t value); void flush(); void stop(); - void complete(DeliveryRecord&); + void complete(DeliveryRecord&); boost::shared_ptr<Queue> getQueue() const { return queue; } bool isBlocked() const { return blocked; } bool setBlocked(bool set) { std::swap(set, blocked); return set; } bool doOutput(); + std::string getName() const { return name; } + bool isAckExpected() const { return ackExpected; } bool isAcquire() const { return acquire; } bool isWindowing() const { return windowing; } @@ -138,7 +138,6 @@ class SemanticState : private boost::noncopyable { uint32_t getMsgCredit() const { return msgCredit; } uint32_t getByteCredit() const { return byteCredit; } std::string getResumeId() const { return resumeId; }; - const std::string& getTag() const { return tag; } uint64_t getResumeTtl() const { return resumeTtl; } const framing::FieldTable& getArguments() const { return arguments; } @@ -149,10 +148,9 @@ class SemanticState : private boost::noncopyable { management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text); }; - typedef std::map<std::string, DtxBuffer::shared_ptr> DtxBufferMap; - private: typedef std::map<std::string, ConsumerImpl::shared_ptr> ConsumerImplMap; + typedef std::map<std::string, DtxBuffer::shared_ptr> DtxBufferMap; SessionContext& session; DeliveryAdapter& deliveryAdapter; @@ -165,6 +163,7 @@ class SemanticState : private boost::noncopyable { DtxBufferMap suspendedXids; framing::SequenceSet accumulatedAck; boost::shared_ptr<Exchange> cacheExchange; + AclModule* acl; const bool authMsg; const std::string userID; const std::string userName; @@ -182,16 +181,14 @@ class SemanticState : private boost::noncopyable { void disable(ConsumerImpl::shared_ptr); public: - SemanticState(DeliveryAdapter&, SessionContext&); ~SemanticState(); SessionContext& getSession() { return session; } const SessionContext& getSession() const { return session; } - const ConsumerImpl::shared_ptr find(const std::string& destination) const; - bool find(const std::string& destination, ConsumerImpl::shared_ptr&) const; - + ConsumerImpl& find(const std::string& destination); + /** * Get named queue, never returns 0. * @return: named queue @@ -199,16 +196,16 @@ class SemanticState : private boost::noncopyable { * @exception: ConnectionException if name="" and session has no default. */ boost::shared_ptr<Queue> getQueue(const std::string& name) const; - + bool exists(const std::string& consumerTag); - void consume(const std::string& destination, - boost::shared_ptr<Queue> queue, + void consume(const std::string& destination, + boost::shared_ptr<Queue> queue, bool ackRequired, bool acquire, bool exclusive, const std::string& resumeId=std::string(), uint64_t resumeTtl=0, const framing::FieldTable& = framing::FieldTable()); - bool cancel(const std::string& tag); + void cancel(const std::string& tag); void setWindowMode(const std::string& destination); void setCreditMode(const std::string& destination); @@ -221,13 +218,12 @@ class SemanticState : private boost::noncopyable { void commit(MessageStore* const store); void rollback(); void selectDtx(); - bool getDtxSelected() const { return dtxSelected; } void startDtx(const std::string& xid, DtxManager& mgr, bool join); void endDtx(const std::string& xid, bool fail); void suspendDtx(const std::string& xid); void resumeDtx(const std::string& xid); void recover(bool requeue); - void deliver(DeliveryRecord& message, bool sync); + void deliver(DeliveryRecord& message, bool sync); void acquire(DeliveryId first, DeliveryId last, DeliveryIds& acquired); void release(DeliveryId first, DeliveryId last, bool setRedelivered); void reject(DeliveryId first, DeliveryId last); @@ -248,12 +244,9 @@ class SemanticState : private boost::noncopyable { DeliveryRecords& getUnacked() { return unacked; } framing::SequenceSet getAccumulatedAck() const { return accumulatedAck; } TxBuffer::shared_ptr getTxBuffer() const { return txBuffer; } - DtxBuffer::shared_ptr getDtxBuffer() const { return dtxBuffer; } void setTxBuffer(const TxBuffer::shared_ptr& txb) { txBuffer = txb; } - void setDtxBuffer(const DtxBuffer::shared_ptr& dtxb) { dtxBuffer = dtxb; txBuffer = dtxb; } void setAccumulatedAck(const framing::SequenceSet& s) { accumulatedAck = s; } void record(const DeliveryRecord& delivery); - DtxBufferMap& getSuspendedXids() { return suspendedXids; } }; }} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/SessionAdapter.cpp b/cpp/src/qpid/broker/SessionAdapter.cpp index 63c4b660b2..3d62e73185 100644 --- a/cpp/src/qpid/broker/SessionAdapter.cpp +++ b/cpp/src/qpid/broker/SessionAdapter.cpp @@ -24,7 +24,6 @@ #include "qpid/log/Statement.h" #include "qpid/framing/SequenceSet.h" #include "qpid/management/ManagementAgent.h" -#include "qpid/broker/SessionState.h" #include "qmf/org/apache/qpid/broker/EventExchangeDeclare.h" #include "qmf/org/apache/qpid/broker/EventExchangeDelete.h" #include "qmf/org/apache/qpid/broker/EventQueueDeclare.h" @@ -65,56 +64,53 @@ void SessionAdapter::ExchangeHandlerImpl::declare(const string& exchange, const const string& alternateExchange, bool passive, bool durable, bool /*autoDelete*/, const FieldTable& args){ + AclModule* acl = getBroker().getAcl(); + if (acl) { + std::map<acl::Property, std::string> params; + params.insert(make_pair(acl::PROP_TYPE, type)); + params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange)); + params.insert(make_pair(acl::PROP_PASSIVE, std::string(passive ? _TRUE : _FALSE) )); + params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE))); + if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_EXCHANGE,exchange,¶ms) ) + throw UnauthorizedAccessException(QPID_MSG("ACL denied exchange declare request from " << getConnection().getUserId())); + } + //TODO: implement autoDelete Exchange::shared_ptr alternate; if (!alternateExchange.empty()) { alternate = getBroker().getExchanges().get(alternateExchange); } if(passive){ - AclModule* acl = getBroker().getAcl(); - if (acl) { - //TODO: why does a passive declare require create - //permission? The purpose of the passive flag is to state - //that the exchange should *not* created. For - //authorisation a passive declare is similar to - //exchange-query. - std::map<acl::Property, std::string> params; - params.insert(make_pair(acl::PROP_TYPE, type)); - params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange)); - params.insert(make_pair(acl::PROP_PASSIVE, _TRUE)); - params.insert(make_pair(acl::PROP_DURABLE, durable ? _TRUE : _FALSE)); - if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_EXCHANGE,exchange,¶ms) ) - throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied exchange create request from " << getConnection().getUserId())); - } Exchange::shared_ptr actual(getBroker().getExchanges().get(exchange)); checkType(actual, type); checkAlternate(actual, alternate); - }else{ + }else{ if(exchange.find("amq.") == 0 || exchange.find("qpid.") == 0) { throw framing::NotAllowedException(QPID_MSG("Exchange names beginning with \"amq.\" or \"qpid.\" are reserved. (exchange=\"" << exchange << "\")")); } try{ - std::pair<Exchange::shared_ptr, bool> response = - getBroker().createExchange(exchange, type, durable, alternateExchange, args, - getConnection().getUserId(), getConnection().getUrl()); - if (!response.second) { - //exchange already there, not created + std::pair<Exchange::shared_ptr, bool> response = getBroker().getExchanges().declare(exchange, type, durable, args); + if (response.second) { + if (alternate) { + response.first->setAlternate(alternate); + alternate->incAlternateUsers(); + } + if (durable) { + getBroker().getStore().create(*response.first, args); + } + } else { checkType(response.first, type); checkAlternate(response.first, alternate); - ManagementAgent* agent = getBroker().getManagementAgent(); - if (agent) - agent->raiseEvent(_qmf::EventExchangeDeclare(getConnection().getUrl(), - getConnection().getUserId(), - exchange, - type, - alternateExchange, - durable, - false, - ManagementAgent::toMap(args), - "existing")); } + + ManagementAgent* agent = getBroker().getManagementAgent(); + if (agent) + agent->raiseEvent(_qmf::EventExchangeDeclare(getConnection().getUrl(), getConnection().getUserId(), exchange, type, + alternateExchange, durable, false, ManagementAgent::toMap(args), + response.second ? "created" : "existing")); + }catch(UnknownExchangeTypeException& /*e*/){ - throw NotFoundException(QPID_MSG("Exchange type not implemented: " << type)); + throw CommandInvalidException(QPID_MSG("Exchange type not implemented: " << type)); } } } @@ -138,8 +134,22 @@ void SessionAdapter::ExchangeHandlerImpl::checkAlternate(Exchange::shared_ptr ex void SessionAdapter::ExchangeHandlerImpl::delete_(const string& name, bool /*ifUnused*/) { - //TODO: implement if-unused - getBroker().deleteExchange(name, getConnection().getUserId(), getConnection().getUrl()); + AclModule* acl = getBroker().getAcl(); + if (acl) { + if (!acl->authorise(getConnection().getUserId(),acl::ACT_DELETE,acl::OBJ_EXCHANGE,name,NULL) ) + throw UnauthorizedAccessException(QPID_MSG("ACL denied exchange delete request from " << getConnection().getUserId())); + } + + //TODO: implement unused + Exchange::shared_ptr exchange(getBroker().getExchanges().get(name)); + if (exchange->inUseAsAlternate()) throw NotAllowedException(QPID_MSG("Exchange in use as alternate-exchange.")); + if (exchange->isDurable()) getBroker().getStore().destroy(*exchange); + if (exchange->getAlternate()) exchange->getAlternate()->decAlternateUsers(); + getBroker().getExchanges().destroy(name); + + ManagementAgent* agent = getBroker().getManagementAgent(); + if (agent) + agent->raiseEvent(_qmf::EventExchangeDelete(getConnection().getUrl(), getConnection().getUserId(), name)); } ExchangeQueryResult SessionAdapter::ExchangeHandlerImpl::query(const string& name) @@ -159,19 +169,67 @@ ExchangeQueryResult SessionAdapter::ExchangeHandlerImpl::query(const string& nam } void SessionAdapter::ExchangeHandlerImpl::bind(const string& queueName, - const string& exchangeName, const string& routingKey, - const FieldTable& arguments) + const string& exchangeName, const string& routingKey, + const FieldTable& arguments) { - getBroker().bind(queueName, exchangeName, routingKey, arguments, - getConnection().getUserId(), getConnection().getUrl()); + AclModule* acl = getBroker().getAcl(); + if (acl) { + std::map<acl::Property, std::string> params; + params.insert(make_pair(acl::PROP_QUEUENAME, queueName)); + params.insert(make_pair(acl::PROP_ROUTINGKEY, routingKey)); + + if (!acl->authorise(getConnection().getUserId(),acl::ACT_BIND,acl::OBJ_EXCHANGE,exchangeName,¶ms)) + throw UnauthorizedAccessException(QPID_MSG("ACL denied exchange bind request from " << getConnection().getUserId())); + } + + Queue::shared_ptr queue = getQueue(queueName); + Exchange::shared_ptr exchange = getBroker().getExchanges().get(exchangeName); + if(exchange){ + string exchangeRoutingKey = routingKey.empty() && queueName.empty() ? queue->getName() : routingKey; + if (exchange->bind(queue, exchangeRoutingKey, &arguments)) { + queue->bound(exchangeName, routingKey, arguments); + if (exchange->isDurable() && queue->isDurable()) { + getBroker().getStore().bind(*exchange, *queue, routingKey, arguments); + } + + ManagementAgent* agent = getBroker().getManagementAgent(); + if (agent) + agent->raiseEvent(_qmf::EventBind(getConnection().getUrl(), getConnection().getUserId(), exchangeName, + queueName, exchangeRoutingKey, ManagementAgent::toMap(arguments))); + } + }else{ + throw NotFoundException("Bind failed. No such exchange: " + exchangeName); + } } void SessionAdapter::ExchangeHandlerImpl::unbind(const string& queueName, const string& exchangeName, const string& routingKey) { - getBroker().unbind(queueName, exchangeName, routingKey, - getConnection().getUserId(), getConnection().getUrl()); + AclModule* acl = getBroker().getAcl(); + if (acl) { + std::map<acl::Property, std::string> params; + params.insert(make_pair(acl::PROP_QUEUENAME, queueName)); + params.insert(make_pair(acl::PROP_ROUTINGKEY, routingKey)); + if (!acl->authorise(getConnection().getUserId(),acl::ACT_UNBIND,acl::OBJ_EXCHANGE,exchangeName,¶ms) ) + throw UnauthorizedAccessException(QPID_MSG("ACL denied exchange unbind request from " << getConnection().getUserId())); + } + + Queue::shared_ptr queue = getQueue(queueName); + if (!queue.get()) throw NotFoundException("Unbind failed. No such exchange: " + exchangeName); + + Exchange::shared_ptr exchange = getBroker().getExchanges().get(exchangeName); + if (!exchange.get()) throw NotFoundException("Unbind failed. No such exchange: " + exchangeName); + + //TODO: revise unbind to rely solely on binding key (not args) + if (exchange->unbind(queue, routingKey, 0)) { + if (exchange->isDurable() && queue->isDurable()) + getBroker().getStore().unbind(*exchange, *queue, routingKey, FieldTable()); + + ManagementAgent* agent = getBroker().getManagementAgent(); + if (agent) + agent->raiseEvent(_qmf::EventUnbind(getConnection().getUrl(), getConnection().getUserId(), exchangeName, queueName, routingKey)); + } } ExchangeBoundResult SessionAdapter::ExchangeHandlerImpl::bound(const std::string& exchangeName, @@ -274,42 +332,52 @@ QueueQueryResult SessionAdapter::QueueHandlerImpl::query(const string& name) void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string& alternateExchange, bool passive, bool durable, bool exclusive, bool autoDelete, const qpid::framing::FieldTable& arguments) -{ +{ + AclModule* acl = getBroker().getAcl(); + if (acl) { + std::map<acl::Property, std::string> params; + params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange)); + params.insert(make_pair(acl::PROP_PASSIVE, std::string(passive ? _TRUE : _FALSE) )); + params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE))); + params.insert(make_pair(acl::PROP_EXCLUSIVE, std::string(exclusive ? _TRUE : _FALSE))); + params.insert(make_pair(acl::PROP_AUTODELETE, std::string(autoDelete ? _TRUE : _FALSE))); + params.insert(make_pair(acl::PROP_POLICYTYPE, arguments.getAsString("qpid.policy_type"))); + params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.max_count")))); + params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.max_size")))); + + if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_QUEUE,name,¶ms) ) + throw UnauthorizedAccessException(QPID_MSG("ACL denied queue create request from " << getConnection().getUserId())); + } + + Exchange::shared_ptr alternate; + if (!alternateExchange.empty()) { + alternate = getBroker().getExchanges().get(alternateExchange); + } Queue::shared_ptr queue; if (passive && !name.empty()) { - AclModule* acl = getBroker().getAcl(); - if (acl) { - //TODO: why does a passive declare require create - //permission? The purpose of the passive flag is to state - //that the queue should *not* created. For - //authorisation a passive declare is similar to - //queue-query (or indeed a qmf query). - std::map<acl::Property, std::string> params; - params.insert(make_pair(acl::PROP_ALTERNATE, alternateExchange)); - params.insert(make_pair(acl::PROP_PASSIVE, _TRUE)); - params.insert(make_pair(acl::PROP_DURABLE, std::string(durable ? _TRUE : _FALSE))); - params.insert(make_pair(acl::PROP_EXCLUSIVE, std::string(exclusive ? _TRUE : _FALSE))); - params.insert(make_pair(acl::PROP_AUTODELETE, std::string(autoDelete ? _TRUE : _FALSE))); - params.insert(make_pair(acl::PROP_POLICYTYPE, arguments.getAsString("qpid.policy_type"))); - params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.max_count")))); - params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.max_size")))); - if (!acl->authorise(getConnection().getUserId(),acl::ACT_CREATE,acl::OBJ_QUEUE,name,¶ms) ) - throw UnauthorizedAccessException(QPID_MSG("ACL denied queue create request from " << getConnection().getUserId())); - } - queue = getQueue(name); + queue = getQueue(name); //TODO: check alternate-exchange is as expected } else { - std::pair<Queue::shared_ptr, bool> queue_created = - getBroker().createQueue(name, durable, - autoDelete, - exclusive ? &session : 0, - alternateExchange, - arguments, - getConnection().getUserId(), - getConnection().getUrl()); + std::pair<Queue::shared_ptr, bool> queue_created = + getBroker().getQueues().declare(name, durable, + autoDelete, + exclusive ? &session : 0); queue = queue_created.first; assert(queue); if (queue_created.second) { // This is a new queue + if (alternate) { + queue->setAlternateExchange(alternate); + alternate->incAlternateUsers(); + } + + //apply settings & create persistent record if required + try { queue_created.first->create(arguments); } + catch (...) { getBroker().getQueues().destroy(name); throw; } + + //add default binding: + getBroker().getExchanges().getDefault()->bind(queue, name, 0); + queue->bound(getBroker().getExchanges().getDefault()->getName(), name, arguments); + //handle automatic cleanup: if (exclusive) { exclusiveQueues.push_back(queue); @@ -318,20 +386,21 @@ void SessionAdapter::QueueHandlerImpl::declare(const string& name, const string& if (exclusive && queue->setExclusiveOwner(&session)) { exclusiveQueues.push_back(queue); } - ManagementAgent* agent = getBroker().getManagementAgent(); - if (agent) - agent->raiseEvent(_qmf::EventQueueDeclare(getConnection().getUrl(), getConnection().getUserId(), - name, durable, exclusive, autoDelete, ManagementAgent::toMap(arguments), - "existing")); } + ManagementAgent* agent = getBroker().getManagementAgent(); + if (agent) + agent->raiseEvent(_qmf::EventQueueDeclare(getConnection().getUrl(), getConnection().getUserId(), + name, durable, exclusive, autoDelete, ManagementAgent::toMap(arguments), + queue_created.second ? "created" : "existing")); } - if (exclusive && !queue->isExclusiveOwner(&session)) + if (exclusive && !queue->isExclusiveOwner(&session)) throw ResourceLockedException(QPID_MSG("Cannot grant exclusive access to queue " << queue->getName())); -} - +} + + void SessionAdapter::QueueHandlerImpl::purge(const string& queue){ AclModule* acl = getBroker().getAcl(); if (acl) @@ -340,32 +409,40 @@ void SessionAdapter::QueueHandlerImpl::purge(const string& queue){ throw UnauthorizedAccessException(QPID_MSG("ACL denied queue purge request from " << getConnection().getUserId())); } getQueue(queue)->purge(); -} +} + +void SessionAdapter::QueueHandlerImpl::delete_(const string& queue, bool ifUnused, bool ifEmpty){ -void SessionAdapter::QueueHandlerImpl::checkDelete(Queue::shared_ptr queue, bool ifUnused, bool ifEmpty) -{ - if (queue->hasExclusiveOwner() && !queue->isExclusiveOwner(&session)) { + AclModule* acl = getBroker().getAcl(); + if (acl) + { + if (!acl->authorise(getConnection().getUserId(),acl::ACT_DELETE,acl::OBJ_QUEUE,queue,NULL) ) + throw UnauthorizedAccessException(QPID_MSG("ACL denied queue delete request from " << getConnection().getUserId())); + } + + Queue::shared_ptr q = getQueue(queue); + if (q->hasExclusiveOwner() && !q->isExclusiveOwner(&session)) throw ResourceLockedException(QPID_MSG("Cannot delete queue " - << queue->getName() << "; it is exclusive to another session")); - } else if(ifEmpty && queue->getMessageCount() > 0) { - throw PreconditionFailedException(QPID_MSG("Cannot delete queue " - << queue->getName() << "; queue not empty")); - } else if(ifUnused && queue->getConsumerCount() > 0) { - throw PreconditionFailedException(QPID_MSG("Cannot delete queue " - << queue->getName() << "; queue in use")); - } else if (queue->isExclusiveOwner(&session)) { + << queue << "; it is exclusive to another session")); + if(ifEmpty && q->getMessageCount() > 0){ + throw PreconditionFailedException("Queue not empty."); + }else if(ifUnused && q->getConsumerCount() > 0){ + throw PreconditionFailedException("Queue in use."); + }else{ //remove the queue from the list of exclusive queues if necessary - QueueVector::iterator i = std::find(exclusiveQueues.begin(), - exclusiveQueues.end(), - queue); - if (i < exclusiveQueues.end()) exclusiveQueues.erase(i); - } -} - -void SessionAdapter::QueueHandlerImpl::delete_(const string& queue, bool ifUnused, bool ifEmpty) -{ - getBroker().deleteQueue(queue, getConnection().getUserId(), getConnection().getUrl(), - boost::bind(&SessionAdapter::QueueHandlerImpl::checkDelete, this, _1, ifUnused, ifEmpty)); + if(q->isExclusiveOwner(&getConnection())){ + QueueVector::iterator i = std::find(getConnection().exclusiveQueues.begin(), getConnection().exclusiveQueues.end(), q); + if(i < getConnection().exclusiveQueues.end()) getConnection().exclusiveQueues.erase(i); + } + q->destroy(); + getBroker().getQueues().destroy(queue); + q->unbind(getBroker().getExchanges(), q); + + ManagementAgent* agent = getBroker().getManagementAgent(); + if (agent) + agent->raiseEvent(_qmf::EventQueueDelete(getConnection().getUrl(), getConnection().getUserId(), queue)); + q->notifyDeleted(); + } } SessionAdapter::MessageHandlerImpl::MessageHandlerImpl(SemanticState& s) : @@ -431,9 +508,7 @@ SessionAdapter::MessageHandlerImpl::subscribe(const string& queueName, void SessionAdapter::MessageHandlerImpl::cancel(const string& destination ) { - if (!state.cancel(destination)) { - throw NotFoundException(QPID_MSG("No such subscription: " << destination)); - } + state.cancel(destination); ManagementAgent* agent = getBroker().getManagementAgent(); if (agent) @@ -512,12 +587,7 @@ framing::MessageResumeResult SessionAdapter::MessageHandlerImpl::resume(const st -void SessionAdapter::ExecutionHandlerImpl::sync() -{ - session.addPendingExecutionSync(); - /** @todo KAG - need a generic mechanism to allow a command to returning "not completed" status back to SessionState */ - -} +void SessionAdapter::ExecutionHandlerImpl::sync() {} //essentially a no-op void SessionAdapter::ExecutionHandlerImpl::result(const SequenceNumber& /*commandId*/, const string& /*value*/) { diff --git a/cpp/src/qpid/broker/SessionAdapter.h b/cpp/src/qpid/broker/SessionAdapter.h index 8987c4812f..ca27fb6e1d 100644 --- a/cpp/src/qpid/broker/SessionAdapter.h +++ b/cpp/src/qpid/broker/SessionAdapter.h @@ -138,7 +138,6 @@ class Queue; bool isLocal(const ConnectionToken* t) const; void destroyExclusiveQueues(); - void checkDelete(boost::shared_ptr<Queue> queue, bool ifUnused, bool ifEmpty); template <class F> void eachExclusiveQueue(F f) { std::for_each(exclusiveQueues.begin(), exclusiveQueues.end(), f); diff --git a/cpp/src/qpid/broker/SessionContext.h b/cpp/src/qpid/broker/SessionContext.h index 253ce8dcf2..afbbb2cc22 100644 --- a/cpp/src/qpid/broker/SessionContext.h +++ b/cpp/src/qpid/broker/SessionContext.h @@ -46,7 +46,6 @@ class SessionContext : public OwnershipToken, public sys::OutputControl virtual Broker& getBroker() = 0; virtual uint16_t getChannel() const = 0; virtual const SessionId& getSessionId() const = 0; - virtual void addPendingExecutionSync() = 0; }; }} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/SessionHandler.cpp b/cpp/src/qpid/broker/SessionHandler.cpp index 752fa55535..69b364ad7b 100644 --- a/cpp/src/qpid/broker/SessionHandler.cpp +++ b/cpp/src/qpid/broker/SessionHandler.cpp @@ -40,6 +40,11 @@ SessionHandler::SessionHandler(Connection& c, ChannelId ch) SessionHandler::~SessionHandler() {} +namespace { +ClassId classId(AMQMethodBody* m) { return m ? m->amqpMethodId() : 0; } +MethodId methodId(AMQMethodBody* m) { return m ? m->amqpClassId() : 0; } +} // namespace + void SessionHandler::connectionException(framing::connection::CloseCode code, const std::string& msg) { // NOTE: must tell the error listener _before_ calling connection.close() if (connection.getErrorListener()) connection.getErrorListener()->connectionError(msg); diff --git a/cpp/src/qpid/broker/SessionState.cpp b/cpp/src/qpid/broker/SessionState.cpp index 1ab17e9893..1ca7b6dfc1 100644 --- a/cpp/src/qpid/broker/SessionState.cpp +++ b/cpp/src/qpid/broker/SessionState.cpp @@ -25,7 +25,6 @@ #include "qpid/broker/SessionManager.h" #include "qpid/broker/SessionHandler.h" #include "qpid/broker/RateFlowcontrol.h" -#include "qpid/sys/ClusterSafe.h" #include "qpid/sys/Timer.h" #include "qpid/framing/AMQContentBody.h" #include "qpid/framing/AMQHeaderBody.h" @@ -61,9 +60,9 @@ SessionState::SessionState( semanticState(*this, *this), adapter(semanticState), msgBuilder(&broker.getStore()), + enqueuedOp(boost::bind(&SessionState::enqueued, this, _1)), mgmtObject(0), - rateFlowcontrol(0), - asyncCommandCompleter(new AsyncCommandCompleter(this)) + rateFlowcontrol(0) { uint32_t maxRate = broker.getOptions().maxSessionRate; if (maxRate) { @@ -96,7 +95,6 @@ void SessionState::addManagementObject() { } SessionState::~SessionState() { - asyncCommandCompleter->cancel(); semanticState.closed(); if (mgmtObject != 0) mgmtObject->resourceDestroy (); @@ -127,7 +125,6 @@ bool SessionState::isLocal(const ConnectionToken* t) const void SessionState::detach() { QPID_LOG(debug, getId() << ": detached on broker."); - asyncCommandCompleter->detached(); disableOutput(); handler = 0; if (mgmtObject != 0) @@ -148,7 +145,6 @@ void SessionState::attach(SessionHandler& h) { mgmtObject->set_connectionRef (h.getConnection().GetManagementObject()->getObjectId()); mgmtObject->set_channelId (h.getChannel()); } - asyncCommandCompleter->attached(); } void SessionState::abort() { @@ -206,17 +202,15 @@ Manageable::status_t SessionState::ManagementMethod (uint32_t methodId, } void SessionState::handleCommand(framing::AMQMethodBody* method, const SequenceNumber& id) { - currentCommandComplete = true; // assumed, can be overridden by invoker method (this sucks). Invoker::Result invocation = invoke(adapter, *method); - if (currentCommandComplete) receiverCompleted(id); - + receiverCompleted(id); if (!invocation.wasHandled()) { throw NotImplementedException(QPID_MSG("Not implemented: " << *method)); } else if (invocation.hasResult()) { getProxy().getExecution().result(id, invocation.getResult()); } - - if (method->isSync() && currentCommandComplete) { + if (method->isSync()) { + incomplete.process(enqueuedOp, true); sendAcceptAndCompletion(); } } @@ -259,14 +253,23 @@ void SessionState::handleContent(AMQFrame& frame, const SequenceNumber& id) header.setEof(false); msg->getFrames().append(header); } - if (broker.isTimestamping()) - msg->setTimestamp(); msg->setPublisher(&getConnection()); - msg->getIngressCompletion().begin(); semanticState.handle(msg); msgBuilder.end(); - IncompleteIngressMsgXfer xfer(this, msg); - msg->getIngressCompletion().end(xfer); // allows msg to complete xfer + + if (msg->isEnqueueComplete()) { + enqueued(msg); + } else { + incomplete.add(msg); + } + + //hold up execution until async enqueue is complete + if (msg->getFrames().getMethod()->isSync()) { + incomplete.process(enqueuedOp, true); + sendAcceptAndCompletion(); + } else { + incomplete.process(enqueuedOp, false); + } } // Handle producer session flow control @@ -316,41 +319,11 @@ void SessionState::sendAcceptAndCompletion() sendCompletion(); } -/** Invoked when the given inbound message is finished being processed - * by all interested parties (eg. it is done being enqueued to all queues, - * its credit has been accounted for, etc). At this point, msg is considered - * by this receiver as 'completed' (as defined by AMQP 0_10) - */ -void SessionState::completeRcvMsg(SequenceNumber id, - bool requiresAccept, - bool requiresSync) +void SessionState::enqueued(boost::intrusive_ptr<Message> msg) { - // Mark this as a cluster-unsafe scope since it can be called in - // journal threads or connection threads as part of asynchronous - // command completion. - sys::ClusterUnsafeScope cus; - - bool callSendCompletion = false; - receiverCompleted(id); - if (requiresAccept) - // will cause msg's seq to appear in the next message.accept we send. - accepted.add(id); - - // Are there any outstanding Execution.Sync commands pending the - // completion of this msg? If so, complete them. - while (!pendingExecutionSyncs.empty() && - receiverGetIncomplete().front() >= pendingExecutionSyncs.front()) { - const SequenceNumber id = pendingExecutionSyncs.front(); - pendingExecutionSyncs.pop(); - QPID_LOG(debug, getId() << ": delayed execution.sync " << id << " is completed."); - receiverCompleted(id); - callSendCompletion = true; // likely peer is pending for this completion. - } - - // if the sender has requested immediate notification of the completion... - if (requiresSync || callSendCompletion) { - sendAcceptAndCompletion(); - } + receiverCompleted(msg->getCommandId()); + if (msg->requiresAccept()) + accepted.add(msg->getCommandId()); } void SessionState::handleIn(AMQFrame& frame) { @@ -423,176 +396,4 @@ framing::AMQP_ClientProxy& SessionState::getClusterOrderProxy() { return handler->getClusterOrderProxy(); } - -// Current received command is an execution.sync command. -// Complete this command only when all preceding commands have completed. -// (called via the invoker() in handleCommand() above) -void SessionState::addPendingExecutionSync() -{ - SequenceNumber syncCommandId = receiverGetCurrent(); - if (receiverGetIncomplete().front() < syncCommandId) { - currentCommandComplete = false; - pendingExecutionSyncs.push(syncCommandId); - asyncCommandCompleter->flushPendingMessages(); - QPID_LOG(debug, getId() << ": delaying completion of execution.sync " << syncCommandId); - } -} - - -/** factory for creating a reference-counted IncompleteIngressMsgXfer object - * which will be attached to a message that will be completed asynchronously. - */ -boost::intrusive_ptr<AsyncCompletion::Callback> -SessionState::IncompleteIngressMsgXfer::clone() -{ - // Optimization: this routine is *only* invoked when the message needs to be asynchronously completed. - // If the client is pending the message.transfer completion, flush now to force immediate write to journal. - if (requiresSync) - msg->flush(); - else { - // otherwise, we need to track this message in order to flush it if an execution.sync arrives - // before it has been completed (see flushPendingMessages()) - pending = true; - completerContext->addPendingMessage(msg); - } - - return boost::intrusive_ptr<SessionState::IncompleteIngressMsgXfer>(new SessionState::IncompleteIngressMsgXfer(*this)); -} - - -/** Invoked by the asynchronous completer associated with a received - * msg that is pending Completion. May be invoked by the IO thread - * (sync == true), or some external thread (!sync). - */ -void SessionState::IncompleteIngressMsgXfer::completed(bool sync) -{ - if (pending) completerContext->deletePendingMessage(id); - if (!sync) { - /** note well: this path may execute in any thread. It is safe to access - * the scheduledCompleterContext, since *this has a shared pointer to it. - * but not session! - */ - session = 0; - QPID_LOG(debug, ": async completion callback scheduled for msg seq=" << id); - completerContext->scheduleMsgCompletion(id, requiresAccept, requiresSync); - } else { - // this path runs directly from the ac->end() call in handleContent() above, - // so *session is definately valid. - if (session->isAttached()) { - QPID_LOG(debug, ": receive completed for msg seq=" << id); - session->completeRcvMsg(id, requiresAccept, requiresSync); - } - } - completerContext = boost::intrusive_ptr<AsyncCommandCompleter>(); -} - - -/** Scheduled from an asynchronous command's completed callback to run on - * the IO thread. - */ -void SessionState::AsyncCommandCompleter::schedule(boost::intrusive_ptr<AsyncCommandCompleter> ctxt) -{ - ctxt->completeCommands(); -} - - -/** Track an ingress message that is pending completion */ -void SessionState::AsyncCommandCompleter::addPendingMessage(boost::intrusive_ptr<Message> msg) -{ - qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock); - std::pair<SequenceNumber, boost::intrusive_ptr<Message> > item(msg->getCommandId(), msg); - bool unique = pendingMsgs.insert(item).second; - if (!unique) { - assert(false); - } -} - - -/** pending message has completed */ -void SessionState::AsyncCommandCompleter::deletePendingMessage(SequenceNumber id) -{ - qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock); - pendingMsgs.erase(id); -} - - -/** done when an execution.sync arrives */ -void SessionState::AsyncCommandCompleter::flushPendingMessages() -{ - std::map<SequenceNumber, boost::intrusive_ptr<Message> > copy; - { - qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock); - pendingMsgs.swap(copy); // we've only tracked these in case a flush is needed, so nuke 'em now. - } - // drop lock, so it is safe to call "flush()" - for (std::map<SequenceNumber, boost::intrusive_ptr<Message> >::iterator i = copy.begin(); - i != copy.end(); ++i) { - i->second->flush(); - } -} - - -/** mark an ingress Message.Transfer command as completed. - * This method must be thread safe - it may run on any thread. - */ -void SessionState::AsyncCommandCompleter::scheduleMsgCompletion(SequenceNumber cmd, - bool requiresAccept, - bool requiresSync) -{ - qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock); - - if (session && isAttached) { - MessageInfo msg(cmd, requiresAccept, requiresSync); - completedMsgs.push_back(msg); - if (completedMsgs.size() == 1) { - session->getConnection().requestIOProcessing(boost::bind(&schedule, - session->asyncCommandCompleter)); - } - } -} - - -/** Cause the session to complete all completed commands. - * Executes on the IO thread. - */ -void SessionState::AsyncCommandCompleter::completeCommands() -{ - qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock); - - // when session is destroyed, it clears the session pointer via cancel(). - if (session && session->isAttached()) { - for (std::vector<MessageInfo>::iterator msg = completedMsgs.begin(); - msg != completedMsgs.end(); ++msg) { - session->completeRcvMsg(msg->cmd, msg->requiresAccept, msg->requiresSync); - } - } - completedMsgs.clear(); -} - - -/** cancel any pending calls to scheduleComplete */ -void SessionState::AsyncCommandCompleter::cancel() -{ - qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock); - session = 0; -} - - -/** inform the completer that the session has attached, - * allows command completion scheduling from any thread */ -void SessionState::AsyncCommandCompleter::attached() -{ - qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock); - isAttached = true; -} - - -/** inform the completer that the session has detached, - * disables command completion scheduling from any thread */ -void SessionState::AsyncCommandCompleter::detached() -{ - qpid::sys::ScopedLock<qpid::sys::Mutex> l(completerLock); - isAttached = false; -} - }} // namespace qpid::broker diff --git a/cpp/src/qpid/broker/SessionState.h b/cpp/src/qpid/broker/SessionState.h index 506af85c47..be79eb0eab 100644 --- a/cpp/src/qpid/broker/SessionState.h +++ b/cpp/src/qpid/broker/SessionState.h @@ -30,15 +30,13 @@ #include "qmf/org/apache/qpid/broker/Session.h" #include "qpid/broker/SessionAdapter.h" #include "qpid/broker/DeliveryAdapter.h" -#include "qpid/broker/AsyncCompletion.h" +#include "qpid/broker/IncompleteMessageList.h" #include "qpid/broker/MessageBuilder.h" #include "qpid/broker/SessionContext.h" #include "qpid/broker/SemanticState.h" -#include "qpid/sys/Monitor.h" #include <boost/noncopyable.hpp> #include <boost/scoped_ptr.hpp> -#include <boost/intrusive_ptr.hpp> #include <set> #include <vector> @@ -125,10 +123,6 @@ class SessionState : public qpid::SessionState, const SessionId& getSessionId() const { return getId(); } - // Used by ExecutionHandler sync command processing. Notifies - // the SessionState of a received Execution.Sync command. - void addPendingExecutionSync(); - // Used to delay creation of management object for sessions // belonging to inter-broker bridges void addManagementObject(); @@ -136,10 +130,7 @@ class SessionState : public qpid::SessionState, private: void handleCommand(framing::AMQMethodBody* method, const framing::SequenceNumber& id); void handleContent(framing::AMQFrame& frame, const framing::SequenceNumber& id); - - // indicate that the given ingress msg has been completely received by the - // broker, and the msg's message.transfer command can be considered completed. - void completeRcvMsg(SequenceNumber id, bool requiresAccept, bool requiresSync); + void enqueued(boost::intrusive_ptr<Message> msg); void handleIn(framing::AMQFrame& frame); void handleOut(framing::AMQFrame& frame); @@ -165,6 +156,8 @@ class SessionState : public qpid::SessionState, SemanticState semanticState; SessionAdapter adapter; MessageBuilder msgBuilder; + IncompleteMessageList incomplete; + IncompleteMessageList::CompletionListener enqueuedOp; qmf::org::apache::qpid::broker::Session* mgmtObject; qpid::framing::SequenceSet accepted; @@ -173,110 +166,6 @@ class SessionState : public qpid::SessionState, boost::scoped_ptr<RateFlowcontrol> rateFlowcontrol; boost::intrusive_ptr<sys::TimerTask> flowControlTimer; - // sequence numbers for pending received Execution.Sync commands - std::queue<SequenceNumber> pendingExecutionSyncs; - bool currentCommandComplete; - - /** This class provides a context for completing asynchronous commands in a thread - * safe manner. Asynchronous commands save their completion state in this class. - * This class then schedules the completeCommands() method in the IO thread. - * While running in the IO thread, completeCommands() may safely complete all - * saved commands without the risk of colliding with other operations on this - * SessionState. - */ - class AsyncCommandCompleter : public RefCounted { - private: - SessionState *session; - bool isAttached; - qpid::sys::Mutex completerLock; - - // special-case message.transfer commands for optimization - struct MessageInfo { - SequenceNumber cmd; // message.transfer command id - bool requiresAccept; - bool requiresSync; - MessageInfo(SequenceNumber c, bool a, bool s) - : cmd(c), requiresAccept(a), requiresSync(s) {} - }; - std::vector<MessageInfo> completedMsgs; - // If an ingress message does not require a Sync, we need to - // hold a reference to it in case an Execution.Sync command is received and we - // have to manually flush the message. - std::map<SequenceNumber, boost::intrusive_ptr<Message> > pendingMsgs; - - /** complete all pending commands, runs in IO thread */ - void completeCommands(); - - /** for scheduling a run of "completeCommands()" on the IO thread */ - static void schedule(boost::intrusive_ptr<AsyncCommandCompleter>); - - public: - AsyncCommandCompleter(SessionState *s) : session(s), isAttached(s->isAttached()) {}; - ~AsyncCommandCompleter() {}; - - /** track a message pending ingress completion */ - void addPendingMessage(boost::intrusive_ptr<Message> m); - void deletePendingMessage(SequenceNumber id); - void flushPendingMessages(); - /** schedule the processing of a completed ingress message.transfer command */ - void scheduleMsgCompletion(SequenceNumber cmd, - bool requiresAccept, - bool requiresSync); - void cancel(); // called by SessionState destructor. - void attached(); // called by SessionState on attach() - void detached(); // called by SessionState on detach() - }; - boost::intrusive_ptr<AsyncCommandCompleter> asyncCommandCompleter; - - /** Abstract class that represents a single asynchronous command that is - * pending completion. - */ - class AsyncCommandContext : public AsyncCompletion::Callback - { - public: - AsyncCommandContext( SessionState *ss, SequenceNumber _id ) - : id(_id), completerContext(ss->asyncCommandCompleter) {} - virtual ~AsyncCommandContext() {} - - protected: - SequenceNumber id; - boost::intrusive_ptr<AsyncCommandCompleter> completerContext; - }; - - /** incomplete Message.transfer commands - inbound to broker from client - */ - class IncompleteIngressMsgXfer : public SessionState::AsyncCommandContext - { - public: - IncompleteIngressMsgXfer( SessionState *ss, - boost::intrusive_ptr<Message> m ) - : AsyncCommandContext(ss, m->getCommandId()), - session(ss), - msg(m), - requiresAccept(m->requiresAccept()), - requiresSync(m->getFrames().getMethod()->isSync()), - pending(false) {} - IncompleteIngressMsgXfer( const IncompleteIngressMsgXfer& x ) - : AsyncCommandContext(x.session, x.msg->getCommandId()), - session(x.session), - msg(x.msg), - requiresAccept(x.requiresAccept), - requiresSync(x.requiresSync), - pending(x.pending) {} - - virtual ~IncompleteIngressMsgXfer() {}; - - virtual void completed(bool); - virtual boost::intrusive_ptr<AsyncCompletion::Callback> clone(); - - private: - SessionState *session; // only valid if sync flag in callback is true - boost::intrusive_ptr<Message> msg; - bool requiresAccept; - bool requiresSync; - bool pending; // true if msg saved on pending list... - }; - friend class SessionManager; }; diff --git a/cpp/src/qpid/broker/StatefulQueueObserver.h b/cpp/src/qpid/broker/StatefulQueueObserver.h deleted file mode 100644 index c682d460b7..0000000000 --- a/cpp/src/qpid/broker/StatefulQueueObserver.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef QPID_BROKER_STATEFULQUEUEOBSERVER_H -#define QPID_BROKER_STATEFULQUEUEOBSERVER_H - -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -#include "qpid/broker/QueueObserver.h" -#include "qpid/framing/FieldTable.h" - -namespace qpid { -namespace broker { - -/** - * Specialized type of QueueObserver that maintains internal state that has to - * be replicated across clustered brokers. - */ -class StatefulQueueObserver : public QueueObserver -{ - public: - StatefulQueueObserver(std::string _id) : id(_id) {} - virtual ~StatefulQueueObserver() {} - - /** This identifier must uniquely identify this particular observer amoung - * all observers on a queue. For cluster replication, this id will be used - * to identify the peer queue observer for synchronization across - * brokers. - */ - const std::string& getId() const { return id; } - - /** This method should return the observer's internal state as an opaque - * map. - */ - virtual void getState(qpid::framing::FieldTable& state ) const = 0; - - /** The input map represents the internal state of the peer observer that - * this observer should synchonize to. - */ - virtual void setState(const qpid::framing::FieldTable&) = 0; - - - private: - std::string id; -}; -}} // namespace qpid::broker - -#endif /*!QPID_BROKER_STATEFULQUEUEOBSERVER_H*/ diff --git a/cpp/src/qpid/broker/ThresholdAlerts.cpp b/cpp/src/qpid/broker/ThresholdAlerts.cpp index 3c9e210d4d..4f35884af8 100644 --- a/cpp/src/qpid/broker/ThresholdAlerts.cpp +++ b/cpp/src/qpid/broker/ThresholdAlerts.cpp @@ -28,52 +28,6 @@ namespace qpid { namespace broker { -namespace { -const qmf::org::apache::qpid::broker::EventQueueThresholdExceeded EVENT("dummy", 0, 0); -bool isQMFv2(const boost::intrusive_ptr<Message> message) -{ - const qpid::framing::MessageProperties* props = message->getProperties<qpid::framing::MessageProperties>(); - return props && props->getAppId() == "qmf2"; -} - -bool isThresholdEvent(const boost::intrusive_ptr<Message> message) -{ - if (message->getIsManagementMessage()) { - //is this a qmf event? if so is it a threshold event? - if (isQMFv2(message)) { - const qpid::framing::FieldTable* headers = message->getApplicationHeaders(); - if (headers && headers->getAsString("qmf.content") == "_event") { - //decode as list - std::string content = message->getFrames().getContent(); - qpid::types::Variant::List list; - qpid::amqp_0_10::ListCodec::decode(content, list); - if (list.empty() || list.front().getType() != qpid::types::VAR_MAP) return false; - qpid::types::Variant::Map map = list.front().asMap(); - try { - std::string eventName = map["_schema_id"].asMap()["_class_name"].asString(); - return eventName == EVENT.getEventName(); - } catch (const std::exception& e) { - QPID_LOG(error, "Error checking for recursive threshold alert: " << e.what()); - } - } - } else { - std::string content = message->getFrames().getContent(); - qpid::framing::Buffer buffer(const_cast<char*>(content.data()), content.size()); - if (buffer.getOctet() == 'A' && buffer.getOctet() == 'M' && buffer.getOctet() == '2' && buffer.getOctet() == 'e') { - buffer.getLong();//sequence - std::string packageName; - buffer.getShortString(packageName); - if (packageName != EVENT.getPackageName()) return false; - std::string eventName; - buffer.getShortString(eventName); - return eventName == EVENT.getEventName(); - } - } - } - return false; -} -} - ThresholdAlerts::ThresholdAlerts(const std::string& n, qpid::management::ManagementAgent& a, const uint32_t ct, @@ -90,14 +44,8 @@ void ThresholdAlerts::enqueued(const QueuedMessage& m) if ((countThreshold && count >= countThreshold) || (sizeThreshold && size >= sizeThreshold)) { if ((repeatInterval == 0 && lastAlert == qpid::sys::EPOCH) || qpid::sys::Duration(lastAlert, qpid::sys::now()) > repeatInterval) { - //Note: Raising an event may result in messages being - //enqueued on queues; it may even be that this event - //causes a message to be enqueued on the queue we are - //tracking, and so we need to avoid recursing - if (isThresholdEvent(m.payload)) return; - lastAlert = qpid::sys::now(); agent.raiseEvent(qmf::org::apache::qpid::broker::EventQueueThresholdExceeded(name, count, size)); - QPID_LOG(info, "Threshold event triggered for " << name << ", count=" << count << ", size=" << size); + lastAlert = qpid::sys::now(); } } } @@ -127,12 +75,12 @@ void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& a } void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& agent, - const qpid::framing::FieldTable& settings, uint16_t limitRatio) + const qpid::framing::FieldTable& settings) { qpid::types::Variant::Map map; qpid::amqp_0_10::translate(settings, map); - observe(queue, agent, map, limitRatio); + observe(queue, agent, map); } template <class T> @@ -170,19 +118,19 @@ class Option }; void ThresholdAlerts::observe(Queue& queue, qpid::management::ManagementAgent& agent, - const qpid::types::Variant::Map& settings, uint16_t limitRatio) + const qpid::types::Variant::Map& settings) { //Note: aliases are keys defined by java broker Option<int64_t> repeatInterval("qpid.alert_repeat_gap", 60); repeatInterval.addAlias("x-qpid-minimum-alert-repeat-gap"); - //If no explicit threshold settings were given use specified - //percentage of any limit from the policy. + //If no explicit threshold settings were given use 80% of any + //limit from the policy. const QueuePolicy* policy = queue.getPolicy(); - Option<uint32_t> countThreshold("qpid.alert_count", (uint32_t) (policy && limitRatio ? (policy->getMaxCount()*limitRatio/100) : 0)); + Option<uint32_t> countThreshold("qpid.alert_count", (uint32_t) (policy ? policy->getMaxCount()*0.8 : 0)); countThreshold.addAlias("x-qpid-maximum-message-count"); - Option<uint64_t> sizeThreshold("qpid.alert_size", (uint64_t) (policy && limitRatio ? (policy->getMaxSize()*limitRatio/100) : 0)); + Option<uint64_t> sizeThreshold("qpid.alert_size", (uint64_t) (policy ? policy->getMaxSize()*0.8 : 0)); sizeThreshold.addAlias("x-qpid-maximum-message-size"); observe(queue, agent, countThreshold.get(settings), sizeThreshold.get(settings), repeatInterval.get(settings)); diff --git a/cpp/src/qpid/broker/ThresholdAlerts.h b/cpp/src/qpid/broker/ThresholdAlerts.h index 2b4a46b736..e1f59252c4 100644 --- a/cpp/src/qpid/broker/ThresholdAlerts.h +++ b/cpp/src/qpid/broker/ThresholdAlerts.h @@ -50,17 +50,14 @@ class ThresholdAlerts : public QueueObserver const long repeatInterval); void enqueued(const QueuedMessage&); void dequeued(const QueuedMessage&); - void acquired(const QueuedMessage&) {}; - void requeued(const QueuedMessage&) {}; - static void observe(Queue& queue, qpid::management::ManagementAgent& agent, const uint64_t countThreshold, const uint64_t sizeThreshold, const long repeatInterval); static void observe(Queue& queue, qpid::management::ManagementAgent& agent, - const qpid::framing::FieldTable& settings, uint16_t limitRatio); + const qpid::framing::FieldTable& settings); static void observe(Queue& queue, qpid::management::ManagementAgent& agent, - const qpid::types::Variant::Map& settings, uint16_t limitRatio); + const qpid::types::Variant::Map& settings); private: const std::string name; qpid::management::ManagementAgent& agent; diff --git a/cpp/src/qpid/broker/TopicExchange.cpp b/cpp/src/qpid/broker/TopicExchange.cpp index 644a3d628e..1b0fe71bcf 100644 --- a/cpp/src/qpid/broker/TopicExchange.cpp +++ b/cpp/src/qpid/broker/TopicExchange.cpp @@ -221,7 +221,6 @@ TopicExchange::TopicExchange(const std::string& _name, bool _durable, bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, const FieldTable* args) { - ClearCache cc(&cacheLock,&bindingCache); // clear the cache on function exit. string fedOp(args ? args->getAsString(qpidFedOp) : fedOpBind); string fedTags(args ? args->getAsString(qpidFedTags) : ""); string fedOrigin(args ? args->getAsString(qpidFedOrigin) : ""); @@ -250,21 +249,21 @@ bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, cons if (mgmtExchange != 0) { mgmtExchange->inc_bindingCount(); } - QPID_LOG(debug, "Binding key [" << routingPattern << "] to queue " << queue->getName() - << " on exchange " << getName() << " (origin=" << fedOrigin << ")"); + QPID_LOG(debug, "Bound key [" << routingPattern << "] to queue " << queue->getName() + << " (origin=" << fedOrigin << ")"); } } else if (fedOp == fedOpUnbind) { - RWlock::ScopedWlock l(lock); - BindingKey* bk = getQueueBinding(queue, routingPattern); - if (bk) { - QPID_LOG(debug, "FedOpUnbind [" << routingPattern << "] from exchange " << getName() - << " on queue=" << queue->getName() << " origin=" << fedOrigin); - propagate = bk->fedBinding.delOrigin(queue->getName(), fedOrigin); - // if this was the last binding for the queue, delete the binding - if (bk->fedBinding.countFedBindings(queue->getName()) == 0) { - deleteBinding(queue, routingPattern, bk); + bool reallyUnbind = false; + { + RWlock::ScopedWlock l(lock); + BindingKey* bk = bindingTree.getBindingKey(routingPattern); + if (bk) { + propagate = bk->fedBinding.delOrigin(queue->getName(), fedOrigin); + reallyUnbind = bk->fedBinding.countFedBindings(queue->getName()) == 0; } } + if (reallyUnbind) + unbind(queue, routingPattern, 0); } else if (fedOp == fedOpReorigin) { /** gather up all the keys that need rebinding in a local vector * while holding the lock. Then propagate once the lock is @@ -282,38 +281,20 @@ bool TopicExchange::bind(Queue::shared_ptr queue, const string& routingKey, cons } } - cc.clearCache(); // clear the cache before we IVE route. routeIVE(); if (propagate) propagateFedOp(routingKey, fedTags, fedOp, fedOrigin); return true; } -bool TopicExchange::unbind(Queue::shared_ptr queue, const string& constRoutingKey, const FieldTable* args) -{ - string fedOrigin(args ? args->getAsString(qpidFedOrigin) : ""); - QPID_LOG(debug, "Unbinding key [" << constRoutingKey << "] from queue " << queue->getName() - << " on exchange " << getName() << " origin=" << fedOrigin << ")" ); - - ClearCache cc(&cacheLock,&bindingCache); // clear the cache on function exit. +bool TopicExchange::unbind(Queue::shared_ptr queue, const string& constRoutingKey, const FieldTable* /*args*/){ RWlock::ScopedWlock l(lock); string routingKey = normalize(constRoutingKey); - BindingKey* bk = getQueueBinding(queue, routingKey); + BindingKey* bk = bindingTree.getBindingKey(routingKey); if (!bk) return false; - bool propagate = bk->fedBinding.delOrigin(queue->getName(), fedOrigin); - deleteBinding(queue, routingKey, bk); - if (propagate) - propagateFedOp(routingKey, string(), fedOpUnbind, string()); - return true; -} - - -bool TopicExchange::deleteBinding(Queue::shared_ptr queue, - const std::string& routingKey, - BindingKey *bk) -{ - // Note well: write lock held by caller Binding::vector& qv(bk->bindingVector); + bool propagate = false; + Binding::vector::iterator q; for (q = qv.begin(); q != qv.end(); q++) if ((*q)->queue == queue) @@ -322,55 +303,42 @@ bool TopicExchange::deleteBinding(Queue::shared_ptr queue, qv.erase(q); assert(nBindings > 0); nBindings--; - + propagate = bk->fedBinding.delOrigin(); if(qv.empty()) { bindingTree.removeBindingKey(routingKey); } if (mgmtExchange != 0) { mgmtExchange->dec_bindingCount(); } - QPID_LOG(debug, "Unbound key [" << routingKey << "] from queue " << queue->getName() - << " on exchange " << getName()); + QPID_LOG(debug, "Unbound [" << routingKey << "] from queue " << queue->getName()); + + if (propagate) + propagateFedOp(routingKey, string(), fedOpUnbind, string()); return true; } -/** returns a pointer to the BindingKey if the given queue is bound to this - * exchange using the routing pattern. 0 if queue binding does not exist. - */ -TopicExchange::BindingKey *TopicExchange::getQueueBinding(Queue::shared_ptr queue, const string& pattern) +bool TopicExchange::isBound(Queue::shared_ptr queue, const string& pattern) { // Note well: lock held by caller.... BindingKey *bk = bindingTree.getBindingKey(pattern); // Exact match against binding pattern - if (!bk) return 0; + if (!bk) return false; Binding::vector& qv(bk->bindingVector); Binding::vector::iterator q; for (q = qv.begin(); q != qv.end(); q++) if ((*q)->queue == queue) break; - return (q != qv.end()) ? bk : 0; + return q != qv.end(); } void TopicExchange::route(Deliverable& msg, const string& routingKey, const FieldTable* /*args*/) { // Note: PERFORMANCE CRITICAL!!! - BindingList b; - std::map<std::string, BindingList>::iterator it; - { // only lock the cache for read - RWlock::ScopedRlock cl(cacheLock); - it = bindingCache.find(routingKey); - if (it != bindingCache.end()) { - b = it->second; - } - } + BindingList b(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >); PreRoute pr(msg, this); - if (!b.get()) // no cache hit + BindingsFinderIter bindingsFinder(b); { RWlock::ScopedRlock l(lock); - b = BindingList(new std::vector<boost::shared_ptr<qpid::broker::Exchange::Binding> >); - BindingsFinderIter bindingsFinder(b); bindingTree.iterateMatch(routingKey, bindingsFinder); - RWlock::ScopedWlock cwl(cacheLock); - bindingCache[routingKey] = b; // update cache } doRoute(msg, b); } @@ -380,7 +348,7 @@ bool TopicExchange::isBound(Queue::shared_ptr queue, const string* const routing RWlock::ScopedRlock l(lock); if (routingKey && queue) { string key(normalize(*routingKey)); - return getQueueBinding(queue, key) != 0; + return isBound(queue, key); } else if (!routingKey && !queue) { return nBindings > 0; } else if (routingKey) { diff --git a/cpp/src/qpid/broker/TopicExchange.h b/cpp/src/qpid/broker/TopicExchange.h index 636918f8a1..a6c457dcb3 100644 --- a/cpp/src/qpid/broker/TopicExchange.h +++ b/cpp/src/qpid/broker/TopicExchange.h @@ -56,7 +56,7 @@ class TopicExchange : public virtual Exchange { // | +-->d-->... // +-->x-->y-->... // - class QPID_BROKER_CLASS_EXTERN BindingNode { + class BindingNode { public: typedef boost::shared_ptr<BindingNode> shared_ptr; @@ -135,31 +135,8 @@ class TopicExchange : public virtual Exchange { BindingNode bindingTree; unsigned long nBindings; qpid::sys::RWlock lock; // protects bindingTree and nBindings - qpid::sys::RWlock cacheLock; // protects cache - std::map<std::string, BindingList> bindingCache; // cache of matched routes. - class ClearCache { - private: - qpid::sys::RWlock* cacheLock; - std::map<std::string, BindingList>* bindingCache; - bool cleared; - public: - ClearCache(qpid::sys::RWlock* l, std::map<std::string, BindingList>* bc): cacheLock(l), - bindingCache(bc),cleared(false) {}; - void clearCache() { - qpid::sys::RWlock::ScopedWlock l(*cacheLock); - if (!cleared) { - bindingCache->clear(); - cleared =true; - } - }; - ~ClearCache(){ - clearCache(); - }; - }; - BindingKey *getQueueBinding(Queue::shared_ptr queue, const std::string& pattern); - bool deleteBinding(Queue::shared_ptr queue, - const std::string& routingKey, - BindingKey *bk); + + bool isBound(Queue::shared_ptr queue, const std::string& pattern); class ReOriginIter; class BindingsFinderIter; diff --git a/cpp/src/qpid/broker/TxBuffer.cpp b/cpp/src/qpid/broker/TxBuffer.cpp index d92e6ace48..b509778e89 100644 --- a/cpp/src/qpid/broker/TxBuffer.cpp +++ b/cpp/src/qpid/broker/TxBuffer.cpp @@ -76,5 +76,5 @@ bool TxBuffer::commitLocal(TransactionalStore* const store) } void TxBuffer::accept(TxOpConstVisitor& v) const { - std::for_each(ops.begin(), ops.end(), boost::bind(&TxOp::accept, _1, boost::ref(v))); + std::for_each(ops.begin(), ops.end(), boost::bind(&TxOp::accept, _1, boost::ref(v))); } diff --git a/cpp/src/qpid/broker/TxPublish.cpp b/cpp/src/qpid/broker/TxPublish.cpp index 9c2cf4a467..36a451e62c 100644 --- a/cpp/src/qpid/broker/TxPublish.cpp +++ b/cpp/src/qpid/broker/TxPublish.cpp @@ -90,7 +90,14 @@ void TxPublish::deliverTo(const boost::shared_ptr<Queue>& queue){ void TxPublish::prepare(TransactionContext* ctxt, const boost::shared_ptr<Queue> queue) { - queue->enqueue(ctxt, msg); + if (!queue->enqueue(ctxt, msg)){ + /** + * if not store then mark message for ack and deleivery once + * commit happens, as async IO will never set it when no store + * exists + */ + msg->enqueueComplete(); + } } TxPublish::Commit::Commit(intrusive_ptr<Message>& _msg) : msg(_msg){} diff --git a/cpp/src/qpid/broker/TxPublish.h b/cpp/src/qpid/broker/TxPublish.h index dba7878af2..effa585676 100644 --- a/cpp/src/qpid/broker/TxPublish.h +++ b/cpp/src/qpid/broker/TxPublish.h @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -34,58 +34,57 @@ #include <boost/intrusive_ptr.hpp> namespace qpid { -namespace broker { -/** - * Defines the behaviour for publish operations on a - * transactional channel. Messages are routed through - * exchanges when received but are not at that stage delivered - * to the matching queues, rather the queues are held in an - * instance of this class. On prepare() the message is marked - * enqueued to the relevant queues in the MessagesStore. On - * commit() the messages will be passed to the queue for - * dispatch or to be added to the in-memory queue. - */ -class QPID_BROKER_CLASS_EXTERN TxPublish : public TxOp, public Deliverable{ + namespace broker { + /** + * Defines the behaviour for publish operations on a + * transactional channel. Messages are routed through + * exchanges when received but are not at that stage delivered + * to the matching queues, rather the queues are held in an + * instance of this class. On prepare() the message is marked + * enqueued to the relevant queues in the MessagesStore. On + * commit() the messages will be passed to the queue for + * dispatch or to be added to the in-memory queue. + */ + class TxPublish : public TxOp, public Deliverable{ - class Commit{ - boost::intrusive_ptr<Message>& msg; - public: - Commit(boost::intrusive_ptr<Message>& msg); - void operator()(const boost::shared_ptr<Queue>& queue); - }; - class Rollback{ - boost::intrusive_ptr<Message>& msg; - public: - Rollback(boost::intrusive_ptr<Message>& msg); - void operator()(const boost::shared_ptr<Queue>& queue); - }; + class Commit{ + boost::intrusive_ptr<Message>& msg; + public: + Commit(boost::intrusive_ptr<Message>& msg); + void operator()(const boost::shared_ptr<Queue>& queue); + }; + class Rollback{ + boost::intrusive_ptr<Message>& msg; + public: + Rollback(boost::intrusive_ptr<Message>& msg); + void operator()(const boost::shared_ptr<Queue>& queue); + }; - boost::intrusive_ptr<Message> msg; - std::list<boost::shared_ptr<Queue> > queues; - std::list<boost::shared_ptr<Queue> > prepared; + boost::intrusive_ptr<Message> msg; + std::list<boost::shared_ptr<Queue> > queues; + std::list<boost::shared_ptr<Queue> > prepared; - void prepare(TransactionContext* ctxt, boost::shared_ptr<Queue>); + void prepare(TransactionContext* ctxt, boost::shared_ptr<Queue>); - public: - QPID_BROKER_EXTERN TxPublish(boost::intrusive_ptr<Message> msg); - QPID_BROKER_EXTERN virtual bool prepare(TransactionContext* ctxt) throw(); - QPID_BROKER_EXTERN virtual void commit() throw(); - QPID_BROKER_EXTERN virtual void rollback() throw(); + public: + QPID_BROKER_EXTERN TxPublish(boost::intrusive_ptr<Message> msg); + QPID_BROKER_EXTERN virtual bool prepare(TransactionContext* ctxt) throw(); + QPID_BROKER_EXTERN virtual void commit() throw(); + QPID_BROKER_EXTERN virtual void rollback() throw(); - virtual Message& getMessage() { return *msg; }; + virtual Message& getMessage() { return *msg; }; + + QPID_BROKER_EXTERN 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); } - virtual ~TxPublish(){} - virtual void accept(TxOpConstVisitor& visitor) const { visitor(*this); } + QPID_BROKER_EXTERN uint64_t contentSize(); - QPID_BROKER_EXTERN uint64_t contentSize(); - - boost::intrusive_ptr<Message> getMessage() const { return msg; } - const std::list<boost::shared_ptr<Queue> >& getQueues() const { return queues; } - const std::list<boost::shared_ptr<Queue> >& getPrepared() const { return prepared; } -}; -} + boost::intrusive_ptr<Message> getMessage() const { return msg; } + const std::list<boost::shared_ptr<Queue> > getQueues() const { return queues; } + }; + } } diff --git a/cpp/src/qpid/broker/windows/BrokerDefaults.cpp b/cpp/src/qpid/broker/windows/BrokerDefaults.cpp index b65440b5ad..b6862f0418 100644 --- a/cpp/src/qpid/broker/windows/BrokerDefaults.cpp +++ b/cpp/src/qpid/broker/windows/BrokerDefaults.cpp @@ -31,16 +31,10 @@ const std::string Broker::Options::DEFAULT_DATA_DIR_NAME("\\QPIDD.DATA"); std::string Broker::Options::getHome() { std::string home; -#ifdef _MSC_VER char home_c[MAX_PATH+1]; size_t unused; if (0 == getenv_s (&unused, home_c, sizeof(home_c), "HOME")) home += home_c; -#else - char *home_c = getenv("HOME"); - if (home_c) - home += home_c; -#endif return home; } diff --git a/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp b/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp index 2acc09cded..608a8f7dae 100644 --- a/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp +++ b/cpp/src/qpid/broker/windows/SaslAuthenticator.cpp @@ -42,7 +42,7 @@ public: NullAuthenticator(Connection& connection); ~NullAuthenticator(); void getMechanisms(framing::Array& mechanisms); - void start(const std::string& mechanism, const std::string* response); + void start(const std::string& mechanism, const std::string& response); void step(const std::string&) {} std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize); }; @@ -57,7 +57,7 @@ public: SspiAuthenticator(Connection& connection); ~SspiAuthenticator(); void getMechanisms(framing::Array& mechanisms); - void start(const std::string& mechanism, const std::string* response); + void start(const std::string& mechanism, const std::string& response); void step(const std::string& response); std::auto_ptr<SecurityLayer> getSecurityLayer(uint16_t maxFrameSize); }; @@ -93,15 +93,14 @@ 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"))); } -void NullAuthenticator::start(const string& mechanism, const string* response) +void NullAuthenticator::start(const string& mechanism, const string& response) { QPID_LOG(warning, "SASL: No Authentication Performed"); if (mechanism == "PLAIN") { // Old behavior - if (response && response->size() > 0 && (*response).c_str()[0] == (char) 0) { - string temp = response->substr(1); + 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); @@ -139,7 +138,7 @@ void SspiAuthenticator::getMechanisms(Array& mechanisms) QPID_LOG(info, "SASL: Mechanism list: ANONYMOUS PLAIN"); } -void SspiAuthenticator::start(const string& mechanism, const string* response) +void SspiAuthenticator::start(const string& mechanism, const string& response) { QPID_LOG(info, "SASL: Starting authentication with mechanism: " << mechanism); if (mechanism == "ANONYMOUS") { @@ -152,19 +151,16 @@ void SspiAuthenticator::start(const string& mechanism, const string* response) // PLAIN's response is composed of 3 strings separated by 0 bytes: // authorization id, authentication id (user), clear-text password. - if (!response || response->size() == 0) + if (response.size() == 0) throw ConnectionForcedException("Authentication failed"); - string::size_type i = response->find((char)0); - string auth = response->substr(0, i); - string::size_type j = response->find((char)0, i+1); - string uid = response->substr(i+1, j-1); - string pwd = response->substr(j+1); - string dot("."); + string::size_type i = response.find((char)0); + string auth = response.substr(0, i); + string::size_type j = response.find((char)0, i+1); + string uid = response.substr(i+1, j-1); + string pwd = response.substr(j+1); int error = 0; - if (!LogonUser(const_cast<char*>(uid.c_str()), - const_cast<char*>(dot.c_str()), - const_cast<char*>(pwd.c_str()), + if (!LogonUser(uid.c_str(), ".", pwd.c_str(), LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &userToken)) @@ -180,7 +176,7 @@ void SspiAuthenticator::start(const string& mechanism, const string* response) client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), 0, 0); } -void SspiAuthenticator::step(const string& /*response*/) +void SspiAuthenticator::step(const string& response) { QPID_LOG(info, "SASL: Need another step!!!"); } diff --git a/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp b/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp index 1dff1ddc8f..fd0e537192 100644 --- a/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp +++ b/cpp/src/qpid/broker/windows/SslProtocolFactory.cpp @@ -27,14 +27,10 @@ #include "qpid/sys/AsynchIOHandler.h" #include "qpid/sys/ConnectionCodec.h" #include "qpid/sys/Socket.h" -#include "qpid/sys/SocketAddress.h" #include "qpid/sys/SystemInfo.h" #include "qpid/sys/windows/SslAsynchIO.h" - #include <boost/bind.hpp> -#include <boost/ptr_container/ptr_vector.hpp> #include <memory> - // security.h needs to see this to distinguish from kernel use. #define SECURITY_WIN32 #include <security.h> @@ -72,10 +68,9 @@ struct SslServerOptions : qpid::Options }; class SslProtocolFactory : public qpid::sys::ProtocolFactory { + qpid::sys::Socket listener; const bool tcpNoDelay; - boost::ptr_vector<Socket> listeners; - boost::ptr_vector<AsynchAcceptor> acceptors; - uint16_t listeningPort; + const uint16_t listeningPort; std::string brokerHost; const bool clientAuthSelected; std::auto_ptr<qpid::sys::AsynchAcceptor> acceptor; @@ -83,14 +78,15 @@ class SslProtocolFactory : public qpid::sys::ProtocolFactory { CredHandle credHandle; public: - SslProtocolFactory(const SslServerOptions&, const std::string& host, const std::string& port, int backlog, bool nodelay); + SslProtocolFactory(const SslServerOptions&, int backlog, bool nodelay); ~SslProtocolFactory(); void accept(sys::Poller::shared_ptr, sys::ConnectionCodec::Factory*); - void connect(sys::Poller::shared_ptr, const std::string& host, const std::string& port, + void connect(sys::Poller::shared_ptr, const std::string& host, int16_t port, sys::ConnectionCodec::Factory*, ConnectFailedCallback failed); uint16_t getPort() const; + std::string getHost() const; bool supports(const std::string& capability); private: @@ -119,7 +115,6 @@ static struct SslPlugin : public Plugin { try { const broker::Broker::Options& opts = broker->getOptions(); ProtocolFactory::shared_ptr protocol(new SslProtocolFactory(options, - "", boost::lexical_cast<std::string>(options.port), opts.connectionBacklog, opts.tcpNoDelay)); QPID_LOG(notice, "Listening for SSL connections on TCP port " << protocol->getPort()); @@ -132,13 +127,12 @@ static struct SslPlugin : public Plugin { } sslPlugin; SslProtocolFactory::SslProtocolFactory(const SslServerOptions& options, - const std::string& host, const std::string& port, int backlog, + int backlog, bool nodelay) : tcpNoDelay(nodelay), + listeningPort(listener.listen(options.port, backlog)), clientAuthSelected(options.clientAuth) { - // Make sure that certificate store is good before listening to sockets - // to avoid having open and listening sockets when there is no cert store SecInvalidateHandle(&credHandle); // Get the certificate for this server. @@ -183,23 +177,6 @@ SslProtocolFactory::SslProtocolFactory(const SslServerOptions& options, throw QPID_WINDOWS_ERROR(status); ::CertFreeCertificateContext(certContext); ::CertCloseStore(certStoreHandle, 0); - - // Listen to socket(s) - SocketAddress sa(host, port); - - // We must have at least one resolved address - QPID_LOG(info, "SSL Listening to: " << sa.asString()) - Socket* s = new Socket; - listeningPort = s->listen(sa, backlog); - listeners.push_back(s); - - // Try any other resolved addresses - while (sa.nextAddress()) { - QPID_LOG(info, "SSL Listening to: " << sa.asString()) - Socket* s = new Socket; - s->listen(sa, backlog); - listeners.push_back(s); - } } SslProtocolFactory::~SslProtocolFactory() { @@ -260,19 +237,21 @@ uint16_t SslProtocolFactory::getPort() const { return listeningPort; // Immutable no need for lock. } +std::string SslProtocolFactory::getHost() const { + return listener.getSockname(); +} + void SslProtocolFactory::accept(sys::Poller::shared_ptr poller, sys::ConnectionCodec::Factory* fact) { - for (unsigned i = 0; i<listeners.size(); ++i) { - acceptors.push_back( - AsynchAcceptor::create(listeners[i], - boost::bind(&SslProtocolFactory::established, this, poller, _1, fact, false))); - acceptors[i].start(poller); - } + acceptor.reset( + AsynchAcceptor::create(listener, + boost::bind(&SslProtocolFactory::established, this, poller, _1, fact, false))); + acceptor->start(poller); } void SslProtocolFactory::connect(sys::Poller::shared_ptr poller, const std::string& host, - const std::string& port, + int16_t port, sys::ConnectionCodec::Factory* fact, ConnectFailedCallback failed) { diff --git a/cpp/src/qpid/client/ConnectionHandler.cpp b/cpp/src/qpid/client/ConnectionHandler.cpp index ab0d8e0700..8dc1e8338a 100644 --- a/cpp/src/qpid/client/ConnectionHandler.cpp +++ b/cpp/src/qpid/client/ConnectionHandler.cpp @@ -22,7 +22,6 @@ #include "qpid/client/ConnectionHandler.h" #include "qpid/SaslFactory.h" -#include "qpid/StringUtils.h" #include "qpid/client/Bounds.h" #include "qpid/framing/amqp_framing.h" #include "qpid/framing/all_method_bodies.h" @@ -143,9 +142,7 @@ void ConnectionHandler::outgoing(AMQFrame& frame) void ConnectionHandler::waitForOpen() { waitFor(ESTABLISHED); - if (getState() == FAILED) { - throw TransportFailure(errorText); - } else if (getState() == CLOSED) { + if (getState() == FAILED || getState() == CLOSED) { throw ConnectionException(errorCode, errorText); } } @@ -205,24 +202,6 @@ void ConnectionHandler::fail(const std::string& message) namespace { std::string SPACE(" "); - -std::string join(const std::vector<std::string>& in) -{ - std::string result; - for (std::vector<std::string>::const_iterator i = in.begin(); i != in.end(); ++i) { - if (result.size()) result += SPACE; - result += *i; - } - return result; -} - -void intersection(const std::vector<std::string>& a, const std::vector<std::string>& b, std::vector<std::string>& results) -{ - for (std::vector<std::string>::const_iterator i = a.begin(); i != a.end(); ++i) { - if (std::find(b.begin(), b.end(), *i) != b.end()) results.push_back(*i); - } -} - } void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& mechanisms, const Array& /*locales*/) @@ -237,35 +216,26 @@ void ConnectionHandler::start(const FieldTable& /*serverProps*/, const Array& me maxSsf ); - std::vector<std::string> mechlist; - if (mechanism.empty()) { - //mechlist is simply what the server offers - mechanisms.collect(mechlist); - } else { - //mechlist is the intersection of those indicated by user and - //those supported by server, in the order listed by user - std::vector<std::string> allowed = split(mechanism, " "); - std::vector<std::string> supported; - mechanisms.collect(supported); - intersection(allowed, supported, mechlist); - if (mechlist.empty()) { - throw Exception(QPID_MSG("Desired mechanism(s) not valid: " << mechanism << " (supported: " << join(supported) << ")")); + std::string mechlist; + bool chosenMechanismSupported = mechanism.empty(); + for (Array::const_iterator i = mechanisms.begin(); i != mechanisms.end(); ++i) { + if (!mechanism.empty() && mechanism == (*i)->get<std::string>()) { + chosenMechanismSupported = true; + mechlist = (*i)->get<std::string>() + SPACE + mechlist; + } else { + if (i != mechanisms.begin()) mechlist += SPACE; + mechlist += (*i)->get<std::string>(); } } + if (!chosenMechanismSupported) { + fail("Selected mechanism not supported: " + mechanism); + } + if (sasl.get()) { - string response; - if (sasl->start(join(mechlist), response, getSecuritySettings ? getSecuritySettings() : 0)) { - proxy.startOk(properties, sasl->getMechanism(), response, locale); - } else { - //response was null - ConnectionStartOkBody body; - body.setClientProperties(properties); - body.setMechanism(sasl->getMechanism()); - //Don't set response, as none was given - body.setLocale(locale); - proxy.send(body); - } + string response = sasl->start(mechanism.empty() ? mechlist : mechanism, + getSecuritySettings ? getSecuritySettings() : 0); + proxy.startOk(properties, sasl->getMechanism(), response, locale); } else { //TODO: verify that desired mechanism and locale are supported string response = ((char)0) + username + ((char)0) + password; diff --git a/cpp/src/qpid/client/ConnectionImpl.cpp b/cpp/src/qpid/client/ConnectionImpl.cpp index db97f1e0f4..40c004f166 100644 --- a/cpp/src/qpid/client/ConnectionImpl.cpp +++ b/cpp/src/qpid/client/ConnectionImpl.cpp @@ -36,7 +36,6 @@ #include <boost/bind.hpp> #include <boost/format.hpp> -#include <boost/lexical_cast.hpp> #include <boost/shared_ptr.hpp> #include <limits> @@ -259,16 +258,16 @@ void ConnectionImpl::open() connector->setInputHandler(&handler); connector->setShutdownHandler(this); try { - std::string p = boost::lexical_cast<std::string>(port); - connector->connect(host, p); - + connector->connect(host, port); + } catch (const std::exception& e) { QPID_LOG(debug, "Failed to connect to " << protocol << ":" << host << ":" << port << " " << e.what()); connector.reset(); - throw TransportFailure(e.what()); + throw; } connector->init(); - + QPID_LOG(info, *this << " connected to " << protocol << ":" << host << ":" << port); + // Enable heartbeat if requested uint16_t heartbeat = static_cast<ConnectionSettings&>(handler).heartbeat; if (heartbeat) { @@ -282,7 +281,6 @@ void ConnectionImpl::open() // - in that case in connector.reset() above; // - or when we are deleted handler.waitForOpen(); - QPID_LOG(info, *this << " connected to " << protocol << ":" << host << ":" << port); // If the SASL layer has provided an "operational" userId for the connection, // put it in the negotiated settings. diff --git a/cpp/src/qpid/client/Connector.h b/cpp/src/qpid/client/Connector.h index bc611ffe0d..586012f9d6 100644 --- a/cpp/src/qpid/client/Connector.h +++ b/cpp/src/qpid/client/Connector.h @@ -61,7 +61,7 @@ class Connector : public framing::OutputHandler static void registerFactory(const std::string& proto, Factory* connectorFactory); virtual ~Connector() {}; - virtual void connect(const std::string& host, const std::string& port) = 0; + virtual void connect(const std::string& host, int port) = 0; virtual void init() {}; virtual void close() = 0; virtual void send(framing::AMQFrame& frame) = 0; diff --git a/cpp/src/qpid/client/RdmaConnector.cpp b/cpp/src/qpid/client/RdmaConnector.cpp index 664640f5e7..6af607198c 100644 --- a/cpp/src/qpid/client/RdmaConnector.cpp +++ b/cpp/src/qpid/client/RdmaConnector.cpp @@ -95,7 +95,7 @@ class RdmaConnector : public Connector, public sys::Codec std::string identifier; - void connect(const std::string& host, const std::string& port); + void connect(const std::string& host, int port); void close(); void send(framing::AMQFrame& frame); void abort() {} // TODO: need to fix this for heartbeat timeouts to work @@ -173,7 +173,7 @@ RdmaConnector::~RdmaConnector() { } } -void RdmaConnector::connect(const std::string& host, const std::string& port){ +void RdmaConnector::connect(const std::string& host, int port){ Mutex::ScopedLock l(dataConnectedLock); assert(!dataConnected); @@ -184,7 +184,7 @@ void RdmaConnector::connect(const std::string& host, const std::string& port){ boost::bind(&RdmaConnector::disconnected, this), boost::bind(&RdmaConnector::rejected, this, poller, _1, _2)); - SocketAddress sa(host, port); + SocketAddress sa(host, boost::lexical_cast<std::string>(port)); acon->start(poller, sa); } diff --git a/cpp/src/qpid/client/SessionImpl.cpp b/cpp/src/qpid/client/SessionImpl.cpp index 7cf4ef648e..b507625b11 100644 --- a/cpp/src/qpid/client/SessionImpl.cpp +++ b/cpp/src/qpid/client/SessionImpl.cpp @@ -170,7 +170,6 @@ Demux& SessionImpl::getDemux() void SessionImpl::waitForCompletion(const SequenceNumber& id) { Lock l(state); - sys::Waitable::ScopedWait w(state); waitForCompletionImpl(id); } diff --git a/cpp/src/qpid/client/SslConnector.cpp b/cpp/src/qpid/client/SslConnector.cpp index 26c2335eda..35c7e6bdf6 100644 --- a/cpp/src/qpid/client/SslConnector.cpp +++ b/cpp/src/qpid/client/SslConnector.cpp @@ -114,7 +114,7 @@ class SslConnector : public Connector std::string identifier; - void connect(const std::string& host, const std::string& port); + void connect(const std::string& host, int port); void init(); void close(); void send(framing::AMQFrame& frame); @@ -190,14 +190,14 @@ SslConnector::~SslConnector() { close(); } -void SslConnector::connect(const std::string& host, const std::string& port){ +void SslConnector::connect(const std::string& host, int port){ Mutex::ScopedLock l(closedLock); assert(closed); try { socket.connect(host, port); } catch (const std::exception& e) { socket.close(); - throw TransportFailure(e.what()); + throw ConnectionException(framing::connection::CLOSE_CODE_FRAMING_ERROR, e.what()); } identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress()); diff --git a/cpp/src/qpid/client/TCPConnector.cpp b/cpp/src/qpid/client/TCPConnector.cpp index 0070b24ec0..e284d57bec 100644 --- a/cpp/src/qpid/client/TCPConnector.cpp +++ b/cpp/src/qpid/client/TCPConnector.cpp @@ -88,7 +88,7 @@ TCPConnector::~TCPConnector() { close(); } -void TCPConnector::connect(const std::string& host, const std::string& port) { +void TCPConnector::connect(const std::string& host, int port) { Mutex::ScopedLock l(lock); assert(closed); connector = AsynchConnector::create( @@ -117,11 +117,11 @@ void TCPConnector::connected(const Socket&) { void TCPConnector::start(sys::AsynchIO* aio_) { aio = aio_; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 32; i++) { aio->queueReadBuffer(new Buff(maxFrameSize)); } - identifier = str(format("[%1%]") % socket.getFullAddress()); + identifier = str(format("[%1% %2%]") % socket.getLocalPort() % socket.getPeerAddress()); } void TCPConnector::initAmqp() { diff --git a/cpp/src/qpid/client/TCPConnector.h b/cpp/src/qpid/client/TCPConnector.h index eb3f696013..c756469182 100644 --- a/cpp/src/qpid/client/TCPConnector.h +++ b/cpp/src/qpid/client/TCPConnector.h @@ -98,7 +98,7 @@ class TCPConnector : public Connector, public sys::Codec protected: virtual ~TCPConnector(); - void connect(const std::string& host, const std::string& port); + void connect(const std::string& host, int port); void start(sys::AsynchIO* aio_); void initAmqp(); virtual void connectFailed(const std::string& msg); diff --git a/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp b/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp index d2accddcd0..bfb20118b5 100644 --- a/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp +++ b/cpp/src/qpid/client/amqp0_10/AcceptTracker.cpp @@ -30,23 +30,12 @@ void AcceptTracker::State::accept() unaccepted.clear(); } -SequenceSet AcceptTracker::State::accept(qpid::framing::SequenceNumber id, bool cumulative) +void AcceptTracker::State::accept(qpid::framing::SequenceNumber id) { - SequenceSet accepting; - if (cumulative) { - for (SequenceSet::iterator i = unaccepted.begin(); i != unaccepted.end() && *i <= id; ++i) { - accepting.add(*i); - } - unconfirmed.add(accepting); - unaccepted.remove(accepting); - } else { - if (unaccepted.contains(id)) { - unaccepted.remove(id); - unconfirmed.add(id); - accepting.add(id); - } + if (unaccepted.contains(id)) { + unaccepted.remove(id); + unconfirmed.add(id); } - return accepting; } void AcceptTracker::State::release() @@ -70,18 +59,6 @@ void AcceptTracker::delivered(const std::string& destination, const qpid::framin destinationState[destination].unaccepted.add(id); } -namespace -{ -const size_t FLUSH_FREQUENCY = 1024; -} - -void AcceptTracker::addToPending(qpid::client::AsyncSession& session, const Record& record) -{ - pending.push_back(record); - if (pending.size() % FLUSH_FREQUENCY == 0) session.flush(); -} - - void AcceptTracker::accept(qpid::client::AsyncSession& session) { for (StateMap::iterator i = destinationState.begin(); i != destinationState.end(); ++i) { @@ -90,19 +67,20 @@ void AcceptTracker::accept(qpid::client::AsyncSession& session) Record record; record.status = session.messageAccept(aggregateState.unaccepted); record.accepted = aggregateState.unaccepted; - addToPending(session, record); + pending.push_back(record); aggregateState.accept(); } -void AcceptTracker::accept(qpid::framing::SequenceNumber id, qpid::client::AsyncSession& session, bool cumulative) +void AcceptTracker::accept(qpid::framing::SequenceNumber id, qpid::client::AsyncSession& session) { for (StateMap::iterator i = destinationState.begin(); i != destinationState.end(); ++i) { - i->second.accept(id, cumulative); + i->second.accept(id); } Record record; - record.accepted = aggregateState.accept(id, cumulative); + record.accepted.add(id); record.status = session.messageAccept(record.accepted); - addToPending(session, record); + pending.push_back(record); + aggregateState.accept(id); } void AcceptTracker::release(qpid::client::AsyncSession& session) diff --git a/cpp/src/qpid/client/amqp0_10/AcceptTracker.h b/cpp/src/qpid/client/amqp0_10/AcceptTracker.h index 85209c3b87..87890e41cc 100644 --- a/cpp/src/qpid/client/amqp0_10/AcceptTracker.h +++ b/cpp/src/qpid/client/amqp0_10/AcceptTracker.h @@ -42,7 +42,7 @@ class AcceptTracker public: void delivered(const std::string& destination, const qpid::framing::SequenceNumber& id); void accept(qpid::client::AsyncSession&); - void accept(qpid::framing::SequenceNumber, qpid::client::AsyncSession&, bool cumulative); + void accept(qpid::framing::SequenceNumber, qpid::client::AsyncSession&); void release(qpid::client::AsyncSession&); uint32_t acceptsPending(); uint32_t acceptsPending(const std::string& destination); @@ -62,7 +62,7 @@ class AcceptTracker qpid::framing::SequenceSet unconfirmed; void accept(); - qpid::framing::SequenceSet accept(qpid::framing::SequenceNumber, bool cumulative); + void accept(qpid::framing::SequenceNumber); void release(); uint32_t acceptsPending(); void completed(qpid::framing::SequenceSet&); @@ -79,7 +79,6 @@ class AcceptTracker StateMap destinationState; Records pending; - void addToPending(qpid::client::AsyncSession&, const Record&); void checkPending(); void completed(qpid::framing::SequenceSet&); }; diff --git a/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp b/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp index 16e5fde075..f1295a3b66 100644 --- a/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp +++ b/cpp/src/qpid/client/amqp0_10/AddressResolution.cpp @@ -129,10 +129,6 @@ const std::string HEADERS_EXCHANGE("headers"); const std::string XML_EXCHANGE("xml"); const std::string WILDCARD_ANY("#"); -//exchange prefixes: -const std::string PREFIX_AMQ("amq."); -const std::string PREFIX_QPID("qpid."); - const Verifier verifier; } @@ -203,7 +199,6 @@ class Exchange : protected Node void checkCreate(qpid::client::AsyncSession&, CheckMode); void checkAssert(qpid::client::AsyncSession&, CheckMode); void checkDelete(qpid::client::AsyncSession&, CheckMode); - bool isReservedName(); protected: const std::string specifiedType; @@ -238,8 +233,6 @@ class Subscription : public Exchange, public MessageSource const bool reliable; const bool durable; const std::string actualType; - const bool exclusiveQueue; - const bool exclusiveSubscription; FieldTable queueOptions; FieldTable subscriptionOptions; Bindings bindings; @@ -314,7 +307,6 @@ struct Opt Opt& operator/(const std::string& name); operator bool() const; std::string str() const; - bool asBool(bool defaultValue) const; const Variant::List& asList() const; void collect(qpid::framing::FieldTable& args) const; @@ -346,12 +338,6 @@ Opt::operator bool() const return value && !value->isVoid() && value->asBool(); } -bool Opt::asBool(bool defaultValue) const -{ - if (value) return value->asBool(); - else return defaultValue; -} - std::string Opt::str() const { if (value) return value->asString(); @@ -495,7 +481,7 @@ std::string Subscription::getSubscriptionName(const std::string& base, const std if (name.empty()) { return (boost::format("%1%_%2%") % base % Uuid(true).str()).str(); } else { - return name; + return (boost::format("%1%_%2%") % base % name).str(); } } @@ -504,9 +490,7 @@ Subscription::Subscription(const Address& address, const std::string& type) queue(getSubscriptionName(name, (Opt(address)/LINK/NAME).str())), reliable(AddressResolution::is_reliable(address)), durable(Opt(address)/LINK/DURABLE), - actualType(type.empty() ? (specifiedType.empty() ? TOPIC_EXCHANGE : specifiedType) : type), - exclusiveQueue((Opt(address)/LINK/X_DECLARE/EXCLUSIVE).asBool(true)), - exclusiveSubscription((Opt(address)/LINK/X_SUBSCRIBE/EXCLUSIVE).asBool(exclusiveQueue)) + actualType(type.empty() ? (specifiedType.empty() ? TOPIC_EXCHANGE : specifiedType) : type) { (Opt(address)/LINK/X_DECLARE/ARGUMENTS).collect(queueOptions); (Opt(address)/LINK/X_SUBSCRIBE/ARGUMENTS).collect(subscriptionOptions); @@ -566,7 +550,7 @@ void Subscription::subscribe(qpid::client::AsyncSession& session, const std::str checkAssert(session, FOR_RECEIVER); //create subscription queue: - session.queueDeclare(arg::queue=queue, arg::exclusive=exclusiveQueue, + session.queueDeclare(arg::queue=queue, arg::exclusive=true, arg::autoDelete=!reliable, arg::durable=durable, arg::arguments=queueOptions); //'default' binding: bindings.bind(session); @@ -575,15 +559,15 @@ void Subscription::subscribe(qpid::client::AsyncSession& session, const std::str linkBindings.bind(session); //subscribe to subscription queue: AcceptMode accept = reliable ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE; - session.messageSubscribe(arg::queue=queue, arg::destination=destination, - arg::exclusive=exclusiveSubscription, arg::acceptMode=accept, arg::arguments=subscriptionOptions); + session.messageSubscribe(arg::queue=queue, arg::destination=destination, + arg::exclusive=true, arg::acceptMode=accept, arg::arguments=subscriptionOptions); } void Subscription::cancel(qpid::client::AsyncSession& session, const std::string& destination) { linkBindings.unbind(session); session.messageCancel(destination); - if (exclusiveQueue) session.queueDelete(arg::queue=queue, arg::ifUnused=true); + session.queueDelete(arg::queue=queue); checkDelete(session, FOR_RECEIVER); } @@ -777,32 +761,18 @@ Exchange::Exchange(const Address& a) : Node(a), linkBindings.setDefaultExchange(name); } -bool Exchange::isReservedName() -{ - return name.find(PREFIX_AMQ) != std::string::npos || name.find(PREFIX_QPID) != std::string::npos; -} - void Exchange::checkCreate(qpid::client::AsyncSession& session, CheckMode mode) { if (enabled(createPolicy, mode)) { try { - if (isReservedName()) { - try { - sync(session).exchangeDeclare(arg::exchange=name, arg::passive=true); - } catch (const qpid::framing::NotFoundException& /*e*/) { - throw ResolutionError((boost::format("Cannot create exchange %1%; names beginning with \"amq.\" or \"qpid.\" are reserved.") % name).str()); - } - - } else { - std::string type = specifiedType; - if (type.empty()) type = TOPIC_EXCHANGE; - session.exchangeDeclare(arg::exchange=name, - arg::type=type, - arg::durable=durable, - arg::autoDelete=autoDelete, - arg::alternateExchange=alternateExchange, - arg::arguments=arguments); - } + std::string type = specifiedType; + if (type.empty()) type = TOPIC_EXCHANGE; + session.exchangeDeclare(arg::exchange=name, + arg::type=type, + arg::durable=durable, + arg::autoDelete=autoDelete, + arg::alternateExchange=alternateExchange, + arg::arguments=arguments); nodeBindings.bind(session); session.sync(); } catch (const qpid::framing::NotAllowedException& e) { @@ -852,7 +822,7 @@ void Exchange::checkAssert(qpid::client::AsyncSession& session, CheckMode mode) FieldTable::ValuePtr v = result.getArguments().get(i->first); if (!v) { throw AssertionFailed((boost::format("Option %1% not set for %2%") % i->first % name).str()); - } else if (*i->second != *v) { + } else if (i->second != v) { throw AssertionFailed((boost::format("Option %1% does not match for %2%, expected %3%, got %4%") % i->first % name % *(i->second) % *v).str()); } diff --git a/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp index cc6e9b9ab2..5a545c1f6a 100644 --- a/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp +++ b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.cpp @@ -20,6 +20,7 @@ */ #include "ConnectionImpl.h" #include "SessionImpl.h" +#include "SimpleUrlParser.h" #include "qpid/messaging/exceptions.h" #include "qpid/messaging/Session.h" #include "qpid/messaging/PrivateImplRef.h" @@ -38,18 +39,26 @@ using qpid::types::Variant; using qpid::types::VAR_LIST; using qpid::framing::Uuid; -namespace { -void merge(const std::string& value, std::vector<std::string>& list) { - if (std::find(list.begin(), list.end(), value) == list.end()) - list.push_back(value); +void convert(const Variant::List& from, std::vector<std::string>& to) +{ + for (Variant::List::const_iterator i = from.begin(); i != from.end(); ++i) { + to.push_back(i->asString()); + } } -void merge(const Variant::List& from, std::vector<std::string>& to) +template <class T> bool setIfFound(const Variant::Map& map, const std::string& key, T& value) { - for (Variant::List::const_iterator i = from.begin(); i != from.end(); ++i) - merge(i->asString(), to); + Variant::Map::const_iterator i = map.find(key); + if (i != map.end()) { + value = (T) i->second; + QPID_LOG(debug, "option " << key << " specified as " << i->second); + return true; + } else { + return false; + } } +namespace { std::string asString(const std::vector<std::string>& v) { std::stringstream os; os << "["; @@ -62,8 +71,49 @@ std::string asString(const std::vector<std::string>& v) { } } +template <> bool setIfFound< std::vector<std::string> >(const Variant::Map& map, + const std::string& key, + std::vector<std::string>& value) +{ + Variant::Map::const_iterator i = map.find(key); + if (i != map.end()) { + value.clear(); + if (i->second.getType() == VAR_LIST) { + convert(i->second.asList(), value); + } else { + value.push_back(i->second.asString()); + } + QPID_LOG(debug, "option " << key << " specified as " << asString(value)); + return true; + } else { + return false; + } +} + +void convert(const Variant::Map& from, ConnectionSettings& to) +{ + setIfFound(from, "username", to.username); + setIfFound(from, "password", to.password); + setIfFound(from, "sasl-mechanism", to.mechanism); + setIfFound(from, "sasl-service", to.service); + setIfFound(from, "sasl-min-ssf", to.minSsf); + setIfFound(from, "sasl-max-ssf", to.maxSsf); + + setIfFound(from, "heartbeat", to.heartbeat); + setIfFound(from, "tcp-nodelay", to.tcpNoDelay); + + setIfFound(from, "locale", to.locale); + setIfFound(from, "max-channels", to.maxChannels); + setIfFound(from, "max-frame-size", to.maxFrameSize); + setIfFound(from, "bounds", to.bounds); + + setIfFound(from, "transport", to.protocol); + + setIfFound(from, "ssl-cert-name", to.sslCertName); +} + ConnectionImpl::ConnectionImpl(const std::string& url, const Variant::Map& options) : - replaceUrls(false), reconnect(false), timeout(-1), limit(-1), + reconnect(false), timeout(-1), limit(-1), minReconnectInterval(3), maxReconnectInterval(60), retries(0), reconnectOnLimitExceeded(true) { @@ -74,69 +124,27 @@ ConnectionImpl::ConnectionImpl(const std::string& url, const Variant::Map& optio void ConnectionImpl::setOptions(const Variant::Map& options) { - for (Variant::Map::const_iterator i = options.begin(); i != options.end(); ++i) { - setOption(i->first, i->second); + sys::Mutex::ScopedLock l(lock); + convert(options, settings); + setIfFound(options, "reconnect", reconnect); + setIfFound(options, "reconnect-timeout", timeout); + setIfFound(options, "reconnect-limit", limit); + int64_t reconnectInterval; + if (setIfFound(options, "reconnect-interval", reconnectInterval)) { + minReconnectInterval = maxReconnectInterval = reconnectInterval; + } else { + setIfFound(options, "reconnect-interval-min", minReconnectInterval); + setIfFound(options, "reconnect-interval-max", maxReconnectInterval); } + setIfFound(options, "reconnect-urls", urls); + setIfFound(options, "x-reconnect-on-limit-exceeded", reconnectOnLimitExceeded); } void ConnectionImpl::setOption(const std::string& name, const Variant& value) { - sys::Mutex::ScopedLock l(lock); - if (name == "reconnect") { - reconnect = value; - } else if (name == "reconnect-timeout" || name == "reconnect_timeout") { - timeout = value; - } else if (name == "reconnect-limit" || name == "reconnect_limit") { - limit = value; - } else if (name == "reconnect-interval" || name == "reconnect_interval") { - maxReconnectInterval = minReconnectInterval = value; - } else if (name == "reconnect-interval-min" || name == "reconnect_interval_min") { - minReconnectInterval = value; - } else if (name == "reconnect-interval-max" || name == "reconnect_interval_max") { - maxReconnectInterval = value; - } else if (name == "reconnect-urls-replace" || name == "reconnect_urls_replace") { - replaceUrls = value.asBool(); - } else if (name == "reconnect-urls" || name == "reconnect_urls") { - if (replaceUrls) urls.clear(); - if (value.getType() == VAR_LIST) { - merge(value.asList(), urls); - } else { - merge(value.asString(), urls); - } - } else if (name == "username") { - settings.username = value.asString(); - } else if (name == "password") { - settings.password = value.asString(); - } else if (name == "sasl-mechanism" || name == "sasl_mechanism" || - name == "sasl-mechanisms" || name == "sasl_mechanisms") { - settings.mechanism = value.asString(); - } else if (name == "sasl-service" || name == "sasl_service") { - settings.service = value.asString(); - } else if (name == "sasl-min-ssf" || name == "sasl_min_ssf") { - settings.minSsf = value; - } else if (name == "sasl-max-ssf" || name == "sasl_max_ssf") { - settings.maxSsf = value; - } else if (name == "heartbeat") { - settings.heartbeat = value; - } else if (name == "tcp-nodelay" || name == "tcp_nodelay") { - settings.tcpNoDelay = value; - } else if (name == "locale") { - settings.locale = value.asString(); - } else if (name == "max-channels" || name == "max_channels") { - settings.maxChannels = value; - } else if (name == "max-frame-size" || name == "max_frame_size") { - settings.maxFrameSize = value; - } else if (name == "bounds") { - settings.bounds = value; - } else if (name == "transport") { - settings.protocol = value.asString(); - } else if (name == "ssl-cert-name" || name == "ssl_cert_name") { - settings.sslCertName = value.asString(); - } else if (name == "x-reconnect-on-limit-exceeded" || name == "x_reconnect_on_limit_exceeded") { - reconnectOnLimitExceeded = value; - } else { - throw qpid::messaging::MessagingException(QPID_MSG("Invalid option: " << name << " not recognised")); - } + Variant::Map options; + options[name] = value; + setOptions(options); } @@ -206,7 +214,7 @@ qpid::messaging::Session ConnectionImpl::newSession(bool transactional, const st sessions[name] = impl; break; } catch (const qpid::TransportFailure&) { - reopen(); + open(); } catch (const qpid::SessionException& e) { throw qpid::messaging::SessionError(e.what()); } catch (const std::exception& e) { @@ -227,15 +235,6 @@ void ConnectionImpl::open() catch (const qpid::Exception& e) { throw messaging::ConnectionError(e.what()); } } -void ConnectionImpl::reopen() -{ - if (!reconnect) { - throw qpid::messaging::TransportFailure("Failed to connect (reconnect disabled)"); - } - open(); -} - - bool expired(const qpid::sys::AbsTime& start, int64_t timeout) { if (timeout == 0) return true; @@ -263,9 +262,14 @@ void ConnectionImpl::connect(const qpid::sys::AbsTime& started) } void ConnectionImpl::mergeUrls(const std::vector<Url>& more, const sys::Mutex::ScopedLock&) { - for (std::vector<Url>::const_iterator i = more.begin(); i != more.end(); ++i) - merge(i->str(), urls); - QPID_LOG(debug, "Added known-hosts, reconnect-urls=" << asString(urls)); + if (more.size()) { + for (size_t i = 0; i < more.size(); ++i) { + if (std::find(urls.begin(), urls.end(), more[i].str()) == urls.end()) { + urls.push_back(more[i].str()); + } + } + QPID_LOG(debug, "Added known-hosts, reconnect-urls=" << asString(urls)); + } } bool ConnectionImpl::tryConnect() @@ -274,14 +278,21 @@ bool ConnectionImpl::tryConnect() for (std::vector<std::string>::const_iterator i = urls.begin(); i != urls.end(); ++i) { try { QPID_LOG(info, "Trying to connect to " << *i << "..."); - Url url(*i); - if (url.getUser().size()) settings.username = url.getUser(); - if (url.getPass().size()) settings.password = url.getPass(); - connection.open(url, settings); + //TODO: when url support is more complete can avoid this test here + if (i->find("amqp:") == 0) { + Url url(*i); + connection.open(url, settings); + } else { + SimpleUrlParser::parse(*i, settings); + connection.open(settings); + } QPID_LOG(info, "Connected to " << *i); mergeUrls(connection.getInitialBrokers(), l); return resetSessions(l); - } catch (const qpid::TransportFailure& e) { + } catch (const qpid::ConnectionException& e) { + //TODO: need to fix timeout on + //qpid::client::Connection::open() so that it throws + //TransportFailure rather than a ConnectionException QPID_LOG(info, "Failed to connect to " << *i << ": " << e.what()); } } diff --git a/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h index 1b58cbbe3e..09f2038312 100644 --- a/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h +++ b/cpp/src/qpid/client/amqp0_10/ConnectionImpl.h @@ -43,7 +43,6 @@ class ConnectionImpl : public qpid::messaging::ConnectionImpl public: ConnectionImpl(const std::string& url, const qpid::types::Variant::Map& options); void open(); - void reopen(); bool isOpen() const; void close(); qpid::messaging::Session newSession(bool transactional, const std::string& name); @@ -60,7 +59,6 @@ class ConnectionImpl : public qpid::messaging::ConnectionImpl qpid::sys::Semaphore semaphore;//used to coordinate reconnection Sessions sessions; qpid::client::Connection connection; - bool replaceUrls; // Replace rather than merging with reconnect-urls std::vector<std::string> urls; qpid::client::ConnectionSettings settings; bool reconnect; diff --git a/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp b/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp index 3badaf40ba..71e89bdba1 100644 --- a/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp +++ b/cpp/src/qpid/client/amqp0_10/IncomingMessages.cpp @@ -144,10 +144,10 @@ void IncomingMessages::accept() acceptTracker.accept(session); } -void IncomingMessages::accept(qpid::framing::SequenceNumber id, bool cumulative) +void IncomingMessages::accept(qpid::framing::SequenceNumber id) { sys::Mutex::ScopedLock l(lock); - acceptTracker.accept(id, session, cumulative); + acceptTracker.accept(id, session); } @@ -301,7 +301,6 @@ const std::string SUBJECT("qpid.subject"); const std::string X_APP_ID("x-amqp-0-10.app-id"); const std::string X_ROUTING_KEY("x-amqp-0-10.routing-key"); const std::string X_CONTENT_ENCODING("x-amqp-0-10.content-encoding"); -const std::string X_TIMESTAMP("x-amqp-0-10.timestamp"); } void populateHeaders(qpid::messaging::Message& message, @@ -335,13 +334,10 @@ void populateHeaders(qpid::messaging::Message& message, if (messageProperties->hasContentEncoding()) { message.getProperties()[X_CONTENT_ENCODING] = messageProperties->getContentEncoding(); } - // routing-key, timestamp, others? + // routing-key, others? if (deliveryProperties && deliveryProperties->hasRoutingKey()) { message.getProperties()[X_ROUTING_KEY] = deliveryProperties->getRoutingKey(); } - if (deliveryProperties && deliveryProperties->hasTimestamp()) { - message.getProperties()[X_TIMESTAMP] = deliveryProperties->getTimestamp(); - } } } diff --git a/cpp/src/qpid/client/amqp0_10/IncomingMessages.h b/cpp/src/qpid/client/amqp0_10/IncomingMessages.h index 9053b70312..f6a291bc68 100644 --- a/cpp/src/qpid/client/amqp0_10/IncomingMessages.h +++ b/cpp/src/qpid/client/amqp0_10/IncomingMessages.h @@ -72,7 +72,7 @@ class IncomingMessages bool get(Handler& handler, qpid::sys::Duration timeout); bool getNextDestination(std::string& destination, qpid::sys::Duration timeout); void accept(); - void accept(qpid::framing::SequenceNumber id, bool cumulative); + void accept(qpid::framing::SequenceNumber id); void releaseAll(); void releasePending(const std::string& destination); diff --git a/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp b/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp index d93416da75..82358961c8 100644 --- a/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp +++ b/cpp/src/qpid/client/amqp0_10/OutgoingMessage.cpp @@ -59,9 +59,7 @@ void OutgoingMessage::convert(const qpid::messaging::Message& from) message.getMessageProperties().setReplyTo(AddressResolution::convert(address)); } translate(from.getProperties(), message.getMessageProperties().getApplicationHeaders()); - if (from.getTtl().getMilliseconds()) { - message.getDeliveryProperties().setTtl(from.getTtl().getMilliseconds()); - } + message.getDeliveryProperties().setTtl(from.getTtl().getMilliseconds()); if (from.getDurable()) { message.getDeliveryProperties().setDeliveryMode(DELIVERY_MODE_PERSISTENT); } diff --git a/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp b/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp index f2f0f1a9e5..e1b75ec0cf 100644 --- a/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp +++ b/cpp/src/qpid/client/amqp0_10/SenderImpl.cpp @@ -135,7 +135,6 @@ void SenderImpl::sendUnreliable(const qpid::messaging::Message& m) void SenderImpl::replay(const sys::Mutex::ScopedLock&) { for (OutgoingMessages::iterator i = outgoing.begin(); i != outgoing.end(); ++i) { - i->message.setRedelivered(true); sink->send(session, name, *i); } } @@ -148,7 +147,7 @@ uint32_t SenderImpl::checkPendingSends(bool flush) { uint32_t SenderImpl::checkPendingSends(bool flush, const sys::Mutex::ScopedLock&) { if (flush) { - session.flush(); + session.flush(); flushed = true; } else { flushed = false; diff --git a/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp b/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp index be5eab1f2b..75a71997fd 100644 --- a/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp +++ b/cpp/src/qpid/client/amqp0_10/SessionImpl.cpp @@ -60,14 +60,12 @@ SessionImpl::SessionImpl(ConnectionImpl& c, bool t) : connection(&c), transactio void SessionImpl::checkError() { - ScopedLock l(lock); qpid::client::SessionBase_0_10Access s(session); s.get()->assertOpen(); } bool SessionImpl::hasError() { - ScopedLock l(lock); qpid::client::SessionBase_0_10Access s(session); return s.get()->hasError(); } @@ -114,14 +112,13 @@ void SessionImpl::release(qpid::messaging::Message& m) execute1<Release>(m); } -void SessionImpl::acknowledge(qpid::messaging::Message& m, bool cumulative) +void SessionImpl::acknowledge(qpid::messaging::Message& m) { //Should probably throw an exception on failure here, or indicate //it through a return type at least. Failure means that the //message may be redelivered; i.e. the application cannot delete //any state necessary for preventing reprocessing of the message - Acknowledge2 ack(*this, m, cumulative); - execute(ack); + execute1<Acknowledge1>(m); } void SessionImpl::close() @@ -131,29 +128,27 @@ void SessionImpl::close() senders.clear(); receivers.clear(); } else { - Senders sCopy; - Receivers rCopy; - { - ScopedLock l(lock); - senders.swap(sCopy); - receivers.swap(rCopy); - } - for (Senders::iterator i = sCopy.begin(); i != sCopy.end(); ++i) - { - // outside the lock, will call senderCancelled - i->second.close(); + while (true) { + Sender s; + { + ScopedLock l(lock); + if (senders.empty()) break; + s = senders.begin()->second; + } + s.close(); // outside the lock, will call senderCancelled } - for (Receivers::iterator i = rCopy.begin(); i != rCopy.end(); ++i) - { - // outside the lock, will call receiverCancelled - i->second.close(); + while (true) { + Receiver r; + { + ScopedLock l(lock); + if (receivers.empty()) break; + r = receivers.begin()->second; + } + r.close(); // outside the lock, will call receiverCancelled } } connection->closed(*this); - if (!hasError()) { - ScopedLock l(lock); - session.close(); - } + if (!hasError()) session.close(); } template <class T, class S> boost::intrusive_ptr<S> getImplPtr(T& t) @@ -436,11 +431,8 @@ uint32_t SessionImpl::getUnsettledAcksImpl(const std::string* destination) void SessionImpl::syncImpl(bool block) { - { - ScopedLock l(lock); - if (block) session.sync(); - else session.flush(); - } + if (block) session.sync(); + else session.flush(); //cleanup unconfirmed accept records: incoming.pendingAccept(); } @@ -475,10 +467,10 @@ void SessionImpl::acknowledgeImpl() if (!transactional) incoming.accept(); } -void SessionImpl::acknowledgeImpl(qpid::messaging::Message& m, bool cumulative) +void SessionImpl::acknowledgeImpl(qpid::messaging::Message& m) { ScopedLock l(lock); - if (!transactional) incoming.accept(MessageImplAccess::get(m).getInternalId(), cumulative); + if (!transactional) incoming.accept(MessageImplAccess::get(m).getInternalId()); } void SessionImpl::rejectImpl(qpid::messaging::Message& m) @@ -517,7 +509,7 @@ void SessionImpl::senderCancelled(const std::string& name) void SessionImpl::reconnect() { - connection->reopen(); + connection->open(); } bool SessionImpl::backoff() diff --git a/cpp/src/qpid/client/amqp0_10/SessionImpl.h b/cpp/src/qpid/client/amqp0_10/SessionImpl.h index c7dea77d18..2a2aa47df6 100644 --- a/cpp/src/qpid/client/amqp0_10/SessionImpl.h +++ b/cpp/src/qpid/client/amqp0_10/SessionImpl.h @@ -63,7 +63,7 @@ class SessionImpl : public qpid::messaging::SessionImpl void acknowledge(bool sync); void reject(qpid::messaging::Message&); void release(qpid::messaging::Message&); - void acknowledge(qpid::messaging::Message& msg, bool cumulative); + void acknowledge(qpid::messaging::Message& msg); void close(); void sync(bool block); qpid::messaging::Sender createSender(const qpid::messaging::Address& address); @@ -139,7 +139,7 @@ class SessionImpl : public qpid::messaging::SessionImpl void commitImpl(); void rollbackImpl(); void acknowledgeImpl(); - void acknowledgeImpl(qpid::messaging::Message&, bool cumulative); + void acknowledgeImpl(qpid::messaging::Message&); void rejectImpl(qpid::messaging::Message&); void releaseImpl(qpid::messaging::Message&); void closeImpl(); @@ -204,13 +204,12 @@ class SessionImpl : public qpid::messaging::SessionImpl void operator()() { impl.releaseImpl(message); } }; - struct Acknowledge2 : Command + struct Acknowledge1 : Command { qpid::messaging::Message& message; - bool cumulative; - Acknowledge2(SessionImpl& i, qpid::messaging::Message& m, bool c) : Command(i), message(m), cumulative(c) {} - void operator()() { impl.acknowledgeImpl(message, cumulative); } + Acknowledge1(SessionImpl& i, qpid::messaging::Message& m) : Command(i), message(m) {} + void operator()() { impl.acknowledgeImpl(message); } }; struct CreateSender; diff --git a/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp b/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp new file mode 100644 index 0000000000..327c2274a6 --- /dev/null +++ b/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.cpp @@ -0,0 +1,79 @@ +/* + * + * 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 "SimpleUrlParser.h" +#include "qpid/client/ConnectionSettings.h" +#include "qpid/Exception.h" +#include <boost/lexical_cast.hpp> + +namespace qpid { +namespace client { +namespace amqp0_10 { + +bool split(const std::string& in, char delim, std::pair<std::string, std::string>& result) +{ + std::string::size_type i = in.find(delim); + if (i != std::string::npos) { + result.first = in.substr(0, i); + if (i+1 < in.size()) { + result.second = in.substr(i+1); + } + return true; + } else { + return false; + } +} + +void parseUsernameAndPassword(const std::string& in, qpid::client::ConnectionSettings& result) +{ + std::pair<std::string, std::string> parts; + if (!split(in, '/', parts)) { + result.username = in; + } else { + result.username = parts.first; + result.password = parts.second; + } +} + +void parseHostAndPort(const std::string& in, qpid::client::ConnectionSettings& result) +{ + std::pair<std::string, std::string> parts; + if (!split(in, ':', parts)) { + result.host = in; + } else { + result.host = parts.first; + if (parts.second.size()) { + result.port = boost::lexical_cast<uint16_t>(parts.second); + } + } +} + +void SimpleUrlParser::parse(const std::string& url, qpid::client::ConnectionSettings& result) +{ + std::pair<std::string, std::string> parts; + if (!split(url, '@', parts)) { + parseHostAndPort(url, result); + } else { + parseUsernameAndPassword(parts.first, result); + parseHostAndPort(parts.second, result); + } +} + +}}} // namespace qpid::client::amqp0_10 diff --git a/cpp/src/qpid/DisableExceptionLogging.h b/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.h index 04a9240513..24f90ca9d6 100644 --- a/cpp/src/qpid/DisableExceptionLogging.h +++ b/cpp/src/qpid/client/amqp0_10/SimpleUrlParser.h @@ -1,5 +1,5 @@ -#ifndef QPID_DISABLEEXCEPTIONLOGGING_H -#define QPID_DISABLEEXCEPTIONLOGGING_H +#ifndef QPID_CLIENT_AMQP0_10_SIMPLEURLPARSER_H +#define QPID_CLIENT_AMQP0_10_SIMPLEURLPARSER_H /* * @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -21,19 +21,22 @@ * under the License. * */ -#include "qpid/CommonImportExport.h" +#include <string> namespace qpid { +namespace client { + +struct ConnectionSettings; + +namespace amqp0_10 { /** - * Temporarily disable logging in qpid::Exception constructor. - * Used by log::Logger to avoid logging exceptions during Logger construction. + * Parses a simple url of the form user/password@hostname:port */ -struct DisableExceptionLogging +struct SimpleUrlParser { - QPID_COMMON_EXTERN DisableExceptionLogging(); - QPID_COMMON_EXTERN ~DisableExceptionLogging(); + static void parse(const std::string& url, qpid::client::ConnectionSettings& result); }; -} // namespace qpid +}}} // namespace qpid::client::amqp0_10 -#endif /*!QPID_DISABLEEXCEPTIONLOGGING_H*/ +#endif /*!QPID_CLIENT_AMQP0_10_SIMPLEURLPARSER_H*/ diff --git a/cpp/src/qpid/client/windows/SaslFactory.cpp b/cpp/src/qpid/client/windows/SaslFactory.cpp index 53d825771b..63c7fa3d1f 100644 --- a/cpp/src/qpid/client/windows/SaslFactory.cpp +++ b/cpp/src/qpid/client/windows/SaslFactory.cpp @@ -71,7 +71,7 @@ class WindowsSasl : public Sasl public: WindowsSasl( const std::string &, const std::string &, const std::string &, const std::string &, int, int ); ~WindowsSasl(); - bool start(const std::string& mechanisms, std::string& response, const SecuritySettings* externalSettings); + std::string start(const std::string& mechanisms, const SecuritySettings* externalSettings); std::string step(const std::string& challenge); std::string getMechanism(); std::string getUserId(); @@ -121,8 +121,8 @@ WindowsSasl::~WindowsSasl() { } -bool WindowsSasl::start(const std::string& mechanisms, std::string& response, - const SecuritySettings* /*externalSettings*/) +std::string WindowsSasl::start(const std::string& mechanisms, + const SecuritySettings* /*externalSettings*/) { QPID_LOG(debug, "WindowsSasl::start(" << mechanisms << ")"); @@ -142,18 +142,18 @@ bool WindowsSasl::start(const std::string& mechanisms, std::string& response, if (!haveAnon && !havePlain) throw InternalErrorException(QPID_MSG("Sasl error: no common mechanism")); + std::string resp = ""; if (havePlain) { mechanism = PLAIN; - response = ((char)0) + settings.username + ((char)0) + settings.password; + resp = ((char)0) + settings.username + ((char)0) + settings.password; } else { mechanism = ANONYMOUS; - response = ""; } - return true; + return resp; } -std::string WindowsSasl::step(const std::string& /*challenge*/) +std::string WindowsSasl::step(const std::string& challenge) { // Shouldn't get this for PLAIN... throw InternalErrorException(QPID_MSG("Sasl step error")); @@ -169,7 +169,7 @@ std::string WindowsSasl::getUserId() return std::string(); // TODO - when GSSAPI is supported, return userId for connection. } -std::auto_ptr<SecurityLayer> WindowsSasl::getSecurityLayer(uint16_t /*maxFrameSize*/) +std::auto_ptr<SecurityLayer> WindowsSasl::getSecurityLayer(uint16_t maxFrameSize) { return std::auto_ptr<SecurityLayer>(0); } diff --git a/cpp/src/qpid/client/windows/SslConnector.cpp b/cpp/src/qpid/client/windows/SslConnector.cpp index 785c817928..a33713e1a8 100644 --- a/cpp/src/qpid/client/windows/SslConnector.cpp +++ b/cpp/src/qpid/client/windows/SslConnector.cpp @@ -77,7 +77,7 @@ public: framing::ProtocolVersion pVersion, const ConnectionSettings&, ConnectionImpl*); - virtual void connect(const std::string& host, const std::string& port); + virtual void connect(const std::string& host, int port); virtual void connected(const Socket&); unsigned int getSSF(); }; @@ -153,7 +153,7 @@ SslConnector::~SslConnector() // Will this get reach via virtual method via boost::bind???? -void SslConnector::connect(const std::string& host, const std::string& port) { +void SslConnector::connect(const std::string& host, int port) { brokerHost = host; TCPConnector::connect(host, port); } diff --git a/cpp/src/qpid/cluster/Cluster.cpp b/cpp/src/qpid/cluster/Cluster.cpp index e6e3de64f2..dd4882774b 100644 --- a/cpp/src/qpid/cluster/Cluster.cpp +++ b/cpp/src/qpid/cluster/Cluster.cpp @@ -36,45 +36,45 @@ * * IMPORTANT NOTE: any time code is added to the broker that uses timers, * the cluster may need to be updated to take account of this. - * + * * * USE OF TIMESTAMPS IN THE BROKER - * + * * The following are the current areas where broker uses timers or timestamps: - * + * * - Producer flow control: broker::SemanticState uses * connection::getClusterOrderOutput. a FrameHandler that sends * frames to the client via the cluster. Used by broker::SessionState - * + * * - QueueCleaner, Message TTL: uses ExpiryPolicy, which is * implemented by cluster::ExpiryPolicy. - * + * * - Connection heartbeat: sends connection controls, not part of * session command counting so OK to ignore. - * + * * - LinkRegistry: only cluster elder is ever active for links. - * + * * - management::ManagementBroker: uses MessageHandler supplied by cluster * to send messages to the broker via the cluster. + * + * - Dtx: not yet supported with cluster. * - * cluster::ExpiryPolicy uses cluster time. + * cluster::ExpiryPolicy implements the strategy for message expiry. * * ClusterTimer implements periodic timed events in the cluster context. - * Used for: - * - periodic management events. - * - DTX transaction timeouts. + * Used for periodic management events. * * <h1>CLUSTER PROTOCOL OVERVIEW</h1> - * + * * Messages sent to/from CPG are called Events. * * An Event carries a ConnectionId, which includes a MemberId and a * connection number. - * + * * Events are either * - Connection events: non-0 connection number and are associated with a connection. * - Cluster Events: 0 connection number, are not associated with a connection. - * + * * Events are further categorized as: * - Control: carries method frame(s) that affect cluster behavior. * - Data: carries raw data received from a client connection. @@ -146,7 +146,6 @@ #include "qpid/framing/AMQP_AllOperations.h" #include "qpid/framing/AllInvoker.h" #include "qpid/framing/ClusterConfigChangeBody.h" -#include "qpid/framing/ClusterClockBody.h" #include "qpid/framing/ClusterConnectionDeliverCloseBody.h" #include "qpid/framing/ClusterConnectionAbortBody.h" #include "qpid/framing/ClusterRetractOfferBody.h" @@ -199,7 +198,7 @@ namespace _qmf = ::qmf::org::apache::qpid::cluster; * Currently use SVN revision to avoid clashes with versions from * different branches. */ -const uint32_t Cluster::CLUSTER_VERSION = 1159329; +const uint32_t Cluster::CLUSTER_VERSION = 1058747; struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler { qpid::cluster::Cluster& cluster; @@ -215,7 +214,7 @@ struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler { { cluster.initialStatus( member, version, active, clusterId, - framing::cluster::StoreState(storeState), shutdownId, + framing::cluster::StoreState(storeState), shutdownId, firstConfig, l); } void ready(const std::string& url) { @@ -231,21 +230,21 @@ struct ClusterDispatcher : public framing::AMQP_AllOperations::ClusterHandler { cluster.updateOffer(member, updatee, l); } void retractOffer(uint64_t updatee) { cluster.retractOffer(member, updatee, l); } + void messageExpired(uint64_t id) { cluster.messageExpired(member, id, l); } void errorCheck(uint8_t type, const framing::SequenceNumber& frameSeq) { cluster.errorCheck(member, type, frameSeq, l); } void timerWakeup(const std::string& name) { cluster.timerWakeup(member, name, l); } - void timerDrop(const std::string& name) { cluster.timerDrop(member, name, l); } + void timerDrop(const std::string& name) { cluster.timerWakeup(member, name, l); } void shutdown(const Uuid& id) { cluster.shutdown(member, id, l); } void deliverToQueue(const std::string& queue, const std::string& message) { cluster.deliverToQueue(queue, message, l); } - void clock(uint64_t time) { cluster.clock(time, l); } bool invoke(AMQBody& body) { return framing::invoke(*this, body).wasHandled(); } }; Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) : - settings(set), + settings(set), broker(b), mgmtObject(0), poller(b.getPoller()), @@ -254,7 +253,7 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) : self(cpg.self()), clusterId(true), mAgent(0), - expiryPolicy(new ExpiryPolicy(*this)), + 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), @@ -278,11 +277,8 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) : lastBroker(false), updateRetracted(false), updateClosed(false), - error(*this), - acl(0) + error(*this) { - broker.setInCluster(true); - // We give ownership of the timer to the broker and keep a plain pointer. // This is OK as it means the timer has the same lifetime as the broker. timer = new ClusterTimer(*this); @@ -303,7 +299,7 @@ Cluster::Cluster(const ClusterSettings& set, broker::Broker& b) : // Load my store status before we go into initialization if (! broker::NullMessageStore::isNullStore(&broker.getStore())) { store.load(); - clusterId = store.getClusterId(); + clusterId = store.getClusterId(); QPID_LOG(notice, "Cluster store state: " << store) } cpg.join(name); @@ -364,15 +360,14 @@ void Cluster::addShadowConnection(const boost::intrusive_ptr<Connection>& c) { // Safe to use connections here because we're pre-catchup, stalled // and discarding, so deliveredFrame is not processing any // connection events. - assert(discarding); + assert(discarding); pair<ConnectionMap::iterator, bool> ib = connections.insert(ConnectionMap::value_type(c->getId(), c)); - // Like this to avoid tripping up unused variable warning when NDEBUG set - if (!ib.second) assert(ib.second); + assert(ib.second); } void Cluster::erase(const ConnectionId& id) { - Lock l(lock); + Lock l(lock); erase(id,l); } @@ -398,9 +393,9 @@ std::vector<Url> Cluster::getUrls() const { std::vector<Url> Cluster::getUrls(Lock&) const { return map.memberUrls(); -} +} -void Cluster::leave() { +void Cluster::leave() { Lock l(lock); leave(l); } @@ -410,7 +405,7 @@ void Cluster::leave() { QPID_LOG(warning, *this << " error leaving cluster: " << e.what()); \ } do {} while(0) -void Cluster::leave(Lock&) { +void Cluster::leave(Lock&) { if (state != LEFT) { state = LEFT; QPID_LOG(notice, *this << " leaving cluster " << name); @@ -429,7 +424,7 @@ void Cluster::deliver( uint32_t nodeid, uint32_t pid, void* msg, - int msg_len) + int msg_len) { MemberId from(nodeid, pid); framing::Buffer buf(static_cast<char*>(msg), msg_len); @@ -460,7 +455,7 @@ void Cluster::deliveredEvent(const Event& e) { EventFrame ef(e, e.getFrame()); // Stop the deliverEventQueue on update offers. // This preserves the connection decoder fragments for an update. - // Only do this for the two brokers that are directly involved in this + // Only do this for the two brokers that are directly involved in this // offer: the one making the offer, or the one receiving it. const ClusterUpdateOfferBody* offer = castUpdateOffer(ef.frame.getBody()); if (offer && ( e.getMemberId() == self || MemberId(offer->getUpdatee()) == self) ) { @@ -470,7 +465,7 @@ void Cluster::deliveredEvent(const Event& e) { } deliverFrame(ef); } - else if(!discarding) { + else if(!discarding) { if (e.isControl()) deliverFrame(EventFrame(e, e.getFrame())); else { @@ -512,7 +507,7 @@ void Cluster::deliveredFrame(const EventFrame& efConst) { // the event queue. e.frame = AMQFrame( ClusterRetractOfferBody(ProtocolVersion(), offer->getUpdatee())); - deliverEventQueue.start(); + deliverEventQueue.start(); } // Process each frame through the error checker. if (error.isUnresolved()) { @@ -520,14 +515,14 @@ void Cluster::deliveredFrame(const EventFrame& efConst) { while (error.canProcess()) // There is a frame ready to process. processFrame(error.getNext(), l); } - else + else processFrame(e, l); } void Cluster::processFrame(const EventFrame& e, Lock& l) { if (e.isCluster()) { - QPID_LOG_IF(trace, loggable(e.frame), *this << " DLVR: " << e); + 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")); @@ -536,15 +531,14 @@ void Cluster::processFrame(const EventFrame& e, Lock& l) { map.incrementFrameSeq(); ConnectionPtr connection = getConnection(e, l); if (connection) { - QPID_LOG_IF(trace, loggable(e.frame), - *this << " DLVR " << map.getFrameSeq() << ": " << e); + QPID_LOG(trace, *this << " DLVR " << map.getFrameSeq() << ": " << e); connection->deliveredFrame(e); } else - throw Exception(QPID_MSG("Unknown connection: " << e)); + QPID_LOG(trace, *this << " DROP (no connection): " << e); } else // Drop connection frames while state < CATCHUP - QPID_LOG_IF(trace, loggable(e.frame), *this << " DROP (joining): " << e); + QPID_LOG(trace, *this << " DROP (joining): " << e); } // Called in deliverFrameQueue thread @@ -583,7 +577,7 @@ Cluster::ConnectionVector Cluster::getConnections(Lock&) { } // CPG config-change callback. -void Cluster::configChange ( +void Cluster::configChange ( cpg_handle_t /*handle*/, const cpg_name */*group*/, const cpg_address *members, int nMembers, @@ -613,7 +607,7 @@ void Cluster::setReady(Lock&) { } // Set the management status from the Cluster::state. -// +// // NOTE: Management updates are sent based on property changes. In // order to keep consistency across the cluster, we touch the local // management status property even if it is locally unchanged for any @@ -624,7 +618,7 @@ void Cluster::setMgmtStatus(Lock&) { } void Cluster::initMapCompleted(Lock& l) { - // Called on completion of the initial status map. + // Called on completion of the initial status map. QPID_LOG(debug, *this << " initial status map complete. "); setMgmtStatus(l); if (state == PRE_INIT) { @@ -671,8 +665,6 @@ void Cluster::initMapCompleted(Lock& l) { else { // I can go ready. discarding = false; setReady(l); - // Must be called *before* memberUpdate so first update will be generated. - failoverExchange->setReady(); memberUpdate(l); updateMgmtMembership(l); mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), self); @@ -709,8 +701,8 @@ void Cluster::configChange(const MemberId&, if (initMap.isResendNeeded()) { mcast.mcastControl( ClusterInitialStatusBody( - ProtocolVersion(), CLUSTER_VERSION, state > INIT, clusterId, - store.getState(), store.getShutdownId(), + ProtocolVersion(), CLUSTER_VERSION, state > INIT, clusterId, + store.getState(), store.getShutdownId(), initMap.getFirstConfigStr() ), self); @@ -725,20 +717,6 @@ void Cluster::configChange(const MemberId&, updateMgmtMembership(l); // Update on every config change for consistency } -struct ClusterClockTask : public sys::TimerTask { - Cluster& cluster; - sys::Timer& timer; - - ClusterClockTask(Cluster& cluster, sys::Timer& timer, uint16_t clockInterval) - : TimerTask(Duration(clockInterval * TIME_MSEC),"ClusterClock"), cluster(cluster), timer(timer) {} - - void fire() { - cluster.sendClockUpdate(); - setupNextFire(); - timer.add(this); - } -}; - void Cluster::becomeElder(Lock&) { if (elder) return; // We were already the elder. // We are the oldest, reactive links if necessary @@ -746,8 +724,6 @@ void Cluster::becomeElder(Lock&) { elder = true; broker.getLinks().setPassive(false); timer->becomeElder(); - - clockTimer.add(new ClusterClockTask(*this, clockTimer, settings.clockInterval)); } void Cluster::makeOffer(const MemberId& id, Lock& ) { @@ -783,7 +759,7 @@ std::string Cluster::debugSnapshot() { // point we know the poller has stopped so no poller callbacks will be // invoked. We must ensure that CPG has also shut down so no CPG // callbacks will be invoked. -// +// void Cluster::brokerShutdown() { sys::ClusterSafeScope css; // Don't trigger cluster-safe asserts. try { cpg.shutdown(); } @@ -799,7 +775,7 @@ void Cluster::updateRequest(const MemberId& id, const std::string& url, Lock& l) } void Cluster::initialStatus(const MemberId& member, uint32_t version, bool active, - const framing::Uuid& id, + const framing::Uuid& id, framing::cluster::StoreState store, const framing::Uuid& shutdownId, const std::string& firstConfig, @@ -857,8 +833,6 @@ void Cluster::updateOffer(const MemberId& updater, uint64_t updateeInt, Lock& l) else if (updatee == self && url) { assert(state == JOINER); state = UPDATEE; - acl = broker.getAcl(); - broker.setAcl(0); // Disable ACL during update QPID_LOG(notice, *this << " receiving update from " << updater); checkUpdateIn(l); } @@ -870,7 +844,7 @@ void Cluster::updateOffer(const MemberId& updater, uint64_t updateeInt, Lock& l) if (updatee != self && url) { QPID_LOG(debug, debugSnapshot()); if (mAgent) mAgent->clusterUpdate(); - // Updatee will call clusterUpdate() via checkUpdateIn() when update completes + // Updatee will call clusterUpdate when update completes } } @@ -951,15 +925,13 @@ void Cluster::checkUpdateIn(Lock& l) { if (!updateClosed) return; // Wait till update connection closes. if (updatedMap) { // We're up to date map = *updatedMap; + failoverExchange->setUrls(getUrls(l)); mcast.mcastControl(ClusterReadyBody(ProtocolVersion(), myUrl.str()), self); state = CATCHUP; memberUpdate(l); - // Must be called *after* memberUpdate() to avoid sending an extra update. - failoverExchange->setReady(); // NB: don't updateMgmtMembership() here as we are not in the deliver // thread. It will be updated on delivery of the "ready" we just mcast. broker.setClusterUpdatee(false); - broker.setAcl(acl); // Restore ACL discarding = false; // OK to set, we're stalled for update. QPID_LOG(notice, *this << " update complete, starting catch-up."); QPID_LOG(debug, debugSnapshot()); // OK to call because we're stalled. @@ -969,10 +941,6 @@ void Cluster::checkUpdateIn(Lock& l) { mAgent->suppress(false); // Enable management output. mAgent->clusterUpdate(); } - // Restore alternate exchange settings on exchanges. - broker.getExchanges().eachExchange( - boost::bind(&broker::Exchange::recoveryComplete, _1, - boost::ref(broker.getExchanges()))); enableClusterSafe(); // Enable cluster-safe assertions deliverEventQueue.start(); } @@ -1001,7 +969,7 @@ void Cluster::updateOutDone(Lock& l) { void Cluster::updateOutError(const std::exception& e) { Monitor::ScopedLock l(lock); - QPID_LOG(error, *this << " error sending update: " << e.what()); + QPID_LOG(error, *this << " error sending update: " << e.what()); updateOutDone(l); } @@ -1099,7 +1067,7 @@ void Cluster::memberUpdate(Lock& l) { void Cluster::updateMgmtMembership(Lock& l) { if (!mgmtObject) return; std::vector<Url> urls = getUrls(l); - mgmtObject->set_clusterSize(urls.size()); + mgmtObject->set_clusterSize(urls.size()); string urlstr; for(std::vector<Url>::iterator i = urls.begin(); i != urls.end(); i++ ) { if (i != urls.begin()) urlstr += ";"; @@ -1146,6 +1114,10 @@ void Cluster::setClusterId(const Uuid& uuid, Lock&) { QPID_LOG(notice, *this << " cluster-uuid = " << clusterId); } +void Cluster::messageExpired(const MemberId&, uint64_t id, Lock&) { + expiryPolicy->deliverExpire(id); +} + void Cluster::errorCheck(const MemberId& from, uint8_t type, framing::SequenceNumber frameSeq, Lock&) { // If we see an errorCheck here (rather than in the ErrorCheck // class) then we have processed succesfully past the point of the @@ -1183,35 +1155,6 @@ void Cluster::deliverToQueue(const std::string& queue, const std::string& messag q->deliver(msg); } -sys::AbsTime Cluster::getClusterTime() { - Mutex::ScopedLock l(lock); - return clusterTime; -} - -// This method is called during update on the updatee to set the initial cluster time. -void Cluster::clock(const uint64_t time) { - Mutex::ScopedLock l(lock); - clock(time, l); -} - -// called when broadcast message received -void Cluster::clock(const uint64_t time, Lock&) { - clusterTime = AbsTime(EPOCH, time); - AbsTime now = AbsTime::now(); - - if (!elder) { - clusterTimeOffset = Duration(now, clusterTime); - } -} - -// called by elder timer to send clock broadcast -void Cluster::sendClockUpdate() { - Mutex::ScopedLock l(lock); - int64_t nanosecondsSinceEpoch = Duration(EPOCH, now()); - nanosecondsSinceEpoch += clusterTimeOffset; - mcast.mcastControl(ClusterClockBody(ProtocolVersion(), nanosecondsSinceEpoch), self); -} - bool Cluster::deferDeliveryImpl(const std::string& queue, const boost::intrusive_ptr<broker::Message>& msg) { @@ -1224,12 +1167,4 @@ bool Cluster::deferDeliveryImpl(const std::string& queue, return true; } -bool Cluster::loggable(const AMQFrame& f) { - const AMQMethodBody* method = (f.getMethod()); - if (!method) return true; // Not a method - bool isClock = method->amqpClassId() == ClusterClockBody::CLASS_ID - && method->amqpMethodId() == ClusterClockBody::METHOD_ID; - return !isClock; -} - }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/Cluster.h b/cpp/src/qpid/cluster/Cluster.h index ccec4948e6..8f73c6acca 100644 --- a/cpp/src/qpid/cluster/Cluster.h +++ b/cpp/src/qpid/cluster/Cluster.h @@ -56,25 +56,17 @@ namespace qpid { namespace broker { class Message; -class AclModule; } namespace framing { -class AMQFrame; class AMQBody; -struct Uuid; -} - -namespace sys { -class Timer; -class AbsTime; -class Duration; +class Uuid; } namespace cluster { class Connection; -struct EventFrame; +class EventFrame; class ClusterTimer; class UpdateDataExchange; @@ -97,10 +89,10 @@ class Cluster : private Cpg::Handler, public management::Manageable { void initialize(); // Connection map. - void addLocalConnection(const ConnectionPtr&); - void addShadowConnection(const ConnectionPtr&); - void erase(const ConnectionId&); - + void addLocalConnection(const ConnectionPtr&); + void addShadowConnection(const ConnectionPtr&); + void erase(const ConnectionId&); + // URLs of current cluster members. std::vector<std::string> getIds() const; std::vector<Url> getUrls() const; @@ -115,7 +107,7 @@ class Cluster : private Cpg::Handler, public management::Manageable { void updateInRetracted(); // True if we are expecting to receive catch-up connections. bool isExpectingUpdate(); - + MemberId getId() const; broker::Broker& getBroker() const; Multicaster& getMulticast() { return mcast; } @@ -143,12 +135,6 @@ class Cluster : private Cpg::Handler, public management::Manageable { bool deferDeliveryImpl(const std::string& queue, const boost::intrusive_ptr<broker::Message>& msg); - sys::AbsTime getClusterTime(); - void sendClockUpdate(); - void clock(const uint64_t time); - - static bool loggable(const framing::AMQFrame&); // True if the frame should be logged. - private: typedef sys::Monitor::ScopedLock Lock; @@ -158,10 +144,10 @@ class Cluster : private Cpg::Handler, public management::Manageable { /** Version number of the cluster protocol, to avoid mixed versions. */ static const uint32_t CLUSTER_VERSION; - + // NB: A dummy Lock& parameter marks functions that must only be // called with Cluster::lock locked. - + void leave(Lock&); std::vector<std::string> getIds(Lock&) const; std::vector<Url> getUrls(Lock&) const; @@ -170,11 +156,11 @@ class Cluster : private Cpg::Handler, public management::Manageable { void brokerShutdown(); // == Called in deliverEventQueue thread - void deliveredEvent(const Event&); + void deliveredEvent(const Event&); // == Called in deliverFrameQueue thread - void deliveredFrame(const EventFrame&); - void processFrame(const EventFrame&, Lock&); + void deliveredFrame(const EventFrame&); + void processFrame(const EventFrame&, Lock&); // Cluster controls implement XML methods from cluster.xml. void updateRequest(const MemberId&, const std::string&, Lock&); @@ -194,12 +180,12 @@ class Cluster : private Cpg::Handler, public management::Manageable { const std::string& left, const std::string& joined, Lock& l); + void messageExpired(const MemberId&, uint64_t, Lock& l); void errorCheck(const MemberId&, uint8_t type, SequenceNumber frameSeq, Lock&); void timerWakeup(const MemberId&, const std::string& name, Lock&); void timerDrop(const MemberId&, const std::string& name, Lock&); void shutdown(const MemberId&, const framing::Uuid& shutdownId, Lock&); void deliverToQueue(const std::string& queue, const std::string& message, Lock&); - void clock(const uint64_t time, Lock&); // Helper functions ConnectionPtr getConnection(const EventFrame&, Lock&); @@ -209,7 +195,7 @@ class Cluster : private Cpg::Handler, public management::Manageable { void setReady(Lock&); void memberUpdate(Lock&); void setClusterId(const framing::Uuid&, Lock&); - void erase(const ConnectionId&, Lock&); + void erase(const ConnectionId&, Lock&); void requestUpdate(Lock& ); void initMapCompleted(Lock&); void becomeElder(Lock&); @@ -217,7 +203,7 @@ class Cluster : private Cpg::Handler, public management::Manageable { void updateMgmtMembership(Lock&); // == Called in CPG dispatch thread - void deliver( // CPG deliver callback. + void deliver( // CPG deliver callback. cpg_handle_t /*handle*/, const struct cpg_name *group, uint32_t /*nodeid*/, @@ -226,7 +212,7 @@ class Cluster : private Cpg::Handler, public management::Manageable { int /*msg_len*/); void deliverEvent(const Event&); - + void configChange( // CPG config change callback. cpg_handle_t /*handle*/, const struct cpg_name */*group*/, @@ -277,7 +263,7 @@ class Cluster : private Cpg::Handler, public management::Manageable { // Used only in deliverEventQueue thread or when stalled for update. Decoder decoder; bool discarding; - + // Remaining members are protected by lock. mutable sys::Monitor lock; @@ -290,7 +276,7 @@ class Cluster : private Cpg::Handler, public management::Manageable { JOINER, ///< Sent update request, waiting for update offer. UPDATEE, ///< Stalled receive queue at update offer, waiting for update to complete. CATCHUP, ///< Update complete, unstalled but has not yet seen own "ready" event. - READY, ///< Fully operational + READY, ///< Fully operational OFFER, ///< Sent an offer, waiting for accept/reject. UPDATER, ///< Offer accepted, sending a state update. LEFT ///< Final state, left the cluster. @@ -310,13 +296,9 @@ class Cluster : private Cpg::Handler, public management::Manageable { ErrorCheck error; UpdateReceiver updateReceiver; ClusterTimer* timer; - sys::Timer clockTimer; - sys::AbsTime clusterTime; - sys::Duration clusterTimeOffset; - broker::AclModule* acl; friend std::ostream& operator<<(std::ostream&, const Cluster&); - friend struct ClusterDispatcher; + friend class ClusterDispatcher; }; }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/ClusterMap.cpp b/cpp/src/qpid/cluster/ClusterMap.cpp index a8389095c9..040e129970 100644 --- a/cpp/src/qpid/cluster/ClusterMap.cpp +++ b/cpp/src/qpid/cluster/ClusterMap.cpp @@ -50,6 +50,11 @@ void insertFieldTableFromMapValue(FieldTable& ft, const ClusterMap::Map::value_t ft.setString(vt.first.str(), vt.second.str()); } +void assignFieldTable(FieldTable& ft, const ClusterMap::Map& map) { + ft.clear(); + for_each(map.begin(), map.end(), bind(&insertFieldTableFromMapValue, ref(ft), _1)); +} + } ClusterMap::ClusterMap() : frameSeq(0) {} diff --git a/cpp/src/qpid/cluster/ClusterPlugin.cpp b/cpp/src/qpid/cluster/ClusterPlugin.cpp index 69ba095f16..2962daaa07 100644 --- a/cpp/src/qpid/cluster/ClusterPlugin.cpp +++ b/cpp/src/qpid/cluster/ClusterPlugin.cpp @@ -72,7 +72,6 @@ struct ClusterOptions : public Options { ("cluster-cman", optValue(settings.quorum), "Integrate with Cluster Manager (CMAN) cluster.") #endif ("cluster-size", optValue(settings.size, "N"), "Wait for N cluster members before allowing clients to connect.") - ("cluster-clock-interval", optValue(settings.clockInterval,"N"), "How often to broadcast the current time to the cluster nodes, in milliseconds. A value between 5 and 1000 is recommended.") ("cluster-read-max", optValue(settings.readMax,"N"), "Experimental: flow-control limit reads per connection. 0=no limit.") ; } diff --git a/cpp/src/qpid/cluster/ClusterSettings.h b/cpp/src/qpid/cluster/ClusterSettings.h index 2f7b5be20a..8e708aa139 100644 --- a/cpp/src/qpid/cluster/ClusterSettings.h +++ b/cpp/src/qpid/cluster/ClusterSettings.h @@ -35,9 +35,8 @@ struct ClusterSettings { size_t readMax; std::string username, password, mechanism; size_t size; - uint16_t clockInterval; - ClusterSettings() : quorum(false), readMax(10), size(1), clockInterval(10) + ClusterSettings() : quorum(false), readMax(10), size(1) {} Url getUrl(uint16_t port) const { diff --git a/cpp/src/qpid/cluster/ClusterTimer.cpp b/cpp/src/qpid/cluster/ClusterTimer.cpp index b4f7d00f38..f6e1c7a849 100644 --- a/cpp/src/qpid/cluster/ClusterTimer.cpp +++ b/cpp/src/qpid/cluster/ClusterTimer.cpp @@ -70,7 +70,6 @@ void ClusterTimer::add(intrusive_ptr<TimerTask> task) if (i != map.end()) throw Exception(QPID_MSG("Task already exists with name " << task->getName())); map[task->getName()] = task; - // Only the elder actually activates the task with the Timer base class. if (cluster.isElder()) { QPID_LOG(trace, "Elder activating cluster timer task " << task->getName()); @@ -113,9 +112,6 @@ void ClusterTimer::deliverWakeup(const std::string& name) { else { intrusive_ptr<TimerTask> t = i->second; map.erase(i); - // Move the nextFireTime so readyToFire() is true. This is to ensure we - // don't get an error if the fired task calls setupNextFire() - t->setFired(); Timer::fire(t); } } diff --git a/cpp/src/qpid/cluster/Connection.cpp b/cpp/src/qpid/cluster/Connection.cpp index 394749aad2..e9b718e6de 100644 --- a/cpp/src/qpid/cluster/Connection.cpp +++ b/cpp/src/qpid/cluster/Connection.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,8 +24,6 @@ #include "Cluster.h" #include "UpdateReceiver.h" #include "qpid/assert.h" -#include "qpid/broker/DtxAck.h" -#include "qpid/broker/DtxBuffer.h" #include "qpid/broker/SessionState.h" #include "qpid/broker/SemanticState.h" #include "qpid/broker/TxBuffer.h" @@ -37,7 +35,6 @@ #include "qpid/broker/Fairshare.h" #include "qpid/broker/Link.h" #include "qpid/broker/Bridge.h" -#include "qpid/broker/StatefulQueueObserver.h" #include "qpid/broker/Queue.h" #include "qpid/framing/enum.h" #include "qpid/framing/AMQFrame.h" @@ -81,7 +78,7 @@ const std::string shadowPrefix("[shadow]"); Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out, const std::string& mgmtId, const ConnectionId& id, const qpid::sys::SecuritySettings& external) - : cluster(c), self(id), catchUp(false), announced(false), output(*this, out), + : cluster(c), self(id), catchUp(false), output(*this, out), connectionCtor(&output, cluster.getBroker(), mgmtId, external, false, 0, true), expectProtocolHeader(false), mcastFrameHandler(cluster.getMulticast(), self), @@ -93,15 +90,13 @@ Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out, Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out, const std::string& mgmtId, MemberId member, bool isCatchUp, bool isLink, const qpid::sys::SecuritySettings& external -) : cluster(c), self(member, ++idCounter), catchUp(isCatchUp), announced(false), output(*this, out), +) : cluster(c), self(member, ++idCounter), catchUp(isCatchUp), output(*this, out), connectionCtor(&output, cluster.getBroker(), mgmtId, external, isLink, isCatchUp ? ++catchUpId : 0, - // The first catch-up connection is not considered a shadow - // as it needs to be authenticated. - isCatchUp && self.second > 1), + isCatchUp), // isCatchUp => shadow expectProtocolHeader(isLink), mcastFrameHandler(cluster.getMulticast(), self), updateIn(c.getUpdateReceiver()), @@ -118,7 +113,7 @@ Connection::Connection(Cluster& c, sys::ConnectionOutputHandler& out, if (!updateIn.nextShadowMgmtId.empty()) connectionCtor.mgmtId = updateIn.nextShadowMgmtId; updateIn.nextShadowMgmtId.clear(); - } + } init(); QPID_LOG(debug, cluster << " local connection " << *this); } @@ -148,7 +143,7 @@ void Connection::init() { // Called when we have consumed a read buffer to give credit to the // connection layer to continue reading. void Connection::giveReadCredit(int credit) { - if (cluster.getSettings().readMax && credit) + if (cluster.getSettings().readMax && credit) output.giveReadCredit(credit); } @@ -171,7 +166,7 @@ void Connection::announce( AMQFrame frame; while (frame.decode(buf)) connection->received(frame); - connection->setUserId(username); + connection->setUserId(username); } // Do managment actions now that the connection is replicated. connection->raiseConnectEvent(); @@ -198,7 +193,7 @@ void Connection::received(framing::AMQFrame& f) { << *this << ": " << f); return; } - QPID_LOG_IF(trace, Cluster::loggable(f), cluster << " RECV " << *this << ": " << f); + QPID_LOG(trace, cluster << " RECV " << *this << ": " << f); if (isLocal()) { // Local catch-up connection. currentChannel = f.getChannel(); if (!framing::invoke(*this, *f.getBody()).wasHandled()) @@ -206,7 +201,7 @@ void Connection::received(framing::AMQFrame& f) { } else { // Shadow or updated catch-up connection. if (f.getMethod() && f.getMethod()->isA<ConnectionCloseBody>()) { - if (isShadow()) + if (isShadow()) cluster.addShadowConnection(this); AMQFrame ok((ConnectionCloseOkBody())); connection->getOutput().send(ok); @@ -218,9 +213,16 @@ void Connection::received(framing::AMQFrame& f) { } } -bool Connection::checkUnsupported(const AMQBody&) { - // Throw an exception for unsupported commands. Currently all are supported. - return false; +bool Connection::checkUnsupported(const AMQBody& body) { + std::string message; + if (body.getMethod()) { + switch (body.getMethod()->amqpClassId()) { + case DTX_CLASS_ID: message = "DTX transactions are not currently supported by cluster."; break; + } + } + if (!message.empty()) + connection->close(connection::CLOSE_CODE_FRAMING_ERROR, message); + return !message.empty(); } struct GiveReadCreditOnExit { @@ -239,7 +241,7 @@ void Connection::deliverDoOutput(uint32_t limit) { void Connection::deliveredFrame(const EventFrame& f) { GiveReadCreditOnExit gc(*this, f.readCredit); assert(!catchUp); - currentChannel = f.frame.getChannel(); + currentChannel = f.frame.getChannel(); if (f.frame.getBody() // frame can be emtpy with just readCredit && !framing::invoke(*this, *f.frame.getBody()).wasHandled() // Connection contol. && !checkUnsupported(*f.frame.getBody())) // Unsupported operation. @@ -253,7 +255,7 @@ void Connection::deliveredFrame(const EventFrame& f) { } } -// A local connection is closed by the network layer. Called in the connection thread. +// A local connection is closed by the network layer. void Connection::closed() { try { if (isUpdated()) { @@ -270,9 +272,8 @@ void Connection::closed() { // closed and process any outstanding frames from the cluster // until self-delivery of deliver-close. output.closeOutput(); - if (announced) - cluster.getMulticast().mcastControl( - ClusterConnectionDeliverCloseBody(), self); + cluster.getMulticast().mcastControl( + ClusterConnectionDeliverCloseBody(), self); } } catch (const std::exception& e) { @@ -286,7 +287,7 @@ void Connection::deliverClose () { cluster.erase(self); } -// Close the connection +// Close the connection void Connection::close() { if (connection.get()) { QPID_LOG(debug, cluster << " closed connection " << *this); @@ -319,10 +320,10 @@ size_t Connection::decode(const char* data, size_t size) { while (localDecoder.decode(buf)) received(localDecoder.getFrame()); if (!wasOpen && connection->isOpen()) { - // Connections marked with setUserProxyAuth are allowed to proxy + // Connections marked as federation links are allowed to proxy // messages with user-ID that doesn't match the connection's // authenticated ID. This is important for updates. - connection->setUserProxyAuth(isCatchUp()); + connection->setFederationLink(isCatchUp()); } } else { // Multicast local connections. @@ -331,9 +332,9 @@ size_t Connection::decode(const char* data, size_t size) { if (!checkProtocolHeader(ptr, size)) // Updates ptr return 0; // Incomplete header - if (!connection->isOpen()) + if (!connection->isOpen()) processInitialFrames(ptr, end-ptr); // Updates ptr - + if (connection->isOpen() && end - ptr > 0) { // We're multi-casting, we will give read credit on delivery. grc.credit = 0; @@ -383,7 +384,6 @@ void Connection::processInitialFrames(const char*& ptr, size_t size) { connection->getUserId(), initialFrames), getId()); - announced = true; initialFrames.clear(); } } @@ -406,11 +406,11 @@ void Connection::shadowSetUser(const std::string& userId) { void Connection::consumerState(const string& name, bool blocked, bool notifyEnabled, const SequenceNumber& position) { - broker::SemanticState::ConsumerImpl::shared_ptr c = semanticState().find(name); - c->position = position; - c->setBlocked(blocked); - if (notifyEnabled) c->enableNotify(); else c->disableNotify(); - updateIn.consumerNumbering.add(c); + broker::SemanticState::ConsumerImpl& c = semanticState().find(name); + c.position = position; + c.setBlocked(blocked); + if (notifyEnabled) c.enableNotify(); else c.disableNotify(); + updateIn.consumerNumbering.add(c.shared_from_this()); } @@ -421,8 +421,7 @@ void Connection::sessionState( const SequenceNumber& expected, const SequenceNumber& received, const SequenceSet& unknownCompleted, - const SequenceSet& receivedIncomplete, - bool dtxSelected) + const SequenceSet& receivedIncomplete) { sessionState().setState( replayStart, @@ -432,10 +431,8 @@ void Connection::sessionState( received, unknownCompleted, receivedIncomplete); - if (dtxSelected) semanticState().selectDtx(); - QPID_LOG(debug, cluster << " received session state update for " - << sessionState().getId()); - // The output tasks will be added later in the update process. + QPID_LOG(debug, cluster << " received session state update for " << sessionState().getId()); + // The output tasks will be added later in the update process. connection->getOutputTasks().removeAll(); } @@ -444,7 +441,7 @@ void Connection::outputTask(uint16_t channel, const std::string& name) { if (!session) throw Exception(QPID_MSG(cluster << " channel not attached " << *this << "[" << channel << "] ")); - OutputTask* task = session->getSemanticState().find(name).get(); + OutputTask* task = &session->getSemanticState().find(name); connection->getOutputTasks().addOutputTask(task); } @@ -464,24 +461,11 @@ void Connection::shadowReady( output.setSendMax(sendMax); } -void Connection::setDtxBuffer(const UpdateReceiver::DtxBufferRef& bufRef) { - broker::DtxManager& mgr = cluster.getBroker().getDtxManager(); - broker::DtxWorkRecord* record = mgr.getWork(bufRef.xid); - broker::DtxBuffer::shared_ptr buffer = (*record)[bufRef.index]; - if (bufRef.suspended) - bufRef.semanticState->getSuspendedXids()[bufRef.xid] = buffer; - else - bufRef.semanticState->setDtxBuffer(buffer); -} - -// Marks the end of the update. void Connection::membership(const FieldTable& joiners, const FieldTable& members, const framing::SequenceNumber& frameSeq) { QPID_LOG(debug, cluster << " incoming update complete on connection " << *this); updateIn.consumerNumbering.clear(); - for_each(updateIn.dtxBuffers.begin(), updateIn.dtxBuffers.end(), - boost::bind(&Connection::setDtxBuffer, this, _1)); closeUpdated(); cluster.updateInDone(ClusterMap(joiners, members, frameSeq)); } @@ -494,7 +478,7 @@ void Connection::retractOffer() { void Connection::closeUpdated() { self.second = 0; // Mark this as completed update connection. - if (connection.get()) + if (connection.get()) connection->close(connection::CLOSE_CODE_NORMAL, "OK"); } @@ -545,20 +529,12 @@ void Connection::deliveryRecord(const string& qname, m = getUpdateMessage(); m.queue = queue.get(); m.position = position; - if (enqueued) queue->updateEnqueued(m); //inform queue of the message + if (enqueued) queue->updateEnqueued(m); //inform queue of the message } else { // Message at original position in original queue - queue->find(position, m); + m = queue->find(position); } - // FIXME aconway 2011-08-19: removed: - // if (!m.payload) - // throw Exception(QPID_MSG("deliveryRecord no update message")); - // - // It seems this could happen legitimately in the case one - // session browses message M, then another session acquires - // it. In that case the browsers delivery record is !acquired - // but the message is not on its original Queue. In that case - // we'll get a deliveryRecord with no payload for the browser. - // + if (!m.payload) + throw Exception(QPID_MSG("deliveryRecord no update message")); } broker::DeliveryRecord dr(m, queue, tag, acquired, accepted, windowing, credit); @@ -566,11 +542,7 @@ void Connection::deliveryRecord(const string& qname, if (cancelled) dr.cancel(dr.getTag()); if (completed) dr.complete(); if (ended) dr.setEnded(); // Exsitance of message - - if (dtxBuffer) // Record for next dtx-ack - dtxAckRecords.push_back(dr); - else - semanticState().record(dr); // Record on session's unacked list. + semanticState().record(dr); // Part of the session's unacked list. } void Connection::queuePosition(const string& qname, const SequenceNumber& position) { @@ -584,46 +556,8 @@ void Connection::queueFairshareState(const std::string& qname, const uint8_t pri } } - -namespace { -// find a StatefulQueueObserver that matches a given identifier -class ObserverFinder { - const std::string id; - boost::shared_ptr<broker::QueueObserver> target; - ObserverFinder(const ObserverFinder&) {} - public: - ObserverFinder(const std::string& _id) : id(_id) {} - broker::StatefulQueueObserver *getObserver() - { - if (target) - return dynamic_cast<broker::StatefulQueueObserver *>(target.get()); - return 0; - } - void operator() (boost::shared_ptr<broker::QueueObserver> o) - { - if (!target) { - broker::StatefulQueueObserver *p = dynamic_cast<broker::StatefulQueueObserver *>(o.get()); - if (p && p->getId() == id) { - target = o; - } - } - } -}; -} - - -void Connection::queueObserverState(const std::string& qname, const std::string& observerId, const FieldTable& state) -{ - boost::shared_ptr<broker::Queue> queue(findQueue(qname)); - ObserverFinder finder(observerId); // find this observer - queue->eachObserver<ObserverFinder &>(finder); - broker::StatefulQueueObserver *so = finder.getObserver(); - if (so) { - so->setState( state ); - QPID_LOG(debug, "updated queue observer " << observerId << "'s state on queue " << qname << "; ..."); - return; - } - QPID_LOG(error, "Failed to find observer " << observerId << " state on queue " << qname << "; this will result in inconsistencies."); +void Connection::expiryId(uint64_t id) { + cluster.getExpiryPolicy().setId(id); } std::ostream& operator<<(std::ostream& o, const Connection& c) { @@ -640,7 +574,6 @@ std::ostream& operator<<(std::ostream& o, const Connection& c) { void Connection::txStart() { txBuffer.reset(new broker::TxBuffer()); } - void Connection::txAccept(const framing::SequenceSet& acked) { txBuffer->enlist(boost::shared_ptr<broker::TxAccept>( new broker::TxAccept(acked, semanticState().getUnacked()))); @@ -656,11 +589,9 @@ void Connection::txEnqueue(const std::string& queue) { new broker::RecoveredEnqueue(findQueue(queue), getUpdateMessage().payload))); } -void Connection::txPublish(const framing::Array& queues, bool delivered) -{ - boost::shared_ptr<broker::TxPublish> txPub( - new broker::TxPublish(getUpdateMessage().payload)); - for (framing::Array::const_iterator i = queues.begin(); i != queues.end(); ++i) +void Connection::txPublish(const framing::Array& queues, bool delivered) { + boost::shared_ptr<broker::TxPublish> txPub(new broker::TxPublish(getUpdateMessage().payload)); + for (framing::Array::const_iterator i = queues.begin(); i != queues.end(); ++i) txPub->deliverTo(findQueue((*i)->get<std::string>())); txPub->delivered = delivered; txBuffer->enlist(txPub); @@ -674,51 +605,6 @@ void Connection::accumulatedAck(const qpid::framing::SequenceSet& s) { semanticState().setAccumulatedAck(s); } -void Connection::dtxStart(const std::string& xid, - bool ended, - bool suspended, - bool failed, - bool expired) -{ - dtxBuffer.reset(new broker::DtxBuffer(xid, ended, suspended, failed, expired)); - txBuffer = dtxBuffer; -} - -void Connection::dtxEnd() { - broker::DtxManager& mgr = cluster.getBroker().getDtxManager(); - std::string xid = dtxBuffer->getXid(); - if (mgr.exists(xid)) - mgr.join(xid, dtxBuffer); - else - mgr.start(xid, dtxBuffer); - dtxBuffer.reset(); - txBuffer.reset(); -} - -// Sent after all DeliveryRecords for a dtx-ack have been collected in dtxAckRecords -void Connection::dtxAck() { - dtxBuffer->enlist( - boost::shared_ptr<broker::DtxAck>(new broker::DtxAck(dtxAckRecords))); - dtxAckRecords.clear(); -} - -void Connection::dtxBufferRef(const std::string& xid, uint32_t index, bool suspended) { - // Save the association between DtxBuffers and the session so we - // can set the DtxBuffers at the end of the update when the - // DtxManager has been replicated. - updateIn.dtxBuffers.push_back( - UpdateReceiver::DtxBufferRef(xid, index, suspended, &semanticState())); -} - -// Sent at end of work record. -void Connection::dtxWorkRecord(const std::string& xid, bool prepared, uint32_t timeout) -{ - broker::DtxManager& mgr = cluster.getBroker().getDtxManager(); - if (timeout) mgr.setTimeout(xid, timeout); - if (prepared) mgr.prepare(xid); -} - - void Connection::exchange(const std::string& encoded) { Buffer buf(const_cast<char*>(encoded.data()), encoded.size()); broker::Exchange::shared_ptr ex = broker::Exchange::decode(cluster.getBroker().getExchanges(), buf); @@ -728,6 +614,12 @@ void Connection::exchange(const std::string& encoded) { QPID_LOG(debug, cluster << " updated exchange " << ex->getName()); } +void Connection::queue(const std::string& encoded) { + Buffer buf(const_cast<char*>(encoded.data()), encoded.size()); + broker::Queue::shared_ptr q = broker::Queue::decode(cluster.getBroker().getQueues(), buf); + QPID_LOG(debug, cluster << " updated queue " << q->getName()); +} + void Connection::sessionError(uint16_t , const std::string& msg) { // Ignore errors before isOpen(), we're not multicasting yet. if (connection->isOpen()) @@ -786,23 +678,6 @@ void Connection::config(const std::string& encoded) { else throw Exception(QPID_MSG("Update failed, invalid kind of config: " << kind)); } -void Connection::doCatchupIoCallbacks() { - // We need to process IO callbacks during the catch-up phase in - // order to service asynchronous completions for messages - // transferred during catch-up. - - if (catchUp) getBrokerConnection()->doIoCallbacks(); -} - -void Connection::clock(uint64_t time) { - QPID_LOG(debug, "Cluster connection received time update"); - cluster.clock(time); -} - -void Connection::queueDequeueSincePurgeState(const std::string& qname, uint32_t dequeueSincePurge) { - boost::shared_ptr<broker::Queue> queue(findQueue(qname)); - queue->setDequeueSincePurge(dequeueSincePurge); -} }} // Namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/Connection.h b/cpp/src/qpid/cluster/Connection.h index fe66b77238..7ee85bf1aa 100644 --- a/cpp/src/qpid/cluster/Connection.h +++ b/cpp/src/qpid/cluster/Connection.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,12 +24,11 @@ #include "types.h" #include "OutputInterceptor.h" +#include "EventFrame.h" #include "McastFrameHandler.h" #include "UpdateReceiver.h" -#include "qpid/RefCounted.h" #include "qpid/broker/Connection.h" -#include "qpid/broker/DeliveryRecord.h" #include "qpid/broker/SecureConnection.h" #include "qpid/broker/SemanticState.h" #include "qpid/amqp_0_10/Connection.h" @@ -48,7 +47,7 @@ namespace framing { class AMQFrame; } namespace broker { class SemanticState; -struct QueuedMessage; +class QueuedMessage; class TxBuffer; class TxAccept; } @@ -56,7 +55,6 @@ class TxAccept; namespace cluster { class Cluster; class Event; -struct EventFrame; /** Intercept broker::Connection calls for shadow and local cluster connections. */ class Connection : @@ -64,7 +62,7 @@ class Connection : public sys::ConnectionInputHandler, public framing::AMQP_AllOperations::ClusterConnectionHandler, private broker::Connection::ErrorListener - + { public: @@ -75,7 +73,7 @@ class Connection : Connection(Cluster&, sys::ConnectionOutputHandler& out, const std::string& mgmtId, const ConnectionId& id, const qpid::sys::SecuritySettings& external); ~Connection(); - + ConnectionId getId() const { return self; } broker::Connection* getBrokerConnection() { return connection.get(); } const broker::Connection* getBrokerConnection() const { return connection.get(); } @@ -110,9 +108,9 @@ class Connection : void deliveredFrame(const EventFrame&); void consumerState(const std::string& name, bool blocked, bool notifyEnabled, const qpid::framing::SequenceNumber& position); - + // ==== Used in catch-up mode to build initial state. - // + // // State update methods. void shadowPrepare(const std::string&); @@ -124,11 +122,10 @@ class Connection : const framing::SequenceNumber& expected, const framing::SequenceNumber& received, const framing::SequenceSet& unknownCompleted, - const SequenceSet& receivedIncomplete, - bool dtxSelected); - + const SequenceSet& receivedIncomplete); + void outputTask(uint16_t channel, const std::string& name); - + void shadowReady(uint64_t memberId, uint64_t connectionId, const std::string& managementId, @@ -156,7 +153,7 @@ class Connection : void queuePosition(const std::string&, const framing::SequenceNumber&); void queueFairshareState(const std::string&, const uint8_t priority, const uint8_t count); - void queueObserverState(const std::string&, const std::string&, const framing::FieldTable&); + void expiryId(uint64_t); void txStart(); void txAccept(const framing::SequenceSet&); @@ -166,18 +163,8 @@ class Connection : void txEnd(); void accumulatedAck(const framing::SequenceSet&); - // Dtx state - void dtxStart(const std::string& xid, - bool ended, - bool suspended, - bool failed, - bool expired); - void dtxEnd(); - void dtxAck(); - void dtxBufferRef(const std::string& xid, uint32_t index, bool suspended); - void dtxWorkRecord(const std::string& xid, bool prepared, uint32_t timeout); - - // Encoded exchange replication. + // Encoded queue/exchange replication. + void queue(const std::string& encoded); void exchange(const std::string& encoded); void giveReadCredit(int credit); @@ -202,12 +189,6 @@ class Connection : void setSecureConnection ( broker::SecureConnection * sc ); - void doCatchupIoCallbacks(); - - void clock(uint64_t time); - - void queueDequeueSincePurgeState(const std::string&, uint32_t); - private: struct NullFrameHandler : public framing::FrameHandler { void handle(framing::AMQFrame&) {} @@ -252,7 +233,7 @@ class Connection : // Error listener functions void connectionError(const std::string&); void sessionError(uint16_t channel, const std::string&); - + void init(); bool checkUnsupported(const framing::AMQBody& body); void deliverDoOutput(uint32_t limit); @@ -264,11 +245,10 @@ class Connection : broker::SemanticState& semanticState(); broker::QueuedMessage getUpdateMessage(); void closeUpdated(); - void setDtxBuffer(const UpdateReceiver::DtxBuffers::value_type &); + Cluster& cluster; ConnectionId self; bool catchUp; - bool announced; OutputInterceptor output; framing::FrameDecoder localDecoder; ConnectionCtor connectionCtor; @@ -276,9 +256,6 @@ class Connection : framing::SequenceNumber deliverSeq; framing::ChannelId currentChannel; boost::shared_ptr<broker::TxBuffer> txBuffer; - boost::shared_ptr<broker::DtxBuffer> dtxBuffer; - broker::DeliveryRecords dtxAckRecords; - broker::DtxWorkRecord* dtxCurrent; bool expectProtocolHeader; McastFrameHandler mcastFrameHandler; UpdateReceiver& updateIn; diff --git a/cpp/src/qpid/cluster/Decoder.h b/cpp/src/qpid/cluster/Decoder.h index 3b5ada4a81..2e2af2868f 100644 --- a/cpp/src/qpid/cluster/Decoder.h +++ b/cpp/src/qpid/cluster/Decoder.h @@ -31,7 +31,7 @@ namespace qpid { namespace cluster { -struct EventFrame; +class EventFrame; class EventHeader; /** diff --git a/cpp/src/qpid/cluster/ErrorCheck.h b/cpp/src/qpid/cluster/ErrorCheck.h index a417b2ec25..de8cedafb3 100644 --- a/cpp/src/qpid/cluster/ErrorCheck.h +++ b/cpp/src/qpid/cluster/ErrorCheck.h @@ -33,7 +33,7 @@ namespace qpid { namespace cluster { -struct EventFrame; +class EventFrame; class Cluster; class Multicaster; class Connection; diff --git a/cpp/src/qpid/cluster/Event.cpp b/cpp/src/qpid/cluster/Event.cpp index da2bc89d8c..cd775ce2f1 100644 --- a/cpp/src/qpid/cluster/Event.cpp +++ b/cpp/src/qpid/cluster/Event.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,7 +23,6 @@ #include "qpid/cluster/Cpg.h" #include "qpid/framing/Buffer.h" #include "qpid/framing/AMQFrame.h" -#include "qpid/RefCountedBuffer.h" #include "qpid/assert.h" #include <ostream> #include <iterator> diff --git a/cpp/src/qpid/cluster/Event.h b/cpp/src/qpid/cluster/Event.h index 13283edff7..07f74d3ba5 100644 --- a/cpp/src/qpid/cluster/Event.h +++ b/cpp/src/qpid/cluster/Event.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,7 +23,7 @@ */ #include "qpid/cluster/types.h" -#include "qpid/BufferRef.h" +#include "qpid/RefCountedBuffer.h" #include "qpid/framing/AMQFrame.h" #include <sys/uio.h> // For iovec #include <iosfwd> @@ -53,7 +53,7 @@ class EventHeader { /** Size of payload data, excluding header. */ size_t getSize() const { return size; } - /** Size of header + payload. */ + /** Size of header + payload. */ size_t getStoreSize() const { return size + HEADER_SIZE; } bool isCluster() const { return connectionId.getNumber() == 0; } @@ -62,7 +62,7 @@ class EventHeader { protected: static const size_t HEADER_SIZE; - + EventType type; ConnectionId connectionId; size_t size; @@ -86,25 +86,25 @@ class Event : public EventHeader { /** Create a control event. */ static Event control(const framing::AMQFrame&, const ConnectionId&); - + // Data excluding header. - char* getData() { return store.begin() + HEADER_SIZE; } - const char* getData() const { return store.begin() + HEADER_SIZE; } + char* getData() { return store + HEADER_SIZE; } + const char* getData() const { return store + HEADER_SIZE; } // Store including header - char* getStore() { return store.begin(); } - const char* getStore() const { return store.begin(); } - - const framing::AMQFrame& getFrame() const; + char* getStore() { return store; } + const char* getStore() const { return store; } + const framing::AMQFrame& getFrame() const; + operator framing::Buffer() const; iovec toIovec() const; - + private: void encodeHeader() const; - BufferRef store; + RefCountedBuffer::pointer store; mutable framing::AMQFrame frame; }; diff --git a/cpp/src/qpid/cluster/EventFrame.h b/cpp/src/qpid/cluster/EventFrame.h index 6b702a9bf8..61447c5525 100644 --- a/cpp/src/qpid/cluster/EventFrame.h +++ b/cpp/src/qpid/cluster/EventFrame.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -48,7 +48,7 @@ struct EventFrame ConnectionId connectionId; - framing::AMQFrame frame; + framing::AMQFrame frame; int readCredit; ///< last frame in an event, give credit when processed. EventType type; }; diff --git a/cpp/src/qpid/cluster/ExpiryPolicy.cpp b/cpp/src/qpid/cluster/ExpiryPolicy.cpp index 0ef5c2a35d..d9a7b0122a 100644 --- a/cpp/src/qpid/cluster/ExpiryPolicy.cpp +++ b/cpp/src/qpid/cluster/ExpiryPolicy.cpp @@ -21,21 +21,106 @@ #include "qpid/broker/Message.h" #include "qpid/cluster/ExpiryPolicy.h" -#include "qpid/cluster/Cluster.h" +#include "qpid/cluster/Multicaster.h" +#include "qpid/framing/ClusterMessageExpiredBody.h" #include "qpid/sys/Time.h" +#include "qpid/sys/Timer.h" #include "qpid/log/Statement.h" namespace qpid { namespace cluster { -ExpiryPolicy::ExpiryPolicy(Cluster& cluster) : cluster(cluster) {} +ExpiryPolicy::ExpiryPolicy(Multicaster& m, const MemberId& id, sys::Timer& t) + : expiryId(1), expiredPolicy(new Expired), mcast(m), memberId(id), timer(t) {} +struct ExpiryTask : public sys::TimerTask { + ExpiryTask(const boost::intrusive_ptr<ExpiryPolicy>& policy, uint64_t id, sys::AbsTime when) + : TimerTask(when,"ExpiryPolicy"), expiryPolicy(policy), expiryId(id) {} + void fire() { expiryPolicy->sendExpire(expiryId); } + boost::intrusive_ptr<ExpiryPolicy> expiryPolicy; + const uint64_t expiryId; +}; + +// Called while receiving an update +void ExpiryPolicy::setId(uint64_t id) { + sys::Mutex::ScopedLock l(lock); + expiryId = id; +} + +// Called while giving an update +uint64_t ExpiryPolicy::getId() const { + sys::Mutex::ScopedLock l(lock); + return expiryId; +} + +// Called in enqueuing connection thread +void ExpiryPolicy::willExpire(broker::Message& m) { + uint64_t id; + { + // When messages are fanned out to multiple queues, update sends + // them as independenty messages so we can have multiple messages + // with the same expiry ID. + // + sys::Mutex::ScopedLock l(lock); + id = expiryId++; + if (!id) { // This is an update of an already-expired message. + m.setExpiryPolicy(expiredPolicy); + } + else { + assert(unexpiredByMessage.find(&m) == unexpiredByMessage.end()); + // If this is an update, the id may already exist + unexpiredById.insert(IdMessageMap::value_type(id, &m)); + unexpiredByMessage[&m] = id; + } + } + timer.add(new ExpiryTask(this, id, m.getExpiration())); +} + +// Called in dequeueing connection thread +void ExpiryPolicy::forget(broker::Message& m) { + sys::Mutex::ScopedLock l(lock); + MessageIdMap::iterator i = unexpiredByMessage.find(&m); + assert(i != unexpiredByMessage.end()); + unexpiredById.erase(i->second); + unexpiredByMessage.erase(i); +} + +// Called in dequeueing connection or cleanup thread. bool ExpiryPolicy::hasExpired(broker::Message& m) { - return m.getExpiration() < cluster.getClusterTime(); + sys::Mutex::ScopedLock l(lock); + return unexpiredByMessage.find(&m) == unexpiredByMessage.end(); +} + +// Called in timer thread +void ExpiryPolicy::sendExpire(uint64_t id) { + { + sys::Mutex::ScopedLock l(lock); + // Don't multicast an expiry notice if message is already forgotten. + if (unexpiredById.find(id) == unexpiredById.end()) return; + } + mcast.mcastControl(framing::ClusterMessageExpiredBody(framing::ProtocolVersion(), id), memberId); } -sys::AbsTime ExpiryPolicy::getCurrentTime() { - return cluster.getClusterTime(); +// Called in CPG deliver thread. +void ExpiryPolicy::deliverExpire(uint64_t id) { + sys::Mutex::ScopedLock l(lock); + std::pair<IdMessageMap::iterator, IdMessageMap::iterator> expired = unexpiredById.equal_range(id); + IdMessageMap::iterator i = expired.first; + while (i != expired.second) { + i->second->setExpiryPolicy(expiredPolicy); // hasExpired() == true; + unexpiredByMessage.erase(i->second); + unexpiredById.erase(i++); + } } +// Called in update thread on the updater. +boost::optional<uint64_t> ExpiryPolicy::getId(broker::Message& m) { + sys::Mutex::ScopedLock l(lock); + MessageIdMap::iterator i = unexpiredByMessage.find(&m); + return i == unexpiredByMessage.end() ? boost::optional<uint64_t>() : i->second; +} + +bool ExpiryPolicy::Expired::hasExpired(broker::Message&) { return true; } +void ExpiryPolicy::Expired::willExpire(broker::Message&) { } + }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/ExpiryPolicy.h b/cpp/src/qpid/cluster/ExpiryPolicy.h index d8ddbca8b3..77a656aa68 100644 --- a/cpp/src/qpid/cluster/ExpiryPolicy.h +++ b/cpp/src/qpid/cluster/ExpiryPolicy.h @@ -36,8 +36,12 @@ namespace broker { class Message; } +namespace sys { +class Timer; +} + namespace cluster { -class Cluster; +class Multicaster; /** * Cluster expiry policy @@ -45,13 +49,43 @@ class Cluster; class ExpiryPolicy : public broker::ExpiryPolicy { public: - ExpiryPolicy(Cluster& cluster); + ExpiryPolicy(Multicaster&, const MemberId&, sys::Timer&); + void willExpire(broker::Message&); bool hasExpired(broker::Message&); - qpid::sys::AbsTime getCurrentTime(); + void forget(broker::Message&); + + // Send expiration notice to cluster. + void sendExpire(uint64_t); + // Cluster delivers expiry notice. + void deliverExpire(uint64_t); + + void setId(uint64_t id); + uint64_t getId() const; + + boost::optional<uint64_t> getId(broker::Message&); + private: - Cluster& cluster; + typedef std::map<broker::Message*, uint64_t> MessageIdMap; + // When messages are fanned out to multiple queues, update sends + // them as independenty messages so we can have multiple messages + // with the same expiry ID. + typedef std::multimap<uint64_t, broker::Message*> IdMessageMap; + + struct Expired : public broker::ExpiryPolicy { + bool hasExpired(broker::Message&); + void willExpire(broker::Message&); + }; + + mutable sys::Mutex lock; + MessageIdMap unexpiredByMessage; + IdMessageMap unexpiredById; + uint64_t expiryId; + boost::intrusive_ptr<Expired> expiredPolicy; + Multicaster& mcast; + MemberId memberId; + sys::Timer& timer; }; }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/FailoverExchange.cpp b/cpp/src/qpid/cluster/FailoverExchange.cpp index cfbe34a460..84232dac1b 100644 --- a/cpp/src/qpid/cluster/FailoverExchange.cpp +++ b/cpp/src/qpid/cluster/FailoverExchange.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -39,10 +39,8 @@ using namespace broker; using namespace framing; const string FailoverExchange::typeName("amq.failover"); - -FailoverExchange::FailoverExchange(management::Manageable* parent, Broker* b) - : Exchange(typeName, parent, b ), ready(false) -{ + +FailoverExchange::FailoverExchange(management::Manageable* parent, Broker* b) : Exchange(typeName, parent, b ) { if (mgmtExchange != 0) mgmtExchange->set_type(typeName); } @@ -55,17 +53,16 @@ void FailoverExchange::setUrls(const vector<Url>& u) { void FailoverExchange::updateUrls(const vector<Url>& u) { Lock l(lock); urls=u; - if (ready && !urls.empty()) { - std::for_each(queues.begin(), queues.end(), - boost::bind(&FailoverExchange::sendUpdate, this, _1)); - } + if (urls.empty()) return; + std::for_each(queues.begin(), queues.end(), + boost::bind(&FailoverExchange::sendUpdate, this, _1)); } string FailoverExchange::getType() const { return typeName; } bool FailoverExchange::bind(Queue::shared_ptr queue, const string&, const framing::FieldTable*) { Lock l(lock); - if (ready) sendUpdate(queue); + sendUpdate(queue); return queues.insert(queue).second; } @@ -87,7 +84,7 @@ void FailoverExchange::sendUpdate(const Queue::shared_ptr& queue) { // Called with lock held. if (urls.empty()) return; framing::Array array(0x95); - for (Urls::const_iterator i = urls.begin(); i != urls.end(); ++i) + for (Urls::const_iterator i = urls.begin(); i != urls.end(); ++i) array.add(boost::shared_ptr<Str16Value>(new Str16Value(i->str()))); const ProtocolVersion v; boost::intrusive_ptr<Message> msg(new Message); @@ -99,12 +96,9 @@ void FailoverExchange::sendUpdate(const Queue::shared_ptr& queue) { header.get<MessageProperties>(true)->getApplicationHeaders().setArray(typeName, array); AMQFrame headerFrame(header); headerFrame.setFirstSegment(false); - msg->getFrames().append(headerFrame); + msg->getFrames().append(headerFrame); DeliverableMessage(msg).deliverTo(queue); } -void FailoverExchange::setReady() { - ready = true; -} }} // namespace cluster diff --git a/cpp/src/qpid/cluster/FailoverExchange.h b/cpp/src/qpid/cluster/FailoverExchange.h index c3e50c6929..2e1edfc0ae 100644 --- a/cpp/src/qpid/cluster/FailoverExchange.h +++ b/cpp/src/qpid/cluster/FailoverExchange.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -46,8 +46,6 @@ class FailoverExchange : public broker::Exchange void setUrls(const std::vector<Url>&); /** Set the URLs and send an update.*/ void updateUrls(const std::vector<Url>&); - /** Flag the failover exchange as ready to generate updates (caught up) */ - void setReady(); // Exchange overrides std::string getType() const; @@ -58,7 +56,7 @@ class FailoverExchange : public broker::Exchange private: void sendUpdate(const boost::shared_ptr<broker::Queue>&); - + typedef sys::Mutex::ScopedLock Lock; typedef std::vector<Url> Urls; typedef std::set<boost::shared_ptr<broker::Queue> > Queues; @@ -66,7 +64,7 @@ class FailoverExchange : public broker::Exchange sys::Mutex lock; Urls urls; Queues queues; - bool ready; + }; }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/Multicaster.cpp b/cpp/src/qpid/cluster/Multicaster.cpp index 217641841c..8916de9628 100644 --- a/cpp/src/qpid/cluster/Multicaster.cpp +++ b/cpp/src/qpid/cluster/Multicaster.cpp @@ -21,7 +21,6 @@ #include "qpid/cluster/Multicaster.h" #include "qpid/cluster/Cpg.h" -#include "qpid/cluster/Cluster.h" #include "qpid/log/Statement.h" #include "qpid/framing/AMQBody.h" #include "qpid/framing/AMQFrame.h" @@ -59,7 +58,7 @@ void Multicaster::mcast(const Event& e) { return; } } - QPID_LOG_IF(trace, e.isControl() && Cluster::loggable(e.getFrame()), "MCAST " << e); + QPID_LOG(trace, "MCAST " << e); if (bypass) { // direct, don't queue iovec iov = e.toIovec(); while (!cpg.mcast(&iov, 1)) diff --git a/cpp/src/qpid/cluster/OutputInterceptor.cpp b/cpp/src/qpid/cluster/OutputInterceptor.cpp index 4bf03eefa2..1354dab17b 100644 --- a/cpp/src/qpid/cluster/OutputInterceptor.cpp +++ b/cpp/src/qpid/cluster/OutputInterceptor.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -45,11 +45,12 @@ void OutputInterceptor::send(framing::AMQFrame& f) { } void OutputInterceptor::activateOutput() { - sys::Mutex::ScopedLock l(lock); - if (parent.isCatchUp()) + if (parent.isCatchUp()) { + sys::Mutex::ScopedLock l(lock); next->activateOutput(); + } else - sendDoOutput(sendMax, l); + sendDoOutput(sendMax); } void OutputInterceptor::abort() { @@ -65,38 +66,29 @@ void OutputInterceptor::giveReadCredit(int32_t credit) { } // Called in write thread when the IO layer has no more data to write. -// We only process IO callbacks in the write thread during catch-up. -// Normally we run doOutput only on delivery of doOutput requests. -bool OutputInterceptor::doOutput() { - parent.doCatchupIoCallbacks(); - return false; -} +// We do nothing in the write thread, we run doOutput only on delivery +// of doOutput requests. +bool OutputInterceptor::doOutput() { return false; } -// Send output up to limit, calculate new limit. +// Send output up to limit, calculate new limit. void OutputInterceptor::deliverDoOutput(uint32_t limit) { - sys::Mutex::ScopedLock l(lock); sentDoOutput = false; sendMax = limit; size_t newLimit = limit; if (parent.isLocal()) { - size_t buffered = next->getBuffered(); + size_t buffered = getBuffered(); if (buffered == 0 && sent == sendMax) // Could have sent more, increase the limit. - newLimit = sendMax*2; + newLimit = sendMax*2; else if (buffered > 0 && sent > 1) // Data left unsent, reduce the limit. newLimit = (sendMax + sent) / 2; } sent = 0; - while (sent < limit) { - { - sys::Mutex::ScopedUnlock u(lock); - if (!parent.getBrokerConnection()->doOutput()) break; - } + while (sent < limit && parent.getBrokerConnection()->doOutput()) ++sent; - } - if (sent == limit) sendDoOutput(newLimit, l); + if (sent == limit) sendDoOutput(newLimit); } -void OutputInterceptor::sendDoOutput(size_t newLimit, const sys::Mutex::ScopedLock&) { +void OutputInterceptor::sendDoOutput(size_t newLimit) { if (parent.isLocal() && !sentDoOutput && !closing) { sentDoOutput = true; parent.getCluster().getMulticast().mcastControl( @@ -105,7 +97,6 @@ void OutputInterceptor::sendDoOutput(size_t newLimit, const sys::Mutex::ScopedLo } } -// Called in connection thread when local connection closes. void OutputInterceptor::closeOutput() { sys::Mutex::ScopedLock l(lock); closing = true; diff --git a/cpp/src/qpid/cluster/OutputInterceptor.h b/cpp/src/qpid/cluster/OutputInterceptor.h index 3abf5273a0..65bd82a4fc 100644 --- a/cpp/src/qpid/cluster/OutputInterceptor.h +++ b/cpp/src/qpid/cluster/OutputInterceptor.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -58,13 +58,13 @@ class OutputInterceptor : public sys::ConnectionOutputHandler { uint32_t getSendMax() const { return sendMax; } void setSendMax(uint32_t sendMax_) { sendMax=sendMax_; } - + cluster::Connection& parent; - + private: typedef sys::Mutex::ScopedLock Locker; - void sendDoOutput(size_t newLimit, const sys::Mutex::ScopedLock&); + void sendDoOutput(size_t newLimit); mutable sys::Mutex lock; bool closing; diff --git a/cpp/src/qpid/cluster/SecureConnectionFactory.cpp b/cpp/src/qpid/cluster/SecureConnectionFactory.cpp index 2672d8360c..6ddef66226 100644 --- a/cpp/src/qpid/cluster/SecureConnectionFactory.cpp +++ b/cpp/src/qpid/cluster/SecureConnectionFactory.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -48,7 +48,7 @@ SecureConnectionFactory::create(ProtocolVersion v, sys::OutputControl& out, cons if (clusterCodec) { SecureConnectionPtr sc(new SecureConnection()); clusterCodec->setSecureConnection(sc.get()); - sc->setCodec(codec); + sc->setCodec(codec); return sc.release(); } return 0; @@ -63,7 +63,7 @@ SecureConnectionFactory::create(sys::OutputControl& out, const std::string& id, if (clusterCodec) { SecureConnectionPtr sc(new SecureConnection()); clusterCodec->setSecureConnection(sc.get()); - sc->setCodec(codec); + sc->setCodec(codec); return sc.release(); } return 0; diff --git a/cpp/src/qpid/cluster/UpdateClient.cpp b/cpp/src/qpid/cluster/UpdateClient.cpp index 2446c12f2b..8f751add9b 100644 --- a/cpp/src/qpid/cluster/UpdateClient.cpp +++ b/cpp/src/qpid/cluster/UpdateClient.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -26,9 +26,9 @@ #include "qpid/cluster/Decoder.h" #include "qpid/cluster/ExpiryPolicy.h" #include "qpid/cluster/UpdateDataExchange.h" -#include "qpid/client/SessionBase_0_10Access.h" -#include "qpid/client/ConnectionAccess.h" -#include "qpid/client/SessionImpl.h" +#include "qpid/client/SessionBase_0_10Access.h" +#include "qpid/client/ConnectionAccess.h" +#include "qpid/client/SessionImpl.h" #include "qpid/client/ConnectionImpl.h" #include "qpid/client/Future.h" #include "qpid/broker/Broker.h" @@ -45,13 +45,10 @@ #include "qpid/broker/SessionState.h" #include "qpid/broker/TxOpVisitor.h" #include "qpid/broker/DtxAck.h" -#include "qpid/broker/DtxBuffer.h" -#include "qpid/broker/DtxWorkRecord.h" #include "qpid/broker/TxAccept.h" #include "qpid/broker/TxPublish.h" #include "qpid/broker/RecoveredDequeue.h" #include "qpid/broker/RecoveredEnqueue.h" -#include "qpid/broker/StatefulQueueObserver.h" #include "qpid/framing/MessageTransferBody.h" #include "qpid/framing/ClusterConnectionMembershipBody.h" #include "qpid/framing/ClusterConnectionShadowReadyBody.h" @@ -67,7 +64,6 @@ #include <boost/bind.hpp> #include <boost/cast.hpp> #include <algorithm> -#include <iterator> #include <sstream> namespace qpid { @@ -86,20 +82,11 @@ using namespace framing; namespace arg=client::arg; using client::SessionBase_0_10Access; -// Reserved exchange/queue name for catch-up, avoid clashes with user queues/exchanges. -const std::string UpdateClient::UPDATE("x-qpid.cluster-update"); -// Name for header used to carry expiration information. -const std::string UpdateClient::X_QPID_EXPIRATION = "x-qpid.expiration"; -// Headers used to flag headers/properties added by the UpdateClient so they can be -// removed on the other side. -const std::string UpdateClient::X_QPID_NO_MESSAGE_PROPS = "x-qpid.no-message-props"; -const std::string UpdateClient::X_QPID_NO_HEADERS = "x-qpid.no-headers"; - std::ostream& operator<<(std::ostream& o, const UpdateClient& c) { return o << "cluster(" << c.updaterId << " UPDATER)"; } -struct ClusterConnectionProxy : public AMQP_AllProxy::ClusterConnection, public framing::FrameHandler +struct ClusterConnectionProxy : public AMQP_AllProxy::ClusterConnection, public framing::FrameHandler { boost::shared_ptr<qpid::client::ConnectionImpl> connection; @@ -133,7 +120,7 @@ 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, ExpiryPolicy& expiry_, + 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, @@ -147,11 +134,13 @@ UpdateClient::UpdateClient(const MemberId& updater, const MemberId& updatee, con UpdateClient::~UpdateClient() {} +// Reserved exchange/queue name for catch-up, avoid clashes with user queues/exchanges. +const std::string UpdateClient::UPDATE("qpid.cluster-update"); + void UpdateClient::run() { try { connection.open(updateeUrl, connectionSettings); session = connection.newSession(UPDATE); - session.sync(); update(); done(); } catch (const std::exception& e) { @@ -165,13 +154,6 @@ void UpdateClient::update() { << " at " << updateeUrl); Broker& b = updaterBroker; - if(b.getExpiryPolicy()) { - QPID_LOG(debug, *this << "Updating updatee with cluster time"); - qpid::sys::AbsTime clusterTime = b.getExpiryPolicy()->getCurrentTime(); - int64_t time = qpid::sys::Duration(qpid::sys::EPOCH, clusterTime); - ClusterConnectionProxy(session).clock(time); - } - updateManagementSetupState(); b.getExchanges().eachExchange(boost::bind(&UpdateClient::updateExchange, this, _1)); @@ -181,20 +163,16 @@ void UpdateClient::update() { // longer on their original queue. session.queueDeclare(arg::queue=UPDATE, arg::autoDelete=true); session.sync(); - std::for_each(connections.begin(), connections.end(), boost::bind(&UpdateClient::updateConnection, this, _1)); - - // some Queue Observers need session state & msgs synced first, so sync observers now - b.getQueues().eachQueue(boost::bind(&UpdateClient::updateQueueObservers, this, _1)); + session.queueDelete(arg::queue=UPDATE); // Update queue listeners: must come after sessions so consumerNumbering is populated b.getQueues().eachQueue(boost::bind(&UpdateClient::updateQueueListeners, this, _1)); + ClusterConnectionProxy(session).expiryId(expiry.getId()); updateLinks(); updateManagementAgent(); - updateDtxManager(); - session.queueDelete(arg::queue=UPDATE); session.close(); @@ -206,7 +184,7 @@ void UpdateClient::update() { // NOTE: connection will be closed from the other end, don't close // it here as that causes a race. - + // TODO aconway 2010-03-15: This sleep avoids the race condition // described in // https://bugzilla.redhat.com/show_bug.cgi?id=568831. // It allows the connection to fully close before destroying the @@ -298,7 +276,7 @@ class MessageUpdater { framing::SequenceNumber lastPos; client::AsyncSession session; ExpiryPolicy& expiry; - + public: MessageUpdater(const string& q, const client::AsyncSession s, ExpiryPolicy& expiry_) : queue(q), haveLastPos(false), session(s), expiry(expiry_) { @@ -315,6 +293,7 @@ class MessageUpdater { } } + void updateQueuedMessage(const broker::QueuedMessage& message) { // Send the queue position if necessary. if (!haveLastPos || message.position - lastPos != 1) { @@ -323,23 +302,10 @@ class MessageUpdater { } lastPos = message.position; - // if the ttl > 0, we need to send the calculated expiration time to the updatee - const DeliveryProperties* dprops = - message.payload->getProperties<DeliveryProperties>(); - if (dprops && dprops->getTtl() > 0) { - bool hadMessageProps = - message.payload->hasProperties<framing::MessageProperties>(); - const framing::MessageProperties* mprops = - message.payload->getProperties<framing::MessageProperties>(); - bool hadApplicationHeaders = mprops->hasApplicationHeaders(); - message.payload->insertCustomProperty(UpdateClient::X_QPID_EXPIRATION, - sys::Duration(sys::EPOCH, message.payload->getExpiration())); - // If message properties or application headers didn't exist - // prior to us adding data, we want to remove them on the other side. - if (!hadMessageProps) - message.payload->insertCustomProperty(UpdateClient::X_QPID_NO_MESSAGE_PROPS, 0); - else if (!hadApplicationHeaders) - message.payload->insertCustomProperty(UpdateClient::X_QPID_NO_HEADERS, 0); + // Send the expiry ID if necessary. + if (message.payload->getProperties<DeliveryProperties>()->getTtl()) { + boost::optional<uint64_t> expiryId = expiry.getId(*message.payload); + ClusterConnectionProxy(session).expiryId(expiryId?*expiryId:0); } // We can't send a broker::Message via the normal client API, @@ -352,7 +318,7 @@ class MessageUpdater { framing::MessageTransferBody transfer( *message.payload->getFrames().as<framing::MessageTransferBody>()); transfer.setDestination(UpdateClient::UPDATE); - + sb.get()->send(transfer, message.payload->getFrames(), !message.payload->isContentReleased()); if (message.payload->isContentReleased()){ @@ -360,10 +326,9 @@ class MessageUpdater { uint16_t maxContentSize = maxFrameSize - AMQFrame::frameOverhead(); bool morecontent = true; for (uint64_t offset = 0; morecontent; offset += maxContentSize) - { + { AMQFrame frame((AMQContentBody())); - morecontent = message.payload->getContentFrame( - *(message.queue), frame, maxContentSize, offset); + morecontent = message.payload->getContentFrame(*(message.queue), frame, maxContentSize, offset); sb.get()->sendRawFrame(frame); } } @@ -392,8 +357,6 @@ void UpdateClient::updateQueue(client::AsyncSession& s, const boost::shared_ptr< if (qpid::broker::Fairshare::getState(q->getMessages(), priority, count)) { ClusterConnectionProxy(s).queueFairshareState(q->getName(), priority, count); } - - ClusterConnectionProxy(s).queueDequeueSincePurgeState(q->getName(), q->getDequeueSincePurge()); } void UpdateClient::updateExclusiveQueue(const boost::shared_ptr<broker::Queue>& q) { @@ -409,11 +372,7 @@ void UpdateClient::updateNonExclusiveQueue(const boost::shared_ptr<broker::Queue } void UpdateClient::updateBinding(client::AsyncSession& s, const std::string& queue, const QueueBinding& binding) { - if (binding.exchange.size()) - s.exchangeBind(queue, binding.exchange, binding.key, binding.args); - //else its the default exchange and there is no need to replicate - //the binding, the creation of the queue will have done so - //automatically + s.exchangeBind(queue, binding.exchange, binding.key, binding.args); } void UpdateClient::updateOutputTask(const sys::OutputTask* task) { @@ -421,8 +380,8 @@ void UpdateClient::updateOutputTask(const sys::OutputTask* task) { boost::polymorphic_downcast<const SemanticState::ConsumerImpl*> (task); SemanticState::ConsumerImpl* ci = const_cast<SemanticState::ConsumerImpl*>(cci); uint16_t channel = ci->getParent().getSession().getChannel(); - ClusterConnectionProxy(shadowConnection).outputTask(channel, ci->getTag()); - QPID_LOG(debug, *this << " updating output task " << ci->getTag() + ClusterConnectionProxy(shadowConnection).outputTask(channel, ci->getName()); + QPID_LOG(debug, *this << " updating output task " << ci->getName() << " channel=" << channel); } @@ -430,7 +389,7 @@ void UpdateClient::updateConnection(const boost::intrusive_ptr<Connection>& upda QPID_LOG(debug, *this << " updating connection " << *updateConnection); assert(updateConnection->getBrokerConnection()); broker::Connection& bc = *updateConnection->getBrokerConnection(); - + // Send the management ID first on the main connection. std::string mgmtId = updateConnection->getBrokerConnection()->getMgmtId(); ClusterConnectionProxy(session).shadowPrepare(mgmtId); @@ -467,7 +426,7 @@ void UpdateClient::updateSession(broker::SessionHandler& sh) { QPID_LOG(debug, *this << " updating session " << ss->getId()); - // Create a client session to update session state. + // Create a client session to update session state. boost::shared_ptr<client::ConnectionImpl> cimpl = client::ConnectionAccess::getImpl(shadowConnection); boost::shared_ptr<client::SessionImpl> simpl = cimpl->newSession(ss->getId().getName(), ss->getTimeout(), sh.getChannel()); simpl->disableAutoDetach(); @@ -486,19 +445,19 @@ void UpdateClient::updateSession(broker::SessionHandler& sh) { QPID_LOG(debug, *this << " updating unacknowledged messages."); broker::DeliveryRecords& drs = ss->getSemanticState().getUnacked(); std::for_each(drs.begin(), drs.end(), - boost::bind(&UpdateClient::updateUnacked, this, _1, shadowSession)); + boost::bind(&UpdateClient::updateUnacked, this, _1)); - updateTransactionState(ss->getSemanticState()); + updateTxState(ss->getSemanticState()); // Tx transaction state. // Adjust command counter for message in progress, will be sent after state update. boost::intrusive_ptr<Message> inProgress = ss->getMessageInProgress(); SequenceNumber received = ss->receiverGetReceived().command; - if (inProgress) + if (inProgress) --received; // Sync the session to ensure all responses from broker have been processed. shadowSession.sync(); - + // Reset command-sequence state. proxy.sessionState( ss->senderGetReplayPoint().command, @@ -507,8 +466,7 @@ void UpdateClient::updateSession(broker::SessionHandler& sh) { std::max(received, ss->receiverGetExpected().command), received, ss->receiverGetUnknownComplete(), - ss->receiverGetIncomplete(), - ss->getSemanticState().getDtxSelected() + ss->receiverGetIncomplete() ); // Send frames for partial message in progress. @@ -521,13 +479,13 @@ void UpdateClient::updateSession(broker::SessionHandler& sh) { void UpdateClient::updateConsumer( const broker::SemanticState::ConsumerImpl::shared_ptr& ci) { - QPID_LOG(debug, *this << " updating consumer " << ci->getTag() << " on " + QPID_LOG(debug, *this << " updating consumer " << ci->getName() << " on " << shadowSession.getId()); using namespace message; shadowSession.messageSubscribe( arg::queue = ci->getQueue()->getName(), - arg::destination = ci->getTag(), + arg::destination = ci->getName(), arg::acceptMode = ci->isAckExpected() ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE, arg::acquireMode = ci->isAcquire() ? ACQUIRE_MODE_PRE_ACQUIRED : ACQUIRE_MODE_NOT_ACQUIRED, arg::exclusive = ci->isExclusive(), @@ -535,32 +493,29 @@ void UpdateClient::updateConsumer( arg::resumeTtl = ci->getResumeTtl(), arg::arguments = ci->getArguments() ); - shadowSession.messageSetFlowMode(ci->getTag(), ci->isWindowing() ? FLOW_MODE_WINDOW : FLOW_MODE_CREDIT); - shadowSession.messageFlow(ci->getTag(), CREDIT_UNIT_MESSAGE, ci->getMsgCredit()); - shadowSession.messageFlow(ci->getTag(), CREDIT_UNIT_BYTE, ci->getByteCredit()); + shadowSession.messageSetFlowMode(ci->getName(), ci->isWindowing() ? FLOW_MODE_WINDOW : FLOW_MODE_CREDIT); + shadowSession.messageFlow(ci->getName(), CREDIT_UNIT_MESSAGE, ci->getMsgCredit()); + shadowSession.messageFlow(ci->getName(), CREDIT_UNIT_BYTE, ci->getByteCredit()); ClusterConnectionProxy(shadowSession).consumerState( - ci->getTag(), + ci->getName(), ci->isBlocked(), ci->isNotifyEnabled(), ci->position ); consumerNumbering.add(ci.get()); - QPID_LOG(debug, *this << " updated consumer " << ci->getTag() + QPID_LOG(debug, *this << " updated consumer " << ci->getName() << " on " << shadowSession.getId()); } - -void UpdateClient::updateUnacked(const broker::DeliveryRecord& dr, - client::AsyncSession& updateSession) -{ - if (!dr.isEnded() && dr.isAcquired()) { - assert(dr.getMessage().payload); + +void UpdateClient::updateUnacked(const broker::DeliveryRecord& dr) { + if (!dr.isEnded() && dr.isAcquired() && dr.getMessage().payload) { // If the message is acquired then it is no longer on the // updatees queue, put it on the update queue for updatee to pick up. // - MessageUpdater(UPDATE, updateSession, expiry).updateQueuedMessage(dr.getMessage()); + MessageUpdater(UPDATE, shadowSession, expiry).updateQueuedMessage(dr.getMessage()); } - ClusterConnectionProxy(updateSession).deliveryRecord( + ClusterConnectionProxy(shadowSession).deliveryRecord( dr.getQueue()->getName(), dr.getMessage().position, dr.getTag(), @@ -581,12 +536,10 @@ class TxOpUpdater : public broker::TxOpConstVisitor, public MessageUpdater { TxOpUpdater(UpdateClient& dc, client::AsyncSession s, ExpiryPolicy& expiry) : MessageUpdater(UpdateClient::UPDATE, s, expiry), parent(dc), session(s), proxy(s) {} - void operator()(const broker::DtxAck& ack) { - std::for_each(ack.getPending().begin(), ack.getPending().end(), - boost::bind(&UpdateClient::updateUnacked, &parent, _1, session)); - proxy.dtxAck(); + void operator()(const broker::DtxAck& ) { + throw InternalErrorException("DTX transactions not currently supported by cluster."); } - + void operator()(const broker::RecoveredDequeue& rdeq) { updateMessage(rdeq.getMessage()); proxy.txEnqueue(rdeq.getQueue()->getName()); @@ -601,18 +554,13 @@ class TxOpUpdater : public broker::TxOpConstVisitor, public MessageUpdater { proxy.txAccept(txAccept.getAcked()); } - typedef std::list<Queue::shared_ptr> QueueList; - - void copy(const QueueList& l, Array& a) { - for (QueueList::const_iterator i = l.begin(); i!=l.end(); ++i) - a.push_back(Array::ValuePtr(new Str8Value((*i)->getName()))); - } - void operator()(const broker::TxPublish& txPub) { updateMessage(txPub.getMessage()); - assert(txPub.getQueues().empty() || txPub.getPrepared().empty()); + typedef std::list<Queue::shared_ptr> QueueList; + const QueueList& qlist = txPub.getQueues(); Array qarray(TYPE_CODE_STR8); - copy(txPub.getQueues().empty() ? txPub.getPrepared() : txPub.getQueues(), qarray); + for (QueueList::const_iterator i = qlist.begin(); i != qlist.end(); ++i) + qarray.push_back(Array::ValuePtr(new Str8Value((*i)->getName()))); proxy.txPublish(qarray, txPub.delivered); } @@ -621,44 +569,18 @@ class TxOpUpdater : public broker::TxOpConstVisitor, public MessageUpdater { client::AsyncSession session; ClusterConnectionProxy proxy; }; - -void UpdateClient::updateBufferRef(const broker::DtxBuffer::shared_ptr& dtx,bool suspended) -{ - ClusterConnectionProxy proxy(shadowSession); - broker::DtxWorkRecord* record = - updaterBroker.getDtxManager().getWork(dtx->getXid()); - proxy.dtxBufferRef(dtx->getXid(), record->indexOf(dtx), suspended); - -} - -void UpdateClient::updateTransactionState(broker::SemanticState& s) { + +void UpdateClient::updateTxState(broker::SemanticState& s) { + QPID_LOG(debug, *this << " updating TX transaction state."); ClusterConnectionProxy proxy(shadowSession); proxy.accumulatedAck(s.getAccumulatedAck()); - broker::TxBuffer::shared_ptr tx = s.getTxBuffer(); - broker::DtxBuffer::shared_ptr dtx = s.getDtxBuffer(); - if (dtx) { - updateBufferRef(dtx, false); // Current transaction. - } else if (tx) { + broker::TxBuffer::shared_ptr txBuffer = s.getTxBuffer(); + if (txBuffer) { proxy.txStart(); TxOpUpdater updater(*this, shadowSession, expiry); - tx->accept(updater); + txBuffer->accept(updater); proxy.txEnd(); } - for (SemanticState::DtxBufferMap::iterator i = s.getSuspendedXids().begin(); - i != s.getSuspendedXids().end(); - ++i) - { - updateBufferRef(i->second, true); - } -} - -void UpdateClient::updateDtxBuffer(const broker::DtxBuffer::shared_ptr& dtx) { - ClusterConnectionProxy proxy(session); - proxy.dtxStart( - dtx->getXid(), dtx->isEnded(), dtx->isSuspended(), dtx->isFailed(), dtx->isExpired()); - TxOpUpdater updater(*this, session, expiry); - dtx->accept(updater); - proxy.dtxEnd(); } void UpdateClient::updateQueueListeners(const boost::shared_ptr<broker::Queue>& queue) { @@ -693,35 +615,4 @@ void UpdateClient::updateBridge(const boost::shared_ptr<broker::Bridge>& bridge) ClusterConnectionProxy(session).config(encode(*bridge)); } -void UpdateClient::updateQueueObservers(const boost::shared_ptr<broker::Queue>& q) -{ - q->eachObserver(boost::bind(&UpdateClient::updateObserver, this, q, _1)); -} - -void UpdateClient::updateObserver(const boost::shared_ptr<broker::Queue>& q, - boost::shared_ptr<broker::QueueObserver> o) -{ - qpid::framing::FieldTable state; - broker::StatefulQueueObserver *so = dynamic_cast<broker::StatefulQueueObserver *>(o.get()); - if (so) { - so->getState( state ); - std::string id(so->getId()); - QPID_LOG(debug, *this << " updating queue " << q->getName() << "'s observer " << id); - ClusterConnectionProxy(session).queueObserverState( q->getName(), id, state ); - } -} - -void UpdateClient::updateDtxManager() { - broker::DtxManager& dtm = updaterBroker.getDtxManager(); - dtm.each(boost::bind(&UpdateClient::updateDtxWorkRecord, this, _1)); -} - -void UpdateClient::updateDtxWorkRecord(const broker::DtxWorkRecord& r) { - QPID_LOG(debug, *this << " updating DTX transaction: " << r.getXid()); - for (size_t i = 0; i < r.size(); ++i) - updateDtxBuffer(r[i]); - ClusterConnectionProxy(session).dtxWorkRecord( - r.getXid(), r.isPrepared(), r.getTimeout()); -} - }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/UpdateClient.h b/cpp/src/qpid/cluster/UpdateClient.h index 481ee357c7..7520bb82cb 100644 --- a/cpp/src/qpid/cluster/UpdateClient.h +++ b/cpp/src/qpid/cluster/UpdateClient.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -34,7 +34,7 @@ namespace qpid { -struct Url; +class Url; namespace broker { @@ -42,8 +42,8 @@ class Broker; class Queue; class Exchange; class QueueBindings; -struct QueueBinding; -struct QueuedMessage; +class QueueBinding; +class QueuedMessage; class SessionHandler; class DeliveryRecord; class SessionState; @@ -51,8 +51,7 @@ class SemanticState; class Decoder; class Link; class Bridge; -class QueueObserver; -class DtxBuffer; + } // namespace broker namespace cluster { @@ -69,26 +68,21 @@ class ExpiryPolicy; class UpdateClient : public sys::Runnable { public: static const std::string UPDATE; // Name for special update queue and exchange. - static const std::string X_QPID_EXPIRATION; // Update message expiration - // Flag to remove props/headers that were added by the UpdateClient - static const std::string X_QPID_NO_MESSAGE_PROPS; - static const std::string X_QPID_NO_HEADERS; - static client::Connection catchUpConnection(); - + UpdateClient(const MemberId& updater, const MemberId& updatee, const Url&, broker::Broker& donor, const ClusterMap& map, ExpiryPolicy& expiry, const std::vector<boost::intrusive_ptr<Connection> >&, Decoder&, const boost::function<void()>& done, const boost::function<void(const std::exception&)>& fail, - const client::ConnectionSettings& + const client::ConnectionSettings& ); ~UpdateClient(); void update(); void run(); // Will delete this when finished. - void updateUnacked(const broker::DeliveryRecord&, client::AsyncSession&); + void updateUnacked(const broker::DeliveryRecord&); private: void updateQueue(client::AsyncSession&, const boost::shared_ptr<broker::Queue>&); @@ -100,8 +94,7 @@ class UpdateClient : public sys::Runnable { void updateBinding(client::AsyncSession&, const std::string& queue, const broker::QueueBinding& binding); void updateConnection(const boost::intrusive_ptr<Connection>& connection); void updateSession(broker::SessionHandler& s); - void updateBufferRef(const broker::DtxBuffer::shared_ptr& dtx, bool suspended); - void updateTransactionState(broker::SemanticState& s); + void updateTxState(broker::SemanticState& s); void updateOutputTask(const sys::OutputTask* task); void updateConsumer(const broker::SemanticState::ConsumerImpl::shared_ptr&); void updateQueueListeners(const boost::shared_ptr<broker::Queue>&); @@ -111,11 +104,6 @@ class UpdateClient : public sys::Runnable { void updateLinks(); void updateLink(const boost::shared_ptr<broker::Link>&); void updateBridge(const boost::shared_ptr<broker::Bridge>&); - void updateQueueObservers(const boost::shared_ptr<broker::Queue>&); - void updateObserver(const boost::shared_ptr<broker::Queue>&, boost::shared_ptr<broker::QueueObserver>); - void updateDtxManager(); - void updateDtxBuffer(const boost::shared_ptr<broker::DtxBuffer>& ); - void updateDtxWorkRecord(const broker::DtxWorkRecord&); Numbering<broker::SemanticState::ConsumerImpl*> consumerNumbering; diff --git a/cpp/src/qpid/cluster/UpdateDataExchange.cpp b/cpp/src/qpid/cluster/UpdateDataExchange.cpp index e5cd82e3d3..2a079b8881 100644 --- a/cpp/src/qpid/cluster/UpdateDataExchange.cpp +++ b/cpp/src/qpid/cluster/UpdateDataExchange.cpp @@ -36,8 +36,13 @@ const std::string UpdateDataExchange::MANAGEMENT_AGENTS_KEY("management-agents") const std::string UpdateDataExchange::MANAGEMENT_SCHEMAS_KEY("management-schemas"); const std::string UpdateDataExchange::MANAGEMENT_DELETED_OBJECTS_KEY("management-deleted-objects"); +std::ostream& operator<<(std::ostream& o, const UpdateDataExchange& c) { + return o << "cluster(" << c.clusterId << " UPDATER)"; +} + UpdateDataExchange::UpdateDataExchange(Cluster& cluster) : - Exchange(EXCHANGE_NAME, &cluster) + Exchange(EXCHANGE_NAME, &cluster), + clusterId(cluster.getId()) {} void UpdateDataExchange::route(broker::Deliverable& msg, const std::string& routingKey, @@ -57,9 +62,11 @@ void UpdateDataExchange::updateManagementAgent(management::ManagementAgent* agen framing::Buffer buf1(const_cast<char*>(managementAgents.data()), managementAgents.size()); agent->importAgents(buf1); + QPID_LOG(debug, *this << " updated management agents."); framing::Buffer buf2(const_cast<char*>(managementSchemas.data()), managementSchemas.size()); agent->importSchemas(buf2); + QPID_LOG(debug, *this << " updated management schemas."); using amqp_0_10::ListCodec; using types::Variant; @@ -71,6 +78,7 @@ void UpdateDataExchange::updateManagementAgent(management::ManagementAgent* agen new management::ManagementAgent::DeletedObject(*i))); } agent->importDeletedObjects(objects); + QPID_LOG(debug, *this << " updated management deleted objects."); } diff --git a/cpp/src/qpid/cluster/UpdateDataExchange.h b/cpp/src/qpid/cluster/UpdateDataExchange.h index d2f6c35ad0..8c493e400a 100644 --- a/cpp/src/qpid/cluster/UpdateDataExchange.h +++ b/cpp/src/qpid/cluster/UpdateDataExchange.h @@ -74,9 +74,11 @@ class UpdateDataExchange : public broker::Exchange void updateManagementAgent(management::ManagementAgent* agent); private: + MemberId clusterId; std::string managementAgents; std::string managementSchemas; std::string managementDeletedObjects; + friend std::ostream& operator<<(std::ostream&, const UpdateDataExchange&); }; }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/UpdateExchange.cpp b/cpp/src/qpid/cluster/UpdateExchange.cpp index cb1376004e..11937f296f 100644 --- a/cpp/src/qpid/cluster/UpdateExchange.cpp +++ b/cpp/src/qpid/cluster/UpdateExchange.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -19,7 +19,6 @@ * */ #include "qpid/framing/MessageTransferBody.h" -#include "qpid/framing/FieldTable.h" #include "qpid/broker/Message.h" #include "UpdateExchange.h" @@ -28,8 +27,6 @@ namespace cluster { using framing::MessageTransferBody; using framing::DeliveryProperties; -using framing::MessageProperties; -using framing::FieldTable; UpdateExchange::UpdateExchange(management::Manageable* parent) : broker::Exchange(UpdateClient::UPDATE, parent), @@ -37,7 +34,6 @@ UpdateExchange::UpdateExchange(management::Manageable* parent) void UpdateExchange::setProperties(const boost::intrusive_ptr<broker::Message>& msg) { - // Copy exchange name to destination property. MessageTransferBody* transfer = msg->getMethod<MessageTransferBody>(); assert(transfer); const DeliveryProperties* props = msg->getProperties<DeliveryProperties>(); @@ -46,23 +42,6 @@ void UpdateExchange::setProperties(const boost::intrusive_ptr<broker::Message>& transfer->setDestination(props->getExchange()); else transfer->clearDestinationFlag(); - - // Copy expiration from x-property if present. - if (msg->hasProperties<MessageProperties>()) { - const MessageProperties* mprops = msg->getProperties<MessageProperties>(); - if (mprops->hasApplicationHeaders()) { - const FieldTable& headers = mprops->getApplicationHeaders(); - if (headers.isSet(UpdateClient::X_QPID_EXPIRATION)) { - msg->setExpiration( - sys::AbsTime(sys::EPOCH, headers.getAsInt64(UpdateClient::X_QPID_EXPIRATION))); - msg->removeCustomProperty(UpdateClient::X_QPID_EXPIRATION); - // Erase props/headers that were added by the UpdateClient - if (headers.isSet(UpdateClient::X_QPID_NO_MESSAGE_PROPS)) - msg->eraseProperties<MessageProperties>(); - else if (headers.isSet(UpdateClient::X_QPID_NO_HEADERS)) - msg->clearApplicationHeadersFlag(); - } - } - } } + }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/UpdateReceiver.h b/cpp/src/qpid/cluster/UpdateReceiver.h index 81ee3a5ffe..7e8ce47662 100644 --- a/cpp/src/qpid/cluster/UpdateReceiver.h +++ b/cpp/src/qpid/cluster/UpdateReceiver.h @@ -39,20 +39,6 @@ class UpdateReceiver { /** Management-id for the next shadow connection */ std::string nextShadowMgmtId; - - /** Record the position of a DtxBuffer in the DtxManager (xid + index) - * and the association with a session, either suspended or current. - */ - struct DtxBufferRef { - std::string xid; - uint32_t index; // Index in WorkRecord in DtxManager - bool suspended; // Is this a suspended or current transaction? - broker::SemanticState* semanticState; // Associated session - DtxBufferRef(const std::string& x, uint32_t i, bool s, broker::SemanticState* ss) - : xid(x), index(i), suspended(s), semanticState(ss) {} - }; - typedef std::vector<DtxBufferRef> DtxBuffers; - DtxBuffers dtxBuffers; }; }} // namespace qpid::cluster diff --git a/cpp/src/qpid/cluster/types.h b/cpp/src/qpid/cluster/types.h index bfb4fd5b9e..0795e5e77a 100644 --- a/cpp/src/qpid/cluster/types.h +++ b/cpp/src/qpid/cluster/types.h @@ -24,7 +24,6 @@ #include "config.h" #include "qpid/Url.h" -#include "qpid/RefCounted.h" #include "qpid/sys/IntegerTypes.h" #include <boost/intrusive_ptr.hpp> #include <utility> diff --git a/cpp/src/qpid/console/SessionManager.cpp b/cpp/src/qpid/console/SessionManager.cpp index 910ae22be8..80c5959417 100644 --- a/cpp/src/qpid/console/SessionManager.cpp +++ b/cpp/src/qpid/console/SessionManager.cpp @@ -362,11 +362,12 @@ void SessionManager::handleCommandComplete(Broker* broker, Buffer& inBuffer, uin void SessionManager::handleClassInd(Broker* broker, Buffer& inBuffer, uint32_t) { + uint8_t kind; string packageName; string className; uint8_t hash[16]; - /*kind*/ (void) inBuffer.getOctet(); + kind = inBuffer.getOctet(); inBuffer.getShortString(packageName); inBuffer.getShortString(className); inBuffer.getBin128(hash); diff --git a/cpp/src/qpid/framing/AMQBody.h b/cpp/src/qpid/framing/AMQBody.h index 56d1d250c1..60ac2d3b7e 100644 --- a/cpp/src/qpid/framing/AMQBody.h +++ b/cpp/src/qpid/framing/AMQBody.h @@ -46,7 +46,7 @@ struct AMQBodyConstVisitor { virtual void visit(const AMQMethodBody&) = 0; }; -class QPID_COMMON_CLASS_EXTERN AMQBody : public RefCounted { +class AMQBody : public RefCounted { public: AMQBody() {} QPID_COMMON_EXTERN virtual ~AMQBody(); diff --git a/cpp/src/qpid/framing/AMQContentBody.h b/cpp/src/qpid/framing/AMQContentBody.h index e25451e354..69813b221c 100644 --- a/cpp/src/qpid/framing/AMQContentBody.h +++ b/cpp/src/qpid/framing/AMQContentBody.h @@ -29,7 +29,7 @@ namespace qpid { namespace framing { -class QPID_COMMON_CLASS_EXTERN AMQContentBody : public AMQBody +class AMQContentBody : public AMQBody { string data; @@ -37,15 +37,15 @@ public: 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; } + 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; - void accept(AMQBodyConstVisitor& v) const { v.visit(*this); } - boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); } + 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/cpp/src/qpid/framing/AMQFrame.cpp b/cpp/src/qpid/framing/AMQFrame.cpp index 5b9673f0d0..cd60cd971f 100644 --- a/cpp/src/qpid/framing/AMQFrame.cpp +++ b/cpp/src/qpid/framing/AMQFrame.cpp @@ -139,11 +139,6 @@ bool AMQFrame::decode(Buffer& buffer) return true; } -void AMQFrame::cloneBody() -{ - body = body->clone(); -} - std::ostream& operator<<(std::ostream& out, const AMQFrame& f) { return diff --git a/cpp/src/qpid/framing/AMQFrame.h b/cpp/src/qpid/framing/AMQFrame.h index 4f6faf4199..d7b04f0f65 100644 --- a/cpp/src/qpid/framing/AMQFrame.h +++ b/cpp/src/qpid/framing/AMQFrame.h @@ -33,7 +33,7 @@ namespace qpid { namespace framing { -class QPID_COMMON_CLASS_EXTERN AMQFrame : public AMQDataBlock +class AMQFrame : public AMQDataBlock { public: QPID_COMMON_EXTERN AMQFrame(const boost::intrusive_ptr<AMQBody>& b=0); @@ -59,11 +59,6 @@ class QPID_COMMON_CLASS_EXTERN AMQFrame : public AMQDataBlock return boost::polymorphic_downcast<const T*>(getBody()); } - /** - * Take a deep copy of the body currently referenced - */ - QPID_COMMON_EXTERN void cloneBody(); - QPID_COMMON_EXTERN void encode(Buffer& buffer) const; QPID_COMMON_EXTERN bool decode(Buffer& buffer); QPID_COMMON_EXTERN uint32_t encodedSize() const; diff --git a/cpp/src/qpid/framing/AMQHeaderBody.h b/cpp/src/qpid/framing/AMQHeaderBody.h index 452154eb5c..8d96e35720 100644 --- a/cpp/src/qpid/framing/AMQHeaderBody.h +++ b/cpp/src/qpid/framing/AMQHeaderBody.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -35,7 +35,7 @@ namespace qpid { namespace framing { -class QPID_COMMON_CLASS_EXTERN AMQHeaderBody : public AMQBody +class AMQHeaderBody : public AMQBody { template <class T> struct OptProps { boost::optional<T> props; }; template <class Base, class T> @@ -58,7 +58,7 @@ class QPID_COMMON_CLASS_EXTERN AMQHeaderBody : public AMQBody } else return Base::decode(buffer, size, type); - } + } void print(std::ostream& out) const { const boost::optional<T>& p=this->OptProps<T>::props; if (p) out << *p; @@ -77,7 +77,7 @@ class QPID_COMMON_CLASS_EXTERN AMQHeaderBody : public AMQBody typedef PropSet<PropSet<Empty, DeliveryProperties>, MessageProperties> Properties; Properties properties; - + public: inline uint8_t type() const { return HEADER_BODY; } @@ -99,10 +99,6 @@ public: return properties.OptProps<T>::props.get_ptr(); } - template <class T> void erase() { - properties.OptProps<T>::props.reset(); - } - boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); } }; diff --git a/cpp/src/qpid/framing/AMQHeartbeatBody.h b/cpp/src/qpid/framing/AMQHeartbeatBody.h index 19ac2be013..9b1fe8a4c1 100644 --- a/cpp/src/qpid/framing/AMQHeartbeatBody.h +++ b/cpp/src/qpid/framing/AMQHeartbeatBody.h @@ -29,7 +29,7 @@ namespace qpid { namespace framing { -class QPID_COMMON_CLASS_EXTERN AMQHeartbeatBody : public AMQBody +class AMQHeartbeatBody : public AMQBody { public: QPID_COMMON_EXTERN virtual ~AMQHeartbeatBody(); diff --git a/cpp/src/qpid/framing/FieldTable.cpp b/cpp/src/qpid/framing/FieldTable.cpp index f80d2f9fb1..023e4af819 100644 --- a/cpp/src/qpid/framing/FieldTable.cpp +++ b/cpp/src/qpid/framing/FieldTable.cpp @@ -129,7 +129,7 @@ FieldTable::ValuePtr FieldTable::get(const std::string& name) const namespace { template <class T> T default_value() { return T(); } template <> int default_value<int>() { return 0; } - //template <> uint64_t default_value<uint64_t>() { return 0; } + template <> uint64_t default_value<uint64_t>() { return 0; } } template <class T> @@ -198,12 +198,10 @@ void FieldTable::encode(Buffer& buffer) const { void FieldTable::decode(Buffer& buffer){ clear(); - if (buffer.available() < 4) - throw IllegalArgumentException(QPID_MSG("Not enough data for field table.")); uint32_t len = buffer.getLong(); if (len) { uint32_t available = buffer.available(); - if ((available < len) || (available < 4)) + if (available < len) throw IllegalArgumentException(QPID_MSG("Not enough data for field table.")); uint32_t count = buffer.getLong(); uint32_t leftover = available - len; diff --git a/cpp/src/qpid/framing/List.cpp b/cpp/src/qpid/framing/List.cpp index d7ea172bac..963ebc206b 100644 --- a/cpp/src/qpid/framing/List.cpp +++ b/cpp/src/qpid/framing/List.cpp @@ -49,9 +49,6 @@ void List::encode(Buffer& buffer) const void List::decode(Buffer& buffer) { values.clear(); - if (buffer.available() < 4) - throw IllegalArgumentException(QPID_MSG("Not enough data for list, expected at least " - " 4 bytes but only " << buffer.available() << " available")); uint32_t size = buffer.getLong(); uint32_t available = buffer.available(); if (available < size) { @@ -59,9 +56,6 @@ void List::decode(Buffer& buffer) << size << " bytes but only " << available << " available")); } if (size) { - if (buffer.available() < 4) - throw IllegalArgumentException(QPID_MSG("Not enough data for list, expected at least " - " 4 bytes but only " << buffer.available() << " available")); uint32_t count = buffer.getLong(); for (uint32_t i = 0; i < count; i++) { ValuePtr value(new FieldValue); diff --git a/cpp/src/qpid/framing/MethodBodyFactory.h b/cpp/src/qpid/framing/MethodBodyFactory.h index 88bc444795..607ec9d959 100644 --- a/cpp/src/qpid/framing/MethodBodyFactory.h +++ b/cpp/src/qpid/framing/MethodBodyFactory.h @@ -22,7 +22,6 @@ * */ #include "qpid/framing/amqp_types.h" -#include "qpid/framing/AMQBody.h" #include <boost/intrusive_ptr.hpp> namespace qpid { diff --git a/cpp/src/qpid/framing/SendContent.h b/cpp/src/qpid/framing/SendContent.h index 1c464b9c8b..745c948c9e 100644 --- a/cpp/src/qpid/framing/SendContent.h +++ b/cpp/src/qpid/framing/SendContent.h @@ -37,7 +37,7 @@ namespace framing { */ class SendContent { - FrameHandler& handler; + mutable FrameHandler& handler; const uint16_t maxFrameSize; uint expectedFrameCount; uint frameCount; diff --git a/cpp/src/qpid/framing/TransferContent.h b/cpp/src/qpid/framing/TransferContent.h index 9a698a1823..5fe1a513a9 100644 --- a/cpp/src/qpid/framing/TransferContent.h +++ b/cpp/src/qpid/framing/TransferContent.h @@ -32,7 +32,7 @@ namespace qpid { namespace framing { /** Message content */ -class QPID_COMMON_CLASS_EXTERN TransferContent : public MethodContent +class TransferContent : public MethodContent { AMQHeaderBody header; std::string data; diff --git a/cpp/src/qpid/framing/Uuid.cpp b/cpp/src/qpid/framing/Uuid.cpp index b3d1e2e1e4..945c0a4d24 100644 --- a/cpp/src/qpid/framing/Uuid.cpp +++ b/cpp/src/qpid/framing/Uuid.cpp @@ -59,9 +59,7 @@ void Uuid::clear() { // Force int 0/!0 to false/true; avoids compile warnings. bool Uuid::isNull() const { - // This const cast is for Solaris which has a - // uuid_is_null that takes a non const argument - return !!uuid_is_null(const_cast<uint8_t*>(data())); + return !!uuid_is_null(data()); } void Uuid::encode(Buffer& buf) const { diff --git a/cpp/src/qpid/log/Logger.cpp b/cpp/src/qpid/log/Logger.cpp index 1600822142..2217cdddbd 100644 --- a/cpp/src/qpid/log/Logger.cpp +++ b/cpp/src/qpid/log/Logger.cpp @@ -22,7 +22,6 @@ #include "qpid/memory.h" #include "qpid/sys/Thread.h" #include "qpid/sys/Time.h" -#include "qpid/DisableExceptionLogging.h" #include <boost/pool/detail/singleton.hpp> #include <boost/bind.hpp> #include <boost/function.hpp> @@ -49,16 +48,11 @@ Logger& Logger::instance() { } Logger::Logger() : flags(0) { - // Disable automatic logging in Exception constructors to avoid - // re-entrant use of logger singleton if there is an error in - // option parsing. - DisableExceptionLogging del; - // Initialize myself from env variables so all programs // (e.g. tests) can use logging even if they don't parse // command line args. Options opts(""); - opts.parse(0, 0); + opts.parse(0, 0); configure(opts); } @@ -79,12 +73,8 @@ void Logger::log(const Statement& s, const std::string& msg) { std::ostringstream os; if (!prefix.empty()) os << prefix << ": "; - if (flags&TIME) { - if (flags&HIRES) - qpid::sys::outputHiresNow(os); - else - qpid::sys::outputFormattedNow(os); - } + if (flags&TIME) + qpid::sys::outputFormattedNow(os); if (flags&LEVEL) os << LevelTraits::name(s.level) << " "; if (flags&THREAD) @@ -133,8 +123,7 @@ int Logger::format(const Options& opts) { bitIf(opts.time, TIME) | bitIf(opts.source, (FILE|LINE)) | bitIf(opts.function, FUNCTION) | - bitIf(opts.thread, THREAD) | - bitIf(opts.hiresTs, HIRES); + bitIf(opts.thread, THREAD); format(flags); return flags; } @@ -151,7 +140,7 @@ void Logger::configure(const Options& opts) { Options o(opts); if (o.trace) o.selectors.push_back("trace+"); - format(o); + format(o); select(Selector(o)); setPrefix(opts.prefix); options.sinkOptions->setup(this); diff --git a/cpp/src/qpid/log/Options.cpp b/cpp/src/qpid/log/Options.cpp index 0001d00bdf..24ef413cbc 100644 --- a/cpp/src/qpid/log/Options.cpp +++ b/cpp/src/qpid/log/Options.cpp @@ -38,7 +38,6 @@ Options::Options(const std::string& argv0_, const std::string& name_) : thread(false), source(false), function(false), - hiresTs(false), trace(false), sinkOptions (SinkOptions::create(argv0_)) { @@ -66,7 +65,6 @@ Options::Options(const std::string& argv0_, const std::string& name_) : ("log-source", optValue(source,"yes|no"), "Include source file:line in log messages") ("log-thread", optValue(thread,"yes|no"), "Include thread ID in log messages") ("log-function", optValue(function,"yes|no"), "Include function signature in log messages") - ("log-hires-timestamp", optValue(hiresTs,"yes|no"), "Use unformatted hi-res timestamp in log messages") ("log-prefix", optValue(prefix,"STRING"), "Prefix to append to all log messages") ; add(*sinkOptions); @@ -82,7 +80,6 @@ Options::Options(const Options &o) : thread(o.thread), source(o.source), function(o.function), - hiresTs(o.hiresTs), trace(o.trace), prefix(o.prefix), sinkOptions (SinkOptions::create(o.argv0)) @@ -100,7 +97,6 @@ Options& Options::operator=(const Options& x) { thread = x.thread; source = x.source; function = x.function; - hiresTs = x.hiresTs; trace = x.trace; prefix = x.prefix; *sinkOptions = *x.sinkOptions; diff --git a/cpp/src/qpid/log/Statement.cpp b/cpp/src/qpid/log/Statement.cpp index 7dfdf08703..6a32b50096 100644 --- a/cpp/src/qpid/log/Statement.cpp +++ b/cpp/src/qpid/log/Statement.cpp @@ -27,6 +27,8 @@ namespace qpid { namespace log { namespace { +using namespace std; + struct NonPrint { bool operator()(unsigned char c) { return !isprint(c) && !isspace(c); } }; const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; @@ -37,7 +39,7 @@ std::string quote(const std::string& str) { if (n==0) return str; std::string ret; ret.reserve(str.size()+2*n); // Avoid extra allocations. - for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) { + for (string::const_iterator i = str.begin(); i != str.end(); ++i) { if (nonPrint(*i)) { ret.push_back('\\'); ret.push_back('x'); @@ -48,6 +50,7 @@ std::string quote(const std::string& str) { } return ret; } + } void Statement::log(const std::string& message) { diff --git a/cpp/src/qpid/log/posix/SinkOptions.cpp b/cpp/src/qpid/log/posix/SinkOptions.cpp index ffa7633e3b..292e9147f6 100644 --- a/cpp/src/qpid/log/posix/SinkOptions.cpp +++ b/cpp/src/qpid/log/posix/SinkOptions.cpp @@ -180,7 +180,7 @@ qpid::log::SinkOptions& SinkOptions::operator=(const qpid::log::SinkOptions& rhs } void SinkOptions::detached(void) { - if (logToStderr && !logToStdout && !logToSyslog && logFile.empty()) { + if (logToStderr && !logToStdout && !logToSyslog) { logToStderr = false; logToSyslog = true; } diff --git a/cpp/src/qpid/log/windows/SinkOptions.cpp b/cpp/src/qpid/log/windows/SinkOptions.cpp index 0c74bea64e..28f4b267e0 100644 --- a/cpp/src/qpid/log/windows/SinkOptions.cpp +++ b/cpp/src/qpid/log/windows/SinkOptions.cpp @@ -53,7 +53,7 @@ static int eventTypes[qpid::log::LevelTraits::COUNT] = { class EventLogOutput : public qpid::log::Logger::Output { public: - EventLogOutput(const std::string& /*sourceName*/) : logHandle(0) + EventLogOutput(const std::string& sourceName) : logHandle(0) { logHandle = OpenEventLog(0, "Application"); } @@ -83,7 +83,7 @@ private: HANDLE logHandle; }; -SinkOptions::SinkOptions(const std::string& /*argv0*/) +SinkOptions::SinkOptions(const std::string& argv0) : qpid::log::SinkOptions(), logToStderr(true), logToStdout(false), diff --git a/cpp/src/qpid/log/windows/SinkOptions.h b/cpp/src/qpid/log/windows/SinkOptions.h index f270c504a2..605822fd46 100644 --- a/cpp/src/qpid/log/windows/SinkOptions.h +++ b/cpp/src/qpid/log/windows/SinkOptions.h @@ -26,7 +26,7 @@ namespace qpid { namespace log { namespace windows { -struct QPID_COMMON_CLASS_EXTERN SinkOptions : public qpid::log::SinkOptions { +struct SinkOptions : public qpid::log::SinkOptions { QPID_COMMON_EXTERN SinkOptions(const std::string& argv0); virtual ~SinkOptions() {} diff --git a/cpp/src/qpid/management/ManagementAgent.cpp b/cpp/src/qpid/management/ManagementAgent.cpp index 5799a1adca..23c999a98a 100644 --- a/cpp/src/qpid/management/ManagementAgent.cpp +++ b/cpp/src/qpid/management/ManagementAgent.cpp @@ -31,7 +31,6 @@ #include <qpid/broker/Message.h> #include "qpid/framing/MessageTransferBody.h" #include "qpid/sys/Time.h" -#include "qpid/sys/Thread.h" #include "qpid/broker/ConnectionState.h" #include "qpid/broker/AclModule.h" #include "qpid/types/Variant.h" @@ -75,18 +74,6 @@ namespace { } return n2; } - -struct ScopedManagementContext -{ - ScopedManagementContext(const qpid::broker::ConnectionState* context) - { - setManagementExecutionContext(context); - } - ~ScopedManagementContext() - { - setManagementExecutionContext(0); - } -}; } @@ -548,7 +535,6 @@ void ManagementAgent::sendBufferLH(Buffer& buf, dp->setRoutingKey(routingKey); msg->getFrames().append(content); - msg->setIsManagementMessage(true); { sys::Mutex::ScopedUnlock u(userLock); @@ -614,7 +600,7 @@ void ManagementAgent::sendBufferLH(const string& data, props->setAppId("qmf2"); for (i = headers.begin(); i != headers.end(); ++i) { - msg->insertCustomProperty(i->first, i->second.asString()); + msg->getOrInsertHeaders().setString(i->first, i->second.asString()); } DeliveryProperties* dp = @@ -622,10 +608,9 @@ void ManagementAgent::sendBufferLH(const string& data, dp->setRoutingKey(routingKey); if (ttl_msec) { dp->setTtl(ttl_msec); - msg->computeExpiration(broker->getExpiryPolicy()); + msg->setTimestamp(broker->getExpiryPolicy()); } msg->getFrames().append(content); - msg->setIsManagementMessage(true); { sys::Mutex::ScopedUnlock u(userLock); @@ -2252,7 +2237,6 @@ void ManagementAgent::dispatchAgentCommandLH(Message& msg, bool viaLocal) uint32_t bufferLen = inBuffer.getPosition(); inBuffer.reset(); - ScopedManagementContext context((const qpid::broker::ConnectionState*) msg.getPublisher()); const framing::FieldTable *headers = msg.getApplicationHeaders(); if (headers && msg.getAppId() == "qmf2") { @@ -2756,14 +2740,200 @@ void ManagementAgent::debugSnapshot(const char* title) { title << ": new objects" << dumpVector(newManagementObjects)); } - Variant::Map ManagementAgent::toMap(const FieldTable& from) { Variant::Map map; - qpid::amqp_0_10::translate(from, map); + + for (FieldTable::const_iterator iter = from.begin(); iter != from.end(); iter++) { + const string& key(iter->first); + const FieldTable::ValuePtr& val(iter->second); + + map[key] = toVariant(val); + } + return map; } +Variant::List ManagementAgent::toList(const List& from) +{ + Variant::List _list; + + for (List::const_iterator iter = from.begin(); iter != from.end(); iter++) { + const List::ValuePtr& val(*iter); + + _list.push_back(toVariant(val)); + } + + return _list; +} + +qpid::framing::FieldTable ManagementAgent::fromMap(const Variant::Map& from) +{ + qpid::framing::FieldTable ft; + + for (Variant::Map::const_iterator iter = from.begin(); + iter != from.end(); + iter++) { + const string& key(iter->first); + const Variant& val(iter->second); + + ft.set(key, toFieldValue(val)); + } + + return ft; +} + + +List ManagementAgent::fromList(const Variant::List& from) +{ + List fa; + + for (Variant::List::const_iterator iter = from.begin(); + iter != from.end(); + iter++) { + const Variant& val(*iter); + + fa.push_back(toFieldValue(val)); + } + + return fa; +} + + +boost::shared_ptr<FieldValue> ManagementAgent::toFieldValue(const Variant& in) +{ + + switch(in.getType()) { + + case types::VAR_VOID: return boost::shared_ptr<FieldValue>(new VoidValue()); + case types::VAR_BOOL: return boost::shared_ptr<FieldValue>(new BoolValue(in.asBool())); + case types::VAR_UINT8: return boost::shared_ptr<FieldValue>(new Unsigned8Value(in.asUint8())); + case types::VAR_UINT16: return boost::shared_ptr<FieldValue>(new Unsigned16Value(in.asUint16())); + case types::VAR_UINT32: return boost::shared_ptr<FieldValue>(new Unsigned32Value(in.asUint32())); + case types::VAR_UINT64: return boost::shared_ptr<FieldValue>(new Unsigned64Value(in.asUint64())); + case types::VAR_INT8: return boost::shared_ptr<FieldValue>(new Integer8Value(in.asInt8())); + case types::VAR_INT16: return boost::shared_ptr<FieldValue>(new Integer16Value(in.asInt16())); + case types::VAR_INT32: return boost::shared_ptr<FieldValue>(new Integer32Value(in.asInt32())); + case types::VAR_INT64: return boost::shared_ptr<FieldValue>(new Integer64Value(in.asInt64())); + case types::VAR_FLOAT: return boost::shared_ptr<FieldValue>(new FloatValue(in.asFloat())); + case types::VAR_DOUBLE: return boost::shared_ptr<FieldValue>(new DoubleValue(in.asDouble())); + case types::VAR_STRING: return boost::shared_ptr<FieldValue>(new Str16Value(in.asString())); + case types::VAR_UUID: return boost::shared_ptr<FieldValue>(new UuidValue(in.asUuid().data())); + case types::VAR_MAP: return boost::shared_ptr<FieldValue>(new FieldTableValue(ManagementAgent::fromMap(in.asMap()))); + case types::VAR_LIST: return boost::shared_ptr<FieldValue>(new ListValue(ManagementAgent::fromList(in.asList()))); + } + + QPID_LOG(error, "Unknown Variant type - not converted: [" << in.getType() << "]"); + return boost::shared_ptr<FieldValue>(new VoidValue()); +} + +// stolen from qpid/client/amqp0_10/Codecs.cpp - TODO: make Codecs public, and remove this dup. +Variant ManagementAgent::toVariant(const boost::shared_ptr<FieldValue>& in) +{ + const string iso885915("iso-8859-15"); + const string utf8("utf8"); + const string utf16("utf16"); + //const string binary("binary"); + const string amqp0_10_binary("amqp0-10:binary"); + //const string amqp0_10_bit("amqp0-10:bit"); + const string amqp0_10_datetime("amqp0-10:datetime"); + const string amqp0_10_struct("amqp0-10:struct"); + Variant out; + + //based on AMQP 0-10 typecode, pick most appropriate variant type + switch (in->getType()) { + //Fixed Width types: + case 0x00: //bin8 + case 0x01: out.setEncoding(amqp0_10_binary); // int8 + case 0x02: out = in->getIntegerValue<int8_t, 1>(); break; //uint8 + case 0x03: out = in->getIntegerValue<uint8_t, 1>(); break; // + // case 0x04: break; //TODO: iso-8859-15 char // char + case 0x08: out = static_cast<bool>(in->getIntegerValue<uint8_t, 1>()); break; // bool int8 + + case 0x10: out.setEncoding(amqp0_10_binary); // bin16 + case 0x11: out = in->getIntegerValue<int16_t, 2>(); break; // int16 + case 0x12: out = in->getIntegerValue<uint16_t, 2>(); break; //uint16 + + case 0x20: out.setEncoding(amqp0_10_binary); // bin32 + case 0x21: out = in->getIntegerValue<int32_t, 4>(); break; // int32 + case 0x22: out = in->getIntegerValue<uint32_t, 4>(); break; // uint32 + + case 0x23: out = in->get<float>(); break; // float(32) + + // case 0x27: break; //TODO: utf-32 char + + case 0x30: out.setEncoding(amqp0_10_binary); // bin64 + case 0x31: out = in->getIntegerValue<int64_t, 8>(); break; //int64 + + case 0x38: out.setEncoding(amqp0_10_datetime); //treat datetime as uint64_t, but set encoding + case 0x32: out = in->getIntegerValue<uint64_t, 8>(); break; //uint64 + case 0x33: out = in->get<double>(); break; // double + + case 0x48: // uuid + { + unsigned char data[16]; + in->getFixedWidthValue<16>(data); + out = qpid::types::Uuid(data); + } break; + + //TODO: figure out whether and how to map values with codes 0x40-0xd8 + + case 0xf0: break;//void, which is the default value for Variant + // case 0xf1: out.setEncoding(amqp0_10_bit); break;//treat 'bit' as void, which is the default value for Variant + + //Variable Width types: + //strings: + case 0x80: // str8 + case 0x90: // str16 + case 0xa0: // str32 + out = in->get<string>(); + out.setEncoding(amqp0_10_binary); + break; + + case 0x84: // str8 + case 0x94: // str16 + out = in->get<string>(); + out.setEncoding(iso885915); + break; + + case 0x85: // str8 + case 0x95: // str16 + out = in->get<string>(); + out.setEncoding(utf8); + break; + + case 0x86: // str8 + case 0x96: // str16 + out = in->get<string>(); + out.setEncoding(utf16); + break; + + case 0xab: // str32 + out = in->get<string>(); + out.setEncoding(amqp0_10_struct); + break; + + case 0xa8: // map + out = ManagementAgent::toMap(in->get<FieldTable>()); + break; + + case 0xa9: // list of variant types + out = ManagementAgent::toList(in->get<List>()); + break; + //case 0xaa: //convert amqp0-10 array (uniform type) into variant list + // out = Variant::List(); + // translate<Array>(in, out.asList(), &toVariant); + // break; + + default: + //error? + QPID_LOG(error, "Unknown FieldValue type - not converted: [" << (unsigned int)(in->getType()) << "]"); + break; + } + + return out; +} + // Build up a list of the current set of deleted objects that are pending their // next (last) publish-ment. @@ -2915,21 +3085,3 @@ bool ManagementAgent::moveDeletedObjectsLH() { } return !deleteList.empty(); } - -namespace qpid { -namespace management { - -namespace { -QPID_TSS const qpid::broker::ConnectionState* executionContext = 0; -} - -void setManagementExecutionContext(const qpid::broker::ConnectionState* ctxt) -{ - executionContext = ctxt; -} -const qpid::broker::ConnectionState* getManagementExecutionContext() -{ - return executionContext; -} - -}} diff --git a/cpp/src/qpid/management/ManagementAgent.h b/cpp/src/qpid/management/ManagementAgent.h index c21f384433..0db19594a7 100644 --- a/cpp/src/qpid/management/ManagementAgent.h +++ b/cpp/src/qpid/management/ManagementAgent.h @@ -41,9 +41,6 @@ #include <map> namespace qpid { -namespace broker { -class ConnectionState; -} namespace management { class ManagementAgent @@ -145,7 +142,13 @@ public: const framing::Uuid& getUuid() const { return uuid; } void setUuid(const framing::Uuid& id) { uuid = id; writeData(); } + // TODO: remove these when Variant API moved into common library. static types::Variant::Map toMap(const framing::FieldTable& from); + static framing::FieldTable fromMap(const types::Variant::Map& from); + static types::Variant::List toList(const framing::List& from); + static framing::List fromList(const types::Variant::List& from); + static boost::shared_ptr<framing::FieldValue> toFieldValue(const types::Variant& in); + static types::Variant toVariant(const boost::shared_ptr<framing::FieldValue>& val); // For Clustering: management objects that have been marked as // "deleted", but are waiting for their last published object @@ -419,8 +422,6 @@ private: void debugSnapshot(const char* title); }; -void setManagementExecutionContext(const qpid::broker::ConnectionState*); -const qpid::broker::ConnectionState* getManagementExecutionContext(); }} - + #endif /*!_ManagementAgent_*/ diff --git a/cpp/src/qpid/messaging/AddressParser.cpp b/cpp/src/qpid/messaging/AddressParser.cpp index d76210ee5d..4c8f35fbc5 100644 --- a/cpp/src/qpid/messaging/AddressParser.cpp +++ b/cpp/src/qpid/messaging/AddressParser.cpp @@ -151,7 +151,7 @@ bool AddressParser::readValueIfExists(Variant& value) bool AddressParser::readString(std::string& value, char delimiter) { if (readChar(delimiter)) { - std::string::size_type start = current; + std::string::size_type start = current++; while (!eos()) { if (input.at(current) == delimiter) { if (current > start) { @@ -201,8 +201,7 @@ bool AddressParser::readSimpleValue(Variant& value) { std::string s; if (readWord(s)) { - value.parse(s); - if (value.getType() == VAR_STRING) value.setEncoding("utf8"); + value.parse(s); return true; } else { return false; diff --git a/cpp/src/qpid/messaging/Duration.cpp b/cpp/src/qpid/messaging/Duration.cpp index a23e9f5bcb..a2c443c746 100644 --- a/cpp/src/qpid/messaging/Duration.cpp +++ b/cpp/src/qpid/messaging/Duration.cpp @@ -37,16 +37,6 @@ Duration operator*(uint64_t multiplier, const Duration& duration) return Duration(duration.getMilliseconds() * multiplier); } -bool operator==(const Duration& a, const Duration& b) -{ - return a.getMilliseconds() == b.getMilliseconds(); -} - -bool operator!=(const Duration& a, const Duration& b) -{ - return a.getMilliseconds() != b.getMilliseconds(); -} - const Duration Duration::FOREVER(std::numeric_limits<uint64_t>::max()); const Duration Duration::IMMEDIATE(0); const Duration Duration::SECOND(1000); diff --git a/cpp/src/qpid/messaging/Message.cpp b/cpp/src/qpid/messaging/Message.cpp index ef70c103e9..83cdfd3c55 100644 --- a/cpp/src/qpid/messaging/Message.cpp +++ b/cpp/src/qpid/messaging/Message.cpp @@ -21,7 +21,6 @@ #include "qpid/messaging/Message.h" #include "qpid/messaging/MessageImpl.h" #include "qpid/amqp_0_10/Codecs.h" -#include <qpid/Exception.h> #include <boost/format.hpp> namespace qpid { @@ -116,11 +115,7 @@ template <class C> struct MessageCodec static void decode(const Message& message, typename C::ObjectType& object, const std::string& encoding) { checkEncoding(message, encoding); - try { - C::decode(message.getContent(), object); - } catch (const qpid::Exception &ex) { - throw EncodingException(ex.what()); - } + C::decode(message.getContent(), object); } static void encode(const typename C::ObjectType& map, Message& message, const std::string& encoding) diff --git a/cpp/src/qpid/messaging/Session.cpp b/cpp/src/qpid/messaging/Session.cpp index cccfd9a873..496953a8e5 100644 --- a/cpp/src/qpid/messaging/Session.cpp +++ b/cpp/src/qpid/messaging/Session.cpp @@ -39,8 +39,7 @@ Session& Session::operator=(const Session& s) { return PI::assign(*this, s); } void Session::commit() { impl->commit(); } void Session::rollback() { impl->rollback(); } void Session::acknowledge(bool sync) { impl->acknowledge(sync); } -void Session::acknowledge(Message& m, bool s) { impl->acknowledge(m, false); sync(s); } -void Session::acknowledgeUpTo(Message& m, bool s) { impl->acknowledge(m, true); sync(s); } +void Session::acknowledge(Message& m, bool s) { impl->acknowledge(m); sync(s); } void Session::reject(Message& m) { impl->reject(m); } void Session::release(Message& m) { impl->release(m); } void Session::close() { impl->close(); } diff --git a/cpp/src/qpid/messaging/SessionImpl.h b/cpp/src/qpid/messaging/SessionImpl.h index 60ae615253..02a254e4f2 100644 --- a/cpp/src/qpid/messaging/SessionImpl.h +++ b/cpp/src/qpid/messaging/SessionImpl.h @@ -41,7 +41,7 @@ class SessionImpl : public virtual qpid::RefCounted virtual void commit() = 0; virtual void rollback() = 0; virtual void acknowledge(bool sync) = 0; - virtual void acknowledge(Message&, bool cumulative) = 0; + virtual void acknowledge(Message&) = 0; virtual void reject(Message&) = 0; virtual void release(Message&) = 0; virtual void close() = 0; diff --git a/cpp/src/qpid/replication/ReplicatingEventListener.cpp b/cpp/src/qpid/replication/ReplicatingEventListener.cpp index 0ced4d9161..b7d52372f4 100644 --- a/cpp/src/qpid/replication/ReplicatingEventListener.cpp +++ b/cpp/src/qpid/replication/ReplicatingEventListener.cpp @@ -69,9 +69,10 @@ void ReplicatingEventListener::deliverDequeueMessage(const QueuedMessage& dequeu void ReplicatingEventListener::deliverEnqueueMessage(const QueuedMessage& enqueued) { boost::intrusive_ptr<Message> msg(cloneMessage(*(enqueued.queue), enqueued.payload)); - msg->insertCustomProperty(REPLICATION_TARGET_QUEUE, enqueued.queue->getName()); - msg->insertCustomProperty(REPLICATION_EVENT_TYPE, ENQUEUE); - msg->insertCustomProperty(QUEUE_MESSAGE_POSITION,enqueued.position); + FieldTable& headers = msg->getProperties<MessageProperties>()->getApplicationHeaders(); + headers.setString(REPLICATION_TARGET_QUEUE, enqueued.queue->getName()); + headers.setInt(REPLICATION_EVENT_TYPE, ENQUEUE); + headers.setInt(QUEUE_MESSAGE_POSITION,enqueued.position); route(msg); } diff --git a/cpp/src/qpid/replication/ReplicationExchange.cpp b/cpp/src/qpid/replication/ReplicationExchange.cpp index 89a2bf516d..4b6d25ac7d 100644 --- a/cpp/src/qpid/replication/ReplicationExchange.cpp +++ b/cpp/src/qpid/replication/ReplicationExchange.cpp @@ -97,10 +97,11 @@ void ReplicationExchange::handleEnqueueEvent(const FieldTable* args, Deliverable } else { queue->setPosition(seqno1); - msg.getMessage().removeCustomProperty(REPLICATION_TARGET_QUEUE); - msg.getMessage().removeCustomProperty(REPLICATION_EVENT_SEQNO); - msg.getMessage().removeCustomProperty(REPLICATION_EVENT_TYPE); - msg.getMessage().removeCustomProperty(QUEUE_MESSAGE_POSITION); + FieldTable& headers = msg.getMessage().getProperties<MessageProperties>()->getApplicationHeaders(); + headers.erase(REPLICATION_TARGET_QUEUE); + headers.erase(REPLICATION_EVENT_SEQNO); + headers.erase(REPLICATION_EVENT_TYPE); + headers.erase(QUEUE_MESSAGE_POSITION); msg.deliverTo(queue); QPID_LOG(debug, "Enqueued replicated message onto " << queueName); if (mgmtExchange != 0) { diff --git a/cpp/src/qpid/store/StorageProvider.h b/cpp/src/qpid/store/StorageProvider.h index d162cc58ec..bc8d187517 100644 --- a/cpp/src/qpid/store/StorageProvider.h +++ b/cpp/src/qpid/store/StorageProvider.h @@ -54,7 +54,7 @@ struct QueueEntry { QueueEntry(uint64_t id, TplStatus tpl = NONE, const std::string& x = "") : queueId(id), tplStatus(tpl), xid(x) {} - bool operator==(const QueueEntry& rhs) const { + bool operator==(const QueueEntry& rhs) { if (queueId != rhs.queueId) return false; if (tplStatus == NONE && rhs.tplStatus == NONE) return true; return xid == rhs.xid; diff --git a/cpp/src/qpid/sys/AggregateOutput.h b/cpp/src/qpid/sys/AggregateOutput.h index d7c0ff29e3..6dad998bb0 100644 --- a/cpp/src/qpid/sys/AggregateOutput.h +++ b/cpp/src/qpid/sys/AggregateOutput.h @@ -41,7 +41,7 @@ namespace sys { * doOutput is called in another. */ -class QPID_COMMON_CLASS_EXTERN AggregateOutput : public OutputTask, public OutputControl +class AggregateOutput : public OutputTask, public OutputControl { typedef std::deque<OutputTask*> TaskList; diff --git a/cpp/src/qpid/sys/AsynchIO.h b/cpp/src/qpid/sys/AsynchIO.h index 41f74f7ed0..50da8fa4fc 100644 --- a/cpp/src/qpid/sys/AsynchIO.h +++ b/cpp/src/qpid/sys/AsynchIO.h @@ -64,8 +64,8 @@ public: // deletes. To correctly manage heaps when needed, the allocate and // delete should both be done from the same class/library. QPID_COMMON_EXTERN static AsynchConnector* create(const Socket& s, - const std::string& hostname, - const std::string& port, + std::string hostname, + uint16_t port, ConnectedCallback connCb, FailedCallback failCb); virtual void start(boost::shared_ptr<Poller> poller) = 0; diff --git a/cpp/src/qpid/sys/AsynchIOHandler.h b/cpp/src/qpid/sys/AsynchIOHandler.h index b9867606c4..e1885bac79 100644 --- a/cpp/src/qpid/sys/AsynchIOHandler.h +++ b/cpp/src/qpid/sys/AsynchIOHandler.h @@ -57,7 +57,7 @@ class AsynchIOHandler : public OutputControl { QPID_COMMON_EXTERN ~AsynchIOHandler(); QPID_COMMON_EXTERN void init(AsynchIO* a, int numBuffs); - QPID_COMMON_INLINE_EXTERN void setClient() { isClient = true; } + QPID_COMMON_EXTERN void setClient() { isClient = true; } // Output side QPID_COMMON_EXTERN void abort(); diff --git a/cpp/src/qpid/sys/AtomicValue.h b/cpp/src/qpid/sys/AtomicValue.h index bf995f991e..6e90eafead 100644 --- a/cpp/src/qpid/sys/AtomicValue.h +++ b/cpp/src/qpid/sys/AtomicValue.h @@ -22,12 +22,7 @@ * */ -// Have to check for clang before gcc as clang pretends to be gcc too -#if defined( __clang__ ) -// Use the clang doesn't support atomic builtins for 64 bit values, so use the slow versions -#include "qpid/sys/AtomicValue_mutex.h" - -#elif defined( __GNUC__ ) && __GNUC__ >= 4 && ( defined( __i686__ ) || defined( __x86_64__ ) ) +#if defined( __GNUC__ ) && __GNUC__ >= 4 && ( defined( __i686__ ) || defined( __x86_64__ ) ) // Use the Gnu C built-in atomic operations if compiling with gcc on a suitable platform. #include "qpid/sys/AtomicValue_gcc.h" diff --git a/cpp/src/qpid/sys/AtomicValue_gcc.h b/cpp/src/qpid/sys/AtomicValue_gcc.h index 724bae422e..d022b07c1d 100644 --- a/cpp/src/qpid/sys/AtomicValue_gcc.h +++ b/cpp/src/qpid/sys/AtomicValue_gcc.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -39,9 +39,6 @@ class AtomicValue public: AtomicValue(T init=0) : value(init) {} - // Not atomic. Don't call concurrently with atomic ops. - AtomicValue<T>& operator=(T newValue) { value = newValue; return *this; } - // Update and return new value. inline T operator+=(T n) { return __sync_add_and_fetch(&value, n); } inline T operator-=(T n) { return __sync_sub_and_fetch(&value, n); } @@ -57,11 +54,11 @@ class AtomicValue /** If current value == testval then set to newval. Returns the old value. */ T valueCompareAndSwap(T testval, T newval) { return __sync_val_compare_and_swap(&value, testval, newval); } - /** If current value == testval then set to newval. Returns true if the swap was performed. */ + /** If current value == testval then set to newval. Returns true if the swap was performed. */ bool boolCompareAndSwap(T testval, T newval) { return __sync_bool_compare_and_swap(&value, testval, newval); } T get() const { return const_cast<AtomicValue<T>*>(this)->fetchAndAdd(static_cast<T>(0)); } - + private: T value; }; diff --git a/cpp/src/qpid/sys/ClusterSafe.cpp b/cpp/src/qpid/sys/ClusterSafe.cpp index dd37615145..c6b527dfdf 100644 --- a/cpp/src/qpid/sys/ClusterSafe.cpp +++ b/cpp/src/qpid/sys/ClusterSafe.cpp @@ -34,6 +34,8 @@ QPID_TSS bool inContext = false; bool isClusterSafe() { return !inCluster || inContext; } +bool isCluster() { return inCluster; } + void assertClusterSafe() { if (!isClusterSafe()) { QPID_LOG(critical, "Modified cluster state outside of cluster context"); @@ -51,16 +53,6 @@ ClusterSafeScope::~ClusterSafeScope() { inContext = save; } -ClusterUnsafeScope::ClusterUnsafeScope() { - save = inContext; - inContext = false; -} - -ClusterUnsafeScope::~ClusterUnsafeScope() { - assert(!inContext); - inContext = save; -} - void enableClusterSafe() { inCluster = true; } }} // namespace qpid::sys diff --git a/cpp/src/qpid/sys/ClusterSafe.h b/cpp/src/qpid/sys/ClusterSafe.h index 27e4eb46a5..15675e8cc5 100644 --- a/cpp/src/qpid/sys/ClusterSafe.h +++ b/cpp/src/qpid/sys/ClusterSafe.h @@ -52,9 +52,14 @@ QPID_COMMON_EXTERN void assertClusterSafe(); */ QPID_COMMON_EXTERN bool isClusterSafe(); +/** Return true in a clustered broker */ +QPID_COMMON_EXTERN bool isCluster(); + /** - * Mark a scope as cluster safe. Sets isClusterSafe in constructor and resets - * to previous value in destructor. + * Base class for classes that encapsulate state which is replicated + * to all members of a cluster. Acts as a marker for clustered state + * and provides functions to assist detecting bugs in cluster + * behavior. */ class ClusterSafeScope { public: @@ -65,18 +70,6 @@ class ClusterSafeScope { }; /** - * Mark a scope as cluster unsafe. Clears isClusterSafe in constructor and resets - * to previous value in destructor. - */ -class ClusterUnsafeScope { - public: - QPID_COMMON_EXTERN ClusterUnsafeScope(); - QPID_COMMON_EXTERN ~ClusterUnsafeScope(); - private: - bool save; -}; - -/** * Enable cluster-safe assertions. By default they are no-ops. * Called by cluster code. */ diff --git a/cpp/src/qpid/sys/CopyOnWriteArray.h b/cpp/src/qpid/sys/CopyOnWriteArray.h index 41384fc5a4..45a231dfd8 100644 --- a/cpp/src/qpid/sys/CopyOnWriteArray.h +++ b/cpp/src/qpid/sys/CopyOnWriteArray.h @@ -43,12 +43,6 @@ public: CopyOnWriteArray() {} CopyOnWriteArray(const CopyOnWriteArray& c) : array(c.array) {} - bool empty() - { - Mutex::ScopedLock l(lock); - return array ? array->empty() : true; - } - void add(T& t) { Mutex::ScopedLock l(lock); diff --git a/cpp/src/qpid/sys/PollableQueue.h b/cpp/src/qpid/sys/PollableQueue.h index 03b9d0084d..81c2301c1e 100644 --- a/cpp/src/qpid/sys/PollableQueue.h +++ b/cpp/src/qpid/sys/PollableQueue.h @@ -10,9 +10,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -28,8 +28,7 @@ #include <boost/function.hpp> #include <boost/bind.hpp> #include <algorithm> -#include <deque> -#include "qpid/log/Statement.h" // FIXME aconway 2011-08-05: +#include <vector> namespace qpid { namespace sys { @@ -45,7 +44,7 @@ class Poller; template <class T> class PollableQueue { public: - typedef std::deque<T> Batch; + typedef std::vector<T> Batch; typedef T value_type; /** @@ -69,11 +68,11 @@ class PollableQueue { const boost::shared_ptr<sys::Poller>& poller); ~PollableQueue(); - + /** Push a value onto the queue. Thread safe */ void push(const T& t); - /** Start polling. */ + /** Start polling. */ void start(); /** Stop polling and wait for the current callback, if any, to complete. */ @@ -91,14 +90,14 @@ class PollableQueue { * ensure clean shutdown with no events left on the queue. */ void shutdown(); - + private: typedef sys::Monitor::ScopedLock ScopedLock; typedef sys::Monitor::ScopedUnlock ScopedUnlock; void dispatch(PollableCondition& cond); void process(); - + mutable sys::Monitor lock; Callback callback; PollableCondition condition; @@ -108,7 +107,7 @@ class PollableQueue { }; template <class T> PollableQueue<T>::PollableQueue( - const Callback& cb, const boost::shared_ptr<sys::Poller>& p) + const Callback& cb, const boost::shared_ptr<sys::Poller>& p) : callback(cb), condition(boost::bind(&PollableQueue<T>::dispatch, this, _1), p), stopped(true) @@ -152,7 +151,7 @@ template <class T> void PollableQueue<T>::process() { putBack = callback(batch); } // put back unprocessed items. - queue.insert(queue.begin(), putBack, typename Batch::const_iterator(batch.end())); + queue.insert(queue.begin(), putBack, typename Batch::const_iterator(batch.end())); batch.clear(); } } diff --git a/cpp/src/qpid/sys/Poller.h b/cpp/src/qpid/sys/Poller.h index 01ee139ee6..ec53b79bad 100644 --- a/cpp/src/qpid/sys/Poller.h +++ b/cpp/src/qpid/sys/Poller.h @@ -120,7 +120,7 @@ class PollerHandle { friend struct Poller::Event; PollerHandlePrivate* const impl; - QPID_COMMON_INLINE_EXTERN virtual void processEvent(Poller::EventType) {}; + QPID_COMMON_EXTERN virtual void processEvent(Poller::EventType) {}; public: QPID_COMMON_EXTERN PollerHandle(const IOHandle& h); diff --git a/cpp/src/qpid/sys/ProtocolFactory.h b/cpp/src/qpid/sys/ProtocolFactory.h index 4d198a92da..b233b2da1a 100644 --- a/cpp/src/qpid/sys/ProtocolFactory.h +++ b/cpp/src/qpid/sys/ProtocolFactory.h @@ -39,10 +39,11 @@ class ProtocolFactory : public qpid::SharedObject<ProtocolFactory> virtual ~ProtocolFactory() = 0; virtual uint16_t getPort() const = 0; + virtual std::string getHost() const = 0; virtual void accept(boost::shared_ptr<Poller>, ConnectionCodec::Factory*) = 0; virtual void connect( boost::shared_ptr<Poller>, - const std::string& host, const std::string& port, + const std::string& host, int16_t port, ConnectionCodec::Factory* codec, ConnectFailedCallback failed) = 0; virtual bool supports(const std::string& /*capability*/) { return false; } diff --git a/cpp/src/qpid/sys/RdmaIOPlugin.cpp b/cpp/src/qpid/sys/RdmaIOPlugin.cpp index 6769e5383c..d53db20598 100644 --- a/cpp/src/qpid/sys/RdmaIOPlugin.cpp +++ b/cpp/src/qpid/sys/RdmaIOPlugin.cpp @@ -31,6 +31,7 @@ #include "qpid/sys/SecuritySettings.h" #include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> #include <memory> #include <netdb.h> @@ -211,9 +212,10 @@ void RdmaIOHandler::readbuff(Rdma::AsynchIO&, Rdma::Buffer* buff) { if (readError) { return; } + size_t decoded = 0; try { if (codec) { - (void) codec->decode(buff->bytes(), buff->dataCount()); + decoded = codec->decode(buff->bytes(), buff->dataCount()); }else{ // Need to start protocol processing initProtocolIn(buff); @@ -228,7 +230,9 @@ void RdmaIOHandler::readbuff(Rdma::AsynchIO&, Rdma::Buffer* buff) { void RdmaIOHandler::initProtocolIn(Rdma::Buffer* buff) { framing::Buffer in(buff->bytes(), buff->dataCount()); framing::ProtocolInitiation protocolInit; + size_t decoded = 0; if (protocolInit.decode(in)) { + decoded = in.getPosition(); QPID_LOG(debug, "Rdma: RECV [" << identifier << "] INIT(" << protocolInit << ")"); codec = factory->create(protocolInit.getVersion(), *this, identifier, SecuritySettings()); @@ -250,9 +254,10 @@ class RdmaIOProtocolFactory : public ProtocolFactory { public: RdmaIOProtocolFactory(int16_t port, int backlog); void accept(Poller::shared_ptr, ConnectionCodec::Factory*); - void connect(Poller::shared_ptr, const string& host, const std::string& port, ConnectionCodec::Factory*, ConnectFailedCallback); + void connect(Poller::shared_ptr, const string& host, int16_t port, ConnectionCodec::Factory*, ConnectFailedCallback); uint16_t getPort() const; + string getHost() const; private: bool request(Rdma::Connection::intrusive_ptr, const Rdma::ConnectionParams&, ConnectionCodec::Factory*); @@ -342,7 +347,18 @@ uint16_t RdmaIOProtocolFactory::getPort() const { return listeningPort; // Immutable no need for lock. } +string RdmaIOProtocolFactory::getHost() const { + //return listener.getSockname(); + return ""; +} + void RdmaIOProtocolFactory::accept(Poller::shared_ptr poller, ConnectionCodec::Factory* fact) { + ::sockaddr_in sin; + + sin.sin_family = AF_INET; + sin.sin_port = htons(listeningPort); + sin.sin_addr.s_addr = INADDR_ANY; + listener.reset( new Rdma::Listener( Rdma::ConnectionParams(65536, Rdma::DEFAULT_WR_ENTRIES), @@ -371,7 +387,7 @@ void RdmaIOProtocolFactory::connected(Poller::shared_ptr poller, Rdma::Connectio void RdmaIOProtocolFactory::connect( Poller::shared_ptr poller, - const std::string& host, const std::string& port, + const std::string& host, int16_t port, ConnectionCodec::Factory* f, ConnectFailedCallback failed) { @@ -383,7 +399,7 @@ void RdmaIOProtocolFactory::connect( boost::bind(&RdmaIOProtocolFactory::disconnected, this, _1), boost::bind(&RdmaIOProtocolFactory::rejected, this, _1, _2, failed)); - SocketAddress sa(host, port); + SocketAddress sa(host, boost::lexical_cast<std::string>(port)); c->start(poller, sa); } diff --git a/cpp/src/qpid/sys/Socket.h b/cpp/src/qpid/sys/Socket.h index 25f1c5fb9d..7d50afc59f 100644 --- a/cpp/src/qpid/sys/Socket.h +++ b/cpp/src/qpid/sys/Socket.h @@ -33,21 +33,21 @@ namespace sys { class Duration; class SocketAddress; -class QPID_COMMON_CLASS_EXTERN Socket : public IOHandle +class Socket : public IOHandle { public: /** Create a socket wrapper for descriptor. */ QPID_COMMON_EXTERN Socket(); - /** Create a new Socket which is the same address family as this one */ - QPID_COMMON_EXTERN Socket* createSameTypeSocket() const; + /** Set timeout for read and write */ + void setTimeout(const Duration& interval) const; /** Set socket non blocking */ void setNonblocking() const; QPID_COMMON_EXTERN void setTcpNoDelay() const; - QPID_COMMON_EXTERN void connect(const std::string& host, const std::string& port) const; + QPID_COMMON_EXTERN void connect(const std::string& host, uint16_t port) const; QPID_COMMON_EXTERN void connect(const SocketAddress&) const; QPID_COMMON_EXTERN void close() const; @@ -57,9 +57,19 @@ public: *@param backlog maximum number of pending connections. *@return The bound port. */ - QPID_COMMON_EXTERN int listen(const std::string& host = "", const std::string& port = "0", int backlog = 10) const; + QPID_COMMON_EXTERN int listen(uint16_t port = 0, int backlog = 10) const; QPID_COMMON_EXTERN int listen(const SocketAddress&, int backlog = 10) const; + /** Returns the "socket name" ie the address bound to + * the near end of the socket + */ + QPID_COMMON_EXTERN std::string getSockname() const; + + /** Returns the "peer name" ie the address bound to + * the remote end of the socket + */ + std::string getPeername() const; + /** * Returns an address (host and port) for the remote end of the * socket @@ -74,13 +84,16 @@ public: /** * Returns the full address of the connection: local and remote host and port. */ - QPID_COMMON_INLINE_EXTERN std::string getFullAddress() const { return getLocalAddress()+"-"+getPeerAddress(); } + QPID_COMMON_EXTERN std::string getFullAddress() const { return getLocalAddress()+"-"+getPeerAddress(); } + + QPID_COMMON_EXTERN uint16_t getLocalPort() const; + uint16_t getRemotePort() const; /** * Returns the error code stored in the socket. This may be used * to determine the result of a non-blocking connect. */ - QPID_COMMON_EXTERN int getError() const; + int getError() const; /** Accept a connection from a socket that is already listening * and has an incoming connection @@ -95,11 +108,8 @@ private: /** Create socket */ void createSocket(const SocketAddress&) const; - /** Construct socket with existing handle */ Socket(IOHandlePrivate*); - - mutable std::string localname; - mutable std::string peername; + mutable std::string connectname; mutable bool nonblocking; mutable bool nodelay; }; diff --git a/cpp/src/qpid/sys/SocketAddress.h b/cpp/src/qpid/sys/SocketAddress.h index dcca109d94..27b9642f2c 100644 --- a/cpp/src/qpid/sys/SocketAddress.h +++ b/cpp/src/qpid/sys/SocketAddress.h @@ -27,7 +27,6 @@ #include <string> struct addrinfo; -struct sockaddr; namespace qpid { namespace sys { @@ -42,19 +41,12 @@ public: QPID_COMMON_EXTERN SocketAddress& operator=(const SocketAddress&); QPID_COMMON_EXTERN ~SocketAddress(); - QPID_COMMON_EXTERN bool nextAddress(); - QPID_COMMON_EXTERN std::string asString(bool numeric=true) const; - QPID_COMMON_EXTERN void setAddrInfoPort(uint16_t port); - - QPID_COMMON_EXTERN static std::string asString(::sockaddr const * const addr, size_t addrlen); - QPID_COMMON_EXTERN static uint16_t getPort(::sockaddr const * const addr); - + std::string asString() const; private: std::string host; std::string port; mutable ::addrinfo* addrInfo; - mutable ::addrinfo* currentAddrInfo; }; }} diff --git a/cpp/src/qpid/sys/SslPlugin.cpp b/cpp/src/qpid/sys/SslPlugin.cpp index 471a0cef60..b0e791d60b 100644 --- a/cpp/src/qpid/sys/SslPlugin.cpp +++ b/cpp/src/qpid/sys/SslPlugin.cpp @@ -66,11 +66,12 @@ class SslProtocolFactory : public ProtocolFactory { public: SslProtocolFactory(const SslServerOptions&, int backlog, bool nodelay); void accept(Poller::shared_ptr, ConnectionCodec::Factory*); - void connect(Poller::shared_ptr, const std::string& host, const std::string& port, + void connect(Poller::shared_ptr, const std::string& host, int16_t port, ConnectionCodec::Factory*, boost::function2<void, int, std::string> failed); uint16_t getPort() const; + std::string getHost() const; bool supports(const std::string& capability); private: @@ -94,7 +95,7 @@ static struct SslPlugin : public Plugin { // Only provide to a Broker if (broker) { if (options.certDbPath.empty()) { - QPID_LOG(notice, "SSL plugin not enabled, you must set --ssl-cert-db to enable it."); + QPID_LOG(info, "SSL plugin not enabled, you must set --ssl-cert-db to enable it."); } else { try { ssl::initNSS(options, true); @@ -145,6 +146,10 @@ uint16_t SslProtocolFactory::getPort() const { return listeningPort; // Immutable no need for lock. } +std::string SslProtocolFactory::getHost() const { + return listener.getSockname(); +} + void SslProtocolFactory::accept(Poller::shared_ptr poller, ConnectionCodec::Factory* fact) { acceptor.reset( @@ -155,7 +160,7 @@ void SslProtocolFactory::accept(Poller::shared_ptr poller, void SslProtocolFactory::connect( Poller::shared_ptr poller, - const std::string& host, const std::string& port, + const std::string& host, int16_t port, ConnectionCodec::Factory* fact, ConnectFailedCallback failed) { diff --git a/cpp/src/qpid/sys/StateMonitor.h b/cpp/src/qpid/sys/StateMonitor.h index eac37a8543..5a92756f3a 100644 --- a/cpp/src/qpid/sys/StateMonitor.h +++ b/cpp/src/qpid/sys/StateMonitor.h @@ -41,9 +41,9 @@ class StateMonitor : public Waitable struct Set : public std::bitset<MaxEnum + 1> { Set() {} Set(Enum s) { set(s); } - Set(Enum s, Enum t) { std::bitset<MaxEnum + 1>::set(s).set(t); } - Set(Enum s, Enum t, Enum u) { std::bitset<MaxEnum + 1>::set(s).set(t).set(u); } - Set(Enum s, Enum t, Enum u, Enum v) { std::bitset<MaxEnum + 1>::set(s).set(t).set(u).set(v); } + Set(Enum s, Enum t) { set(s).set(t); } + Set(Enum s, Enum t, Enum u) { set(s).set(t).set(u); } + Set(Enum s, Enum t, Enum u, Enum v) { set(s).set(t).set(u).set(v); } }; @@ -60,13 +60,13 @@ class StateMonitor : public Waitable operator Enum() const { return state; } /** @pre Caller holds a ScopedLock */ - void waitFor(Enum s) { ScopedWait w(*this); while (s != state) wait(); } + void waitFor(Enum s) { ScopedWait(*this); while (s != state) wait(); } /** @pre Caller holds a ScopedLock */ - void waitFor(Set s) { ScopedWait w(*this); while (!s.test(state)) wait(); } + void waitFor(Set s) { ScopedWait(*this); while (!s.test(state)) wait(); } /** @pre Caller holds a ScopedLock */ - void waitNot(Enum s) { ScopedWait w(*this); while (s == state) wait(); } + void waitNot(Enum s) { ScopedWait(*this); while (s == state) wait(); } /** @pre Caller holds a ScopedLock */ - void waitNot(Set s) { ScopedWait w(*this); while (s.test(state)) wait(); } + void waitNot(Set s) { ScopedWait(*this); while (s.test(state)) wait(); } private: Enum state; diff --git a/cpp/src/qpid/sys/TCPIOPlugin.cpp b/cpp/src/qpid/sys/TCPIOPlugin.cpp index 85d8c1db87..a6528f9ad9 100644 --- a/cpp/src/qpid/sys/TCPIOPlugin.cpp +++ b/cpp/src/qpid/sys/TCPIOPlugin.cpp @@ -25,31 +25,31 @@ #include "qpid/Plugin.h" #include "qpid/sys/Socket.h" -#include "qpid/sys/SocketAddress.h" #include "qpid/sys/Poller.h" #include "qpid/broker/Broker.h" #include "qpid/log/Statement.h" #include <boost/bind.hpp> -#include <boost/ptr_container/ptr_vector.hpp> +#include <memory> namespace qpid { namespace sys { class AsynchIOProtocolFactory : public ProtocolFactory { const bool tcpNoDelay; - boost::ptr_vector<Socket> listeners; - boost::ptr_vector<AsynchAcceptor> acceptors; - uint16_t listeningPort; + Socket listener; + const uint16_t listeningPort; + std::auto_ptr<AsynchAcceptor> acceptor; public: - AsynchIOProtocolFactory(const std::string& host, const std::string& port, int backlog, bool nodelay); + AsynchIOProtocolFactory(int16_t port, int backlog, bool nodelay); void accept(Poller::shared_ptr, ConnectionCodec::Factory*); - void connect(Poller::shared_ptr, const std::string& host, const std::string& port, + void connect(Poller::shared_ptr, const std::string& host, int16_t port, ConnectionCodec::Factory*, ConnectFailedCallback); uint16_t getPort() const; + std::string getHost() const; private: void established(Poller::shared_ptr, const Socket&, ConnectionCodec::Factory*, @@ -61,49 +61,23 @@ class AsynchIOProtocolFactory : public ProtocolFactory { static class TCPIOPlugin : public Plugin { void earlyInitialize(Target&) { } - + void initialize(Target& target) { broker::Broker* broker = dynamic_cast<broker::Broker*>(&target); // Only provide to a Broker if (broker) { const broker::Broker::Options& opts = broker->getOptions(); - ProtocolFactory::shared_ptr protocolt( - new AsynchIOProtocolFactory( - "", boost::lexical_cast<std::string>(opts.port), - opts.connectionBacklog, - opts.tcpNoDelay)); - QPID_LOG(notice, "Listening on TCP/TCP6 port " << protocolt->getPort()); - broker->registerProtocolFactory("tcp", protocolt); + ProtocolFactory::shared_ptr protocol(new AsynchIOProtocolFactory(opts.port, opts.connectionBacklog, + opts.tcpNoDelay)); + QPID_LOG(notice, "Listening on TCP port " << protocol->getPort()); + broker->registerProtocolFactory("tcp", protocol); } } } tcpPlugin; -AsynchIOProtocolFactory::AsynchIOProtocolFactory(const std::string& host, const std::string& port, int backlog, bool nodelay) : - tcpNoDelay(nodelay) -{ - SocketAddress sa(host, port); - - // We must have at least one resolved address - QPID_LOG(info, "Listening to: " << sa.asString()) - Socket* s = new Socket; - uint16_t lport = s->listen(sa, backlog); - QPID_LOG(debug, "Listened to: " << lport); - listeners.push_back(s); - - listeningPort = lport; - - // Try any other resolved addresses - while (sa.nextAddress()) { - // Hack to ensure that all listening connections are on the same port - sa.setAddrInfoPort(listeningPort); - QPID_LOG(info, "Listening to: " << sa.asString()) - Socket* s = new Socket; - uint16_t lport = s->listen(sa, backlog); - QPID_LOG(debug, "Listened to: " << lport); - listeners.push_back(s); - } - -} +AsynchIOProtocolFactory::AsynchIOProtocolFactory(int16_t port, int backlog, bool nodelay) : + tcpNoDelay(nodelay), listeningPort(listener.listen(port, backlog)) +{} void AsynchIOProtocolFactory::established(Poller::shared_ptr poller, const Socket& s, ConnectionCodec::Factory* f, bool isClient) { @@ -133,14 +107,16 @@ uint16_t AsynchIOProtocolFactory::getPort() const { return listeningPort; // Immutable no need for lock. } +std::string AsynchIOProtocolFactory::getHost() const { + return listener.getSockname(); +} + void AsynchIOProtocolFactory::accept(Poller::shared_ptr poller, ConnectionCodec::Factory* fact) { - for (unsigned i = 0; i<listeners.size(); ++i) { - acceptors.push_back( - AsynchAcceptor::create(listeners[i], - boost::bind(&AsynchIOProtocolFactory::established, this, poller, _1, fact, false))); - acceptors[i].start(poller); - } + acceptor.reset( + AsynchAcceptor::create(listener, + boost::bind(&AsynchIOProtocolFactory::established, this, poller, _1, fact, false))); + acceptor->start(poller); } void AsynchIOProtocolFactory::connectFailed( @@ -154,7 +130,7 @@ void AsynchIOProtocolFactory::connectFailed( void AsynchIOProtocolFactory::connect( Poller::shared_ptr poller, - const std::string& host, const std::string& port, + const std::string& host, int16_t port, ConnectionCodec::Factory* fact, ConnectFailedCallback failed) { @@ -163,8 +139,8 @@ void AsynchIOProtocolFactory::connect( // upon connection failure or by the AsynchIO upon connection // shutdown. The allocated AsynchConnector frees itself when it // is no longer needed. + Socket* socket = new Socket(); - try { AsynchConnector* c = AsynchConnector::create( *socket, host, @@ -174,12 +150,6 @@ void AsynchIOProtocolFactory::connect( boost::bind(&AsynchIOProtocolFactory::connectFailed, this, _1, _2, _3, failed)); c->start(poller); - } catch (std::exception&) { - // TODO: Design question - should we do the error callback and also throw? - int errCode = socket->getError(); - connectFailed(*socket, errCode, strError(errCode), failed); - throw; - } } }} // namespace qpid::sys diff --git a/cpp/src/qpid/sys/Timer.cpp b/cpp/src/qpid/sys/Timer.cpp index 47752e4584..a97ccd1bd1 100644 --- a/cpp/src/qpid/sys/Timer.cpp +++ b/cpp/src/qpid/sys/Timer.cpp @@ -75,12 +75,6 @@ void TimerTask::cancel() { cancelled = true; } -void TimerTask::setFired() { - // Set nextFireTime to just before now, making readyToFire() true. - nextFireTime = AbsTime(sys::now(), Duration(-1)); -} - - Timer::Timer() : active(false), late(50 * TIME_MSEC), @@ -137,14 +131,12 @@ void Timer::run() bool warningsEnabled; QPID_LOG_TEST(warning, warningsEnabled); if (warningsEnabled) { - if (overrun > overran) { - if (delay > overran) // if delay is significant to an overrun. - warn.lateAndOverran(t->name, delay, overrun, Duration(start, end)); - else - warn.overran(t->name, overrun, Duration(start, end)); - } + if (delay > late && overrun > overran) + warn.lateAndOverran(t->name, delay, overrun, Duration(start, end)); else if (delay > late) warn.late(t->name, delay); + else if (overrun > overran) + warn.overran(t->name, overrun, Duration(start, end)); } continue; } else { @@ -191,11 +183,7 @@ void Timer::stop() // Allow subclasses to override behavior when firing a task. void Timer::fire(boost::intrusive_ptr<TimerTask> t) { - try { - t->fireTask(); - } catch (const std::exception& e) { - QPID_LOG(error, "Exception thrown by timer task " << t->getName() << ": " << e.what()); - } + t->fireTask(); } // Provided for subclasses: called when a task is droped. diff --git a/cpp/src/qpid/sys/Timer.h b/cpp/src/qpid/sys/Timer.h index fccb17dbc2..98ba39ce38 100644 --- a/cpp/src/qpid/sys/Timer.h +++ b/cpp/src/qpid/sys/Timer.h @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -64,10 +64,6 @@ class TimerTask : public RefCounted { std::string getName() const { return name; } - // Move the nextFireTime so readyToFire is true. - // Used by the cluster, where tasks are fired on cluster events, not on local time. - QPID_COMMON_EXTERN void setFired(); - protected: // Must be overridden with callback virtual void fire() = 0; diff --git a/cpp/src/qpid/sys/TimerWarnings.cpp b/cpp/src/qpid/sys/TimerWarnings.cpp index 85e26da54a..48a56eb472 100644 --- a/cpp/src/qpid/sys/TimerWarnings.cpp +++ b/cpp/src/qpid/sys/TimerWarnings.cpp @@ -56,22 +56,20 @@ void TimerWarnings::log() { std::string task = i->first; TaskStats& stats = i->second; if (stats.lateDelay.count) - QPID_LOG(info, task << " task late " + QPID_LOG(warning, task << " task late " << stats.lateDelay.count << " times by " << stats.lateDelay.average()/TIME_MSEC << "ms on average."); - if (stats.overranOverrun.count) - QPID_LOG(info, task << " task overran " + QPID_LOG(warning, task << " task overran " << stats.overranOverrun.count << " times by " << stats.overranOverrun.average()/TIME_MSEC << "ms (taking " << stats.overranTime.average() << "ns) on average."); - if (stats.lateAndOverranOverrun.count) - QPID_LOG(info, task << " task late and overran " - << stats.lateAndOverranOverrun.count << " times: late " - << stats.lateAndOverranDelay.average()/TIME_MSEC << "ms, overran " - << stats.lateAndOverranOverrun.average()/TIME_MSEC << "ms (taking " - << stats.lateAndOverranTime.average() << "ns) on average."); + if (stats.lateAndOverranDelay.count) + QPID_LOG(warning, task << " task overran " + << stats.overranOverrun.count << " times by " + << stats.overranOverrun.average()/TIME_MSEC << "ms (taking " + << stats.overranTime.average() << "ns) on average."); } nextReport = AbsTime(now(), interval); diff --git a/cpp/src/qpid/sys/alloca.h b/cpp/src/qpid/sys/alloca.h index b3f59b7c3f..e989670e4f 100644 --- a/cpp/src/qpid/sys/alloca.h +++ b/cpp/src/qpid/sys/alloca.h @@ -21,22 +21,19 @@ * */ -#if (defined(_WINDOWS) || defined (WIN32)) -# include <malloc.h> - -# if defined(_MSC_VER) -# ifdef alloc -# undef alloc -# endif -# define alloc _alloc -# ifdef alloca -# undef alloca -# endif -# define alloca _alloca -# endif +#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> +#include <alloca.h> #endif #endif /*!QPID_SYS_ALLOCA_H*/ diff --git a/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp b/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp index 249b769051..454ce62495 100644 --- a/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp +++ b/cpp/src/qpid/sys/cyrus/CyrusSecurityLayer.cpp @@ -57,7 +57,6 @@ size_t CyrusSecurityLayer::decode(const char* input, size_t size) copied += count; decodeBuffer.position += count; size_t decodedSize = codec->decode(decodeBuffer.data, decodeBuffer.position); - if (decodedSize == 0) break; if (decodedSize < decodeBuffer.position) { ::memmove(decodeBuffer.data, decodeBuffer.data + decodedSize, decodeBuffer.position - decodedSize); } @@ -107,7 +106,7 @@ size_t CyrusSecurityLayer::encode(const char* buffer, size_t size) bool CyrusSecurityLayer::canEncode() { - return codec && (encrypted || codec->canEncode()); + return encrypted || codec->canEncode(); } void CyrusSecurityLayer::init(qpid::sys::Codec* c) diff --git a/cpp/src/qpid/sys/epoll/EpollPoller.cpp b/cpp/src/qpid/sys/epoll/EpollPoller.cpp index dcc9d9181c..9ad05c71a3 100644 --- a/cpp/src/qpid/sys/epoll/EpollPoller.cpp +++ b/cpp/src/qpid/sys/epoll/EpollPoller.cpp @@ -384,12 +384,7 @@ void PollerPrivate::resetMode(PollerHandlePrivate& eh) { epe.data.u64 = 0; // Keep valgrind happy epe.data.ptr = &eh; - int rc = ::epoll_ctl(epollFd, EPOLL_CTL_MOD, eh.fd(), &epe); - // If something has closed the fd in the meantime try adding it back - if (rc ==-1 && errno == ENOENT) { - rc = ::epoll_ctl(epollFd, EPOLL_CTL_ADD, eh.fd(), &epe); - } - QPID_POSIX_CHECK(rc); + QPID_POSIX_CHECK(::epoll_ctl(epollFd, EPOLL_CTL_MOD, eh.fd(), &epe)); eh.setActive(); return; diff --git a/cpp/src/qpid/sys/posix/AsynchIO.cpp b/cpp/src/qpid/sys/posix/AsynchIO.cpp index dab8bd09c6..119a6aa8a4 100644 --- a/cpp/src/qpid/sys/posix/AsynchIO.cpp +++ b/cpp/src/qpid/sys/posix/AsynchIO.cpp @@ -149,12 +149,11 @@ private: ConnectedCallback connCallback; FailedCallback failCallback; const Socket& socket; - SocketAddress sa; public: AsynchConnector(const Socket& socket, - const std::string& hostname, - const std::string& port, + std::string hostname, + uint16_t port, ConnectedCallback connCb, FailedCallback failCb); void start(Poller::shared_ptr poller); @@ -162,8 +161,8 @@ public: }; AsynchConnector::AsynchConnector(const Socket& s, - const std::string& hostname, - const std::string& port, + std::string hostname, + uint16_t port, ConnectedCallback connCb, FailedCallback failCb) : DispatchHandle(s, @@ -172,13 +171,11 @@ AsynchConnector::AsynchConnector(const Socket& s, boost::bind(&AsynchConnector::connComplete, this, _1)), connCallback(connCb), failCallback(failCb), - socket(s), - sa(hostname, port) + socket(s) { socket.setNonblocking(); - + SocketAddress sa(hostname, boost::lexical_cast<std::string>(port)); // Note, not catching any exceptions here, also has effect of destructing - QPID_LOG(info, "Connecting: " << sa.asString()); socket.connect(sa); } @@ -194,26 +191,11 @@ void AsynchConnector::stop() void AsynchConnector::connComplete(DispatchHandle& h) { + h.stopWatch(); int errCode = socket.getError(); if (errCode == 0) { - h.stopWatch(); connCallback(socket); } else { - // Retry while we cause an immediate exception - // (asynch failure will be handled by re-entering here at the top) - while (sa.nextAddress()) { - try { - // Try next address without deleting ourselves - QPID_LOG(debug, "Ignored socket connect error: " << strError(errCode)); - QPID_LOG(info, "Retrying connect: " << sa.asString()); - socket.connect(sa); - return; - } catch (const std::exception& e) { - QPID_LOG(debug, "Ignored socket connect exception: " << e.what()); - } - errCode = socket.getError(); - } - h.stopWatch(); failCallback(socket, errCode, strError(errCode)); } DispatchHandle::doDelete(); @@ -607,8 +589,8 @@ AsynchAcceptor* AsynchAcceptor::create(const Socket& s, } AsynchConnector* AsynchConnector::create(const Socket& s, - const std::string& hostname, - const std::string& port, + std::string hostname, + uint16_t port, ConnectedCallback connCb, FailedCallback failCb) { diff --git a/cpp/src/qpid/sys/posix/LockFile.cpp b/cpp/src/qpid/sys/posix/LockFile.cpp index f5a6c292cb..1862ff6ac9 100755 --- a/cpp/src/qpid/sys/posix/LockFile.cpp +++ b/cpp/src/qpid/sys/posix/LockFile.cpp @@ -58,7 +58,8 @@ LockFile::~LockFile() { if (impl) { int f = impl->fd; if (f >= 0) { - (void) ::lockf(f, F_ULOCK, 0); // Suppress warnings about ignoring return value. + int unused_ret; + unused_ret = ::lockf(f, F_ULOCK, 0); // Suppress warnings about ignoring return value. ::close(f); impl->fd = -1; } diff --git a/cpp/src/qpid/sys/posix/Socket.cpp b/cpp/src/qpid/sys/posix/Socket.cpp index 4a6dc66f80..7b906f33e8 100644 --- a/cpp/src/qpid/sys/posix/Socket.cpp +++ b/cpp/src/qpid/sys/posix/Socket.cpp @@ -7,9 +7,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -34,35 +34,65 @@ #include <netdb.h> #include <cstdlib> #include <string.h> +#include <iostream> + +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp> namespace qpid { namespace sys { namespace { -std::string getName(int fd, bool local) +std::string getName(int fd, bool local, bool includeService = false) { - ::sockaddr_storage name_s; // big enough for any socket address - ::sockaddr* name = (::sockaddr*)&name_s; - ::socklen_t namelen = sizeof(name_s); - + ::sockaddr_storage name; // big enough for any socket address + ::socklen_t namelen = sizeof(name); + + int result = -1; if (local) { - QPID_POSIX_CHECK( ::getsockname(fd, name, &namelen) ); + result = ::getsockname(fd, (::sockaddr*)&name, &namelen); } else { - QPID_POSIX_CHECK( ::getpeername(fd, name, &namelen) ); + result = ::getpeername(fd, (::sockaddr*)&name, &namelen); } - return SocketAddress::asString(name, namelen); + QPID_POSIX_CHECK(result); + + char servName[NI_MAXSERV]; + char dispName[NI_MAXHOST]; + if (includeService) { + if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName), + servName, sizeof(servName), + NI_NUMERICHOST | NI_NUMERICSERV) != 0) + throw QPID_POSIX_ERROR(rc); + return std::string(dispName) + ":" + std::string(servName); + + } else { + if (int rc=::getnameinfo((::sockaddr*)&name, namelen, dispName, sizeof(dispName), 0, 0, NI_NUMERICHOST) != 0) + throw QPID_POSIX_ERROR(rc); + return dispName; + } } -uint16_t getLocalPort(int fd) +std::string getService(int fd, bool local) { - ::sockaddr_storage name_s; // big enough for any socket address - ::sockaddr* name = (::sockaddr*)&name_s; - ::socklen_t namelen = sizeof(name_s); + ::sockaddr_storage name; // big enough for any socket address + ::socklen_t namelen = sizeof(name); + + int result = -1; + if (local) { + result = ::getsockname(fd, (::sockaddr*)&name, &namelen); + } else { + result = ::getpeername(fd, (::sockaddr*)&name, &namelen); + } - QPID_POSIX_CHECK( ::getsockname(fd, name, &namelen) ); + QPID_POSIX_CHECK(result); - return SocketAddress::getPort(name); + char servName[NI_MAXSERV]; + if (int rc=::getnameinfo((::sockaddr*)&name, namelen, 0, 0, + servName, sizeof(servName), + NI_NUMERICHOST | NI_NUMERICSERV) != 0) + throw QPID_POSIX_ERROR(rc); + return servName; } } @@ -89,11 +119,6 @@ void Socket::createSocket(const SocketAddress& sa) const try { if (nonblocking) setNonblocking(); if (nodelay) setTcpNoDelay(); - if (getAddrInfo(sa).ai_family == AF_INET6) { - int flag = 1; - int result = ::setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&flag, sizeof(flag)); - QPID_POSIX_CHECK(result); - } } catch (std::exception&) { ::close(s); socket = -1; @@ -101,18 +126,13 @@ void Socket::createSocket(const SocketAddress& sa) const } } -Socket* Socket::createSameTypeSocket() const { - int& socket = impl->fd; - // Socket currently has no actual socket attached - if (socket == -1) - return new Socket; - - ::sockaddr_storage sa; - ::socklen_t salen = sizeof(sa); - QPID_POSIX_CHECK(::getsockname(socket, (::sockaddr*)&sa, &salen)); - int s = ::socket(sa.ss_family, SOCK_STREAM, 0); // Currently only work with SOCK_STREAM - if (s < 0) throw QPID_POSIX_ERROR(errno); - return new Socket(new IOHandlePrivate(s)); +void Socket::setTimeout(const Duration& interval) const +{ + const int& socket = impl->fd; + struct timeval tv; + toTimeval(tv, interval); + setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); } void Socket::setNonblocking() const { @@ -129,27 +149,20 @@ void Socket::setTcpNoDelay() const nodelay = true; if (socket != -1) { int flag = 1; - int result = ::setsockopt(impl->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); + int result = setsockopt(impl->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); QPID_POSIX_CHECK(result); } } -void Socket::connect(const std::string& host, const std::string& port) const +void Socket::connect(const std::string& host, uint16_t port) const { - SocketAddress sa(host, port); + SocketAddress sa(host, boost::lexical_cast<std::string>(port)); connect(sa); } void Socket::connect(const SocketAddress& addr) const { - // The display name for an outbound connection needs to be the name that was specified - // for the address rather than a resolved IP address as we don't know which of - // the IP addresses is actually the one that will be connected to. - peername = addr.asString(false); - - // However the string we compare with the local port must be numeric or it might not - // match when it should as getLocalAddress() will always be numeric - std::string connectname = addr.asString(); + connectname = addr.asString(); createSocket(addr); @@ -157,24 +170,7 @@ void Socket::connect(const SocketAddress& addr) const // TODO the correct thing to do here is loop on failure until you've used all the returned addresses if ((::connect(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) < 0) && (errno != EINPROGRESS)) { - throw Exception(QPID_MSG(strError(errno) << ": " << peername)); - } - // When connecting to a port on the same host which no longer has - // a process associated with it, the OS occasionally chooses the - // remote port (which is unoccupied) as the port to bind the local - // end of the socket, resulting in a "circular" connection. - // - // This seems like something the OS should prevent but I have - // confirmed that sporadic hangs in - // cluster_tests.LongTests.test_failover on RHEL5 are caused by - // such a circular connection. - // - // Raise an error if we see such a connection, since we know there is - // no listener on the peer address. - // - if (getLocalAddress() == connectname) { - close(); - throw Exception(QPID_MSG("Connection refused: " << peername)); + throw Exception(QPID_MSG(strError(errno) << ": " << connectname)); } } @@ -187,9 +183,9 @@ Socket::close() const socket = -1; } -int Socket::listen(const std::string& host, const std::string& port, int backlog) const +int Socket::listen(uint16_t port, int backlog) const { - SocketAddress sa(host, port); + SocketAddress sa("", boost::lexical_cast<std::string>(port)); return listen(sa, backlog); } @@ -199,24 +195,26 @@ int Socket::listen(const SocketAddress& sa, int backlog) const const int& socket = impl->fd; int yes=1; - QPID_POSIX_CHECK(::setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))); + QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))); if (::bind(socket, getAddrInfo(sa).ai_addr, getAddrInfo(sa).ai_addrlen) < 0) throw Exception(QPID_MSG("Can't bind to port " << sa.asString() << ": " << strError(errno))); if (::listen(socket, backlog) < 0) throw Exception(QPID_MSG("Can't listen on port " << sa.asString() << ": " << strError(errno))); - return getLocalPort(socket); + struct sockaddr_in name; + socklen_t namelen = sizeof(name); + if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0) + throw QPID_POSIX_ERROR(errno); + + return ntohs(name.sin_port); } Socket* Socket::accept() const { int afd = ::accept(impl->fd, 0, 0); - if ( afd >= 0) { - Socket* s = new Socket(new IOHandlePrivate(afd)); - s->localname = localname; - return s; - } + if ( afd >= 0) + return new Socket(new IOHandlePrivate(afd)); else if (errno == EAGAIN) return 0; else throw QPID_POSIX_ERROR(errno); @@ -232,20 +230,37 @@ int Socket::write(const void *buf, size_t count) const return ::write(impl->fd, buf, count); } +std::string Socket::getSockname() const +{ + return getName(impl->fd, true); +} + +std::string Socket::getPeername() const +{ + return getName(impl->fd, false); +} + std::string Socket::getPeerAddress() const { - if (peername.empty()) { - peername = getName(impl->fd, false); + if (connectname.empty()) { + connectname = getName(impl->fd, false, true); } - return peername; + return connectname; } std::string Socket::getLocalAddress() const { - if (localname.empty()) { - localname = getName(impl->fd, true); - } - return localname; + return getName(impl->fd, true, true); +} + +uint16_t Socket::getLocalPort() const +{ + return std::atoi(getService(impl->fd, true).c_str()); +} + +uint16_t Socket::getRemotePort() const +{ + return std::atoi(getService(impl->fd, true).c_str()); } int Socket::getError() const diff --git a/cpp/src/qpid/sys/posix/SocketAddress.cpp b/cpp/src/qpid/sys/posix/SocketAddress.cpp index 077942ef2f..8f5f29d793 100644 --- a/cpp/src/qpid/sys/posix/SocketAddress.cpp +++ b/cpp/src/qpid/sys/posix/SocketAddress.cpp @@ -21,13 +21,11 @@ #include "qpid/sys/SocketAddress.h" -#include "qpid/Exception.h" -#include "qpid/Msg.h" +#include "qpid/sys/posix/check.h" #include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> #include <string.h> +#include <netdb.h> namespace qpid { namespace sys { @@ -48,9 +46,15 @@ SocketAddress::SocketAddress(const SocketAddress& sa) : SocketAddress& SocketAddress::operator=(const SocketAddress& sa) { - SocketAddress temp(sa); + if (&sa != this) { + host = sa.host; + port = sa.port; - std::swap(temp, *this); + if (addrInfo) { + ::freeaddrinfo(addrInfo); + addrInfo = 0; + } + } return *this; } @@ -61,61 +65,9 @@ SocketAddress::~SocketAddress() } } -std::string SocketAddress::asString(::sockaddr const * const addr, size_t addrlen) -{ - char servName[NI_MAXSERV]; - char dispName[NI_MAXHOST]; - if (int rc=::getnameinfo(addr, addrlen, - dispName, sizeof(dispName), - servName, sizeof(servName), - NI_NUMERICHOST | NI_NUMERICSERV) != 0) - throw qpid::Exception(QPID_MSG(gai_strerror(rc))); - std::string s; - switch (addr->sa_family) { - case AF_INET: s += dispName; break; - case AF_INET6: s += "["; s += dispName; s+= "]"; break; - default: throw Exception(QPID_MSG("Unexpected socket type")); - } - s += ":"; - s += servName; - return s; -} - -uint16_t SocketAddress::getPort(::sockaddr const * const addr) +std::string SocketAddress::asString() const { - switch (addr->sa_family) { - case AF_INET: return ntohs(((::sockaddr_in*)addr)->sin_port); - case AF_INET6: return ntohs(((::sockaddr_in6*)addr)->sin6_port); - default:throw Exception(QPID_MSG("Unexpected socket type")); - } -} - -std::string SocketAddress::asString(bool numeric) const -{ - if (!numeric) - return host + ":" + port; - // Canonicalise into numeric id - const ::addrinfo& ai = getAddrInfo(*this); - - return asString(ai.ai_addr, ai.ai_addrlen); -} - -bool SocketAddress::nextAddress() { - bool r = currentAddrInfo->ai_next != 0; - if (r) - currentAddrInfo = currentAddrInfo->ai_next; - return r; -} - -void SocketAddress::setAddrInfoPort(uint16_t port) { - if (!currentAddrInfo) return; - - ::addrinfo& ai = *currentAddrInfo; - switch (ai.ai_family) { - case AF_INET: ((::sockaddr_in*)ai.ai_addr)->sin_port = htons(port); return; - case AF_INET6:((::sockaddr_in6*)ai.ai_addr)->sin6_port = htons(port); return; - default: throw Exception(QPID_MSG("Unexpected socket type")); - } + return host + ":" + port; } const ::addrinfo& getAddrInfo(const SocketAddress& sa) @@ -123,8 +75,7 @@ const ::addrinfo& getAddrInfo(const SocketAddress& sa) if (!sa.addrInfo) { ::addrinfo hints; ::memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_ADDRCONFIG; // Only use protocols that we have configured interfaces for - hints.ai_family = AF_UNSPEC; // Allow both IPv4 and IPv6 + hints.ai_family = AF_INET; // Change this to support IPv6 hints.ai_socktype = SOCK_STREAM; const char* node = 0; @@ -137,11 +88,10 @@ const ::addrinfo& getAddrInfo(const SocketAddress& sa) int n = ::getaddrinfo(node, service, &hints, &sa.addrInfo); if (n != 0) - throw Exception(QPID_MSG("Cannot resolve " << sa.asString(false) << ": " << ::gai_strerror(n))); - sa.currentAddrInfo = sa.addrInfo; + throw Exception(QPID_MSG("Cannot resolve " << sa.host << ": " << ::gai_strerror(n))); } - return *sa.currentAddrInfo; + return *sa.addrInfo; } }} diff --git a/cpp/src/qpid/sys/posix/Thread.cpp b/cpp/src/qpid/sys/posix/Thread.cpp index a1d6396763..b466733260 100644 --- a/cpp/src/qpid/sys/posix/Thread.cpp +++ b/cpp/src/qpid/sys/posix/Thread.cpp @@ -37,8 +37,7 @@ void* runRunnable(void* p) } } -class ThreadPrivate { -public: +struct ThreadPrivate { pthread_t thread; ThreadPrivate(Runnable* runnable) { diff --git a/cpp/src/qpid/sys/posix/Time.cpp b/cpp/src/qpid/sys/posix/Time.cpp index 9661f0c5e8..b3858279b4 100644 --- a/cpp/src/qpid/sys/posix/Time.cpp +++ b/cpp/src/qpid/sys/posix/Time.cpp @@ -27,7 +27,6 @@ #include <stdio.h> #include <sys/time.h> #include <unistd.h> -#include <iomanip> namespace { int64_t max_abstime() { return std::numeric_limits<int64_t>::max(); } @@ -104,12 +103,6 @@ void outputFormattedNow(std::ostream& o) { o << " "; } -void outputHiresNow(std::ostream& o) { - ::timespec time; - ::clock_gettime(CLOCK_REALTIME, &time); - o << time.tv_sec << "." << std::setw(9) << std::setfill('0') << time.tv_nsec << "s "; -} - void sleep(int secs) { ::sleep(secs); } diff --git a/cpp/src/qpid/sys/rdma/RdmaIO.cpp b/cpp/src/qpid/sys/rdma/RdmaIO.cpp index 78bcdec68e..c80c94cba6 100644 --- a/cpp/src/qpid/sys/rdma/RdmaIO.cpp +++ b/cpp/src/qpid/sys/rdma/RdmaIO.cpp @@ -140,8 +140,8 @@ namespace Rdma { // Prepost recv buffers before we go any further qp->allocateRecvBuffers(recvBufferCount, bufferSize+FrameHeaderSize); - // Create xmit buffers, reserve space for frame header. - qp->createSendBuffers(xmitBufferCount, bufferSize, FrameHeaderSize); + // Create xmit buffers + qp->createSendBuffers(xmitBufferCount, bufferSize+FrameHeaderSize); } AsynchIO::~AsynchIO() { @@ -210,14 +210,12 @@ namespace Rdma { } break; case 1: - if (!buff) - buff = getSendBuffer(); + Buffer* ob = buff ? buff : getSendBuffer(); // Add FrameHeader after frame data FrameHeader header(credit); - assert(buff->dataCount() <= buff->byteCount()); // ensure app data doesn't impinge on reserved space. - ::memcpy(buff->bytes()+buff->dataCount(), &header, FrameHeaderSize); - buff->dataCount(buff->dataCount()+FrameHeaderSize); - qp->postSend(buff); + ::memcpy(ob->bytes()+ob->dataCount(), &header, FrameHeaderSize); + ob->dataCount(ob->dataCount()+FrameHeaderSize); + qp->postSend(ob); break; } } diff --git a/cpp/src/qpid/sys/rdma/rdma_wrap.cpp b/cpp/src/qpid/sys/rdma/rdma_wrap.cpp index efe454c5be..6d38c42502 100644 --- a/cpp/src/qpid/sys/rdma/rdma_wrap.cpp +++ b/cpp/src/qpid/sys/rdma/rdma_wrap.cpp @@ -50,9 +50,8 @@ namespace Rdma { return count; } - Buffer::Buffer(uint32_t lkey, char* bytes, const int32_t byteCount, - const int32_t reserve) : - bufferSize(byteCount + reserve), reserved(reserve) + Buffer::Buffer(uint32_t lkey, char* bytes, const int32_t byteCount) : + bufferSize(byteCount) { sge.addr = (uintptr_t) bytes; sge.length = 0; @@ -164,21 +163,21 @@ namespace Rdma { } // Create buffers to use for writing - void QueuePair::createSendBuffers(int sendBufferCount, int bufferSize, int reserved) + void QueuePair::createSendBuffers(int sendBufferCount, int bufferSize) { assert(!smr); // Round up buffersize to cacheline (64 bytes) - int dataLength = (bufferSize+reserved+63) & (~63); + bufferSize = (bufferSize+63) & (~63); // Allocate memory block for all receive buffers - char* mem = new char [sendBufferCount * dataLength]; - smr = regMr(pd.get(), mem, sendBufferCount * dataLength, ::IBV_ACCESS_LOCAL_WRITE); + char* mem = new char [sendBufferCount * bufferSize]; + smr = regMr(pd.get(), mem, sendBufferCount * bufferSize, ::IBV_ACCESS_LOCAL_WRITE); sendBuffers.reserve(sendBufferCount); freeBuffers.reserve(sendBufferCount); for (int i = 0; i<sendBufferCount; ++i) { // Allocate xmit buffer - sendBuffers.push_back(Buffer(smr->lkey, &mem[i*dataLength], bufferSize, reserved)); + sendBuffers.push_back(Buffer(smr->lkey, &mem[i*bufferSize], bufferSize)); freeBuffers.push_back(i); } } diff --git a/cpp/src/qpid/sys/rdma/rdma_wrap.h b/cpp/src/qpid/sys/rdma/rdma_wrap.h index 8e3429027b..28bddd2165 100644 --- a/cpp/src/qpid/sys/rdma/rdma_wrap.h +++ b/cpp/src/qpid/sys/rdma/rdma_wrap.h @@ -57,9 +57,8 @@ namespace Rdma { void dataCount(int32_t); private: - Buffer(uint32_t lkey, char* bytes, const int32_t byteCount, const int32_t reserve=0); + Buffer(uint32_t lkey, char* bytes, const int32_t byteCount); int32_t bufferSize; - int32_t reserved; // for framing header ::ibv_sge sge; }; @@ -67,9 +66,8 @@ namespace Rdma { return (char*) sge.addr; } - /** return the number of bytes available for application data */ inline int32_t Buffer::byteCount() const { - return bufferSize - reserved; + return bufferSize; } inline int32_t Buffer::dataCount() const { @@ -77,8 +75,6 @@ namespace Rdma { } inline void Buffer::dataCount(int32_t s) { - // catch any attempt to overflow a buffer - assert(s <= bufferSize + reserved); sge.length = s; } @@ -140,7 +136,7 @@ namespace Rdma { typedef boost::intrusive_ptr<QueuePair> intrusive_ptr; // Create a buffers to use for writing - void createSendBuffers(int sendBufferCount, int dataSize, int headerSize); + void createSendBuffers(int sendBufferCount, int bufferSize); // Get a send buffer Buffer* getSendBuffer(); diff --git a/cpp/src/qpid/sys/ssl/SslHandler.h b/cpp/src/qpid/sys/ssl/SslHandler.h index 400fa317fd..a340109966 100644 --- a/cpp/src/qpid/sys/ssl/SslHandler.h +++ b/cpp/src/qpid/sys/ssl/SslHandler.h @@ -35,7 +35,7 @@ namespace sys { namespace ssl { class SslIO; -struct SslIOBufferBase; +class SslIOBufferBase; class SslSocket; class SslHandler : public OutputControl { diff --git a/cpp/src/qpid/sys/ssl/SslIo.cpp b/cpp/src/qpid/sys/ssl/SslIo.cpp index 734ebb483a..a58a137473 100644 --- a/cpp/src/qpid/sys/ssl/SslIo.cpp +++ b/cpp/src/qpid/sys/ssl/SslIo.cpp @@ -117,7 +117,7 @@ void SslAcceptor::readable(DispatchHandle& h) { SslConnector::SslConnector(const SslSocket& s, Poller::shared_ptr poller, std::string hostname, - std::string port, + uint16_t port, ConnectedCallback connCb, FailedCallback failCb) : DispatchHandle(s, diff --git a/cpp/src/qpid/sys/ssl/SslIo.h b/cpp/src/qpid/sys/ssl/SslIo.h index 8785852c24..53ac69d8d6 100644 --- a/cpp/src/qpid/sys/ssl/SslIo.h +++ b/cpp/src/qpid/sys/ssl/SslIo.h @@ -73,7 +73,7 @@ public: SslConnector(const SslSocket& socket, Poller::shared_ptr poller, std::string hostname, - std::string port, + uint16_t port, ConnectedCallback connCb, FailedCallback failCb = 0); diff --git a/cpp/src/qpid/sys/ssl/SslSocket.cpp b/cpp/src/qpid/sys/ssl/SslSocket.cpp index f7483a220c..01e2658877 100644 --- a/cpp/src/qpid/sys/ssl/SslSocket.cpp +++ b/cpp/src/qpid/sys/ssl/SslSocket.cpp @@ -158,7 +158,7 @@ void SslSocket::setNonblocking() const PR_SetSocketOption(socket, &option); } -void SslSocket::connect(const std::string& host, const std::string& port) const +void SslSocket::connect(const std::string& host, uint16_t port) const { std::stringstream namestream; namestream << host << ":" << port; @@ -180,7 +180,7 @@ void SslSocket::connect(const std::string& host, const std::string& port) const PRHostEnt hostEntry; PR_CHECK(PR_GetHostByName(host.data(), hostBuffer, PR_NETDB_BUF_SIZE, &hostEntry)); PRNetAddr address; - int value = PR_EnumerateHostEnt(0, &hostEntry, boost::lexical_cast<PRUint16>(port), &address); + int value = PR_EnumerateHostEnt(0, &hostEntry, port, &address); if (value < 0) { throw Exception(QPID_MSG("Error getting address for host: " << ErrorString())); } else if (value == 0) { diff --git a/cpp/src/qpid/sys/ssl/SslSocket.h b/cpp/src/qpid/sys/ssl/SslSocket.h index 993859495b..25712c98d5 100644 --- a/cpp/src/qpid/sys/ssl/SslSocket.h +++ b/cpp/src/qpid/sys/ssl/SslSocket.h @@ -53,7 +53,7 @@ public: * NSSInit().*/ void setCertName(const std::string& certName); - void connect(const std::string& host, const std::string& port) const; + void connect(const std::string& host, uint16_t port) const; void close() const; diff --git a/cpp/src/qpid/sys/windows/AsynchIO.cpp b/cpp/src/qpid/sys/windows/AsynchIO.cpp index 30378d4c5f..38d8842521 100644 --- a/cpp/src/qpid/sys/windows/AsynchIO.cpp +++ b/cpp/src/qpid/sys/windows/AsynchIO.cpp @@ -30,7 +30,6 @@ #include "qpid/log/Statement.h" #include "qpid/sys/windows/check.h" -#include "qpid/sys/windows/mingw32_compat.h" #include <boost/thread/once.hpp> @@ -47,13 +46,16 @@ namespace { /* * The function pointers for AcceptEx and ConnectEx need to be looked up - * at run time. + * at run time. Make sure this is done only once. */ -const LPFN_ACCEPTEX lookUpAcceptEx(const qpid::sys::Socket& s) { - SOCKET h = toSocketHandle(s); +boost::once_flag lookUpAcceptExOnce = BOOST_ONCE_INIT; +LPFN_ACCEPTEX fnAcceptEx = 0; +typedef void (*lookUpFunc)(const qpid::sys::Socket &); + +void lookUpAcceptEx() { + SOCKET h = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); GUID guidAcceptEx = WSAID_ACCEPTEX; DWORD dwBytes = 0; - LPFN_ACCEPTEX fnAcceptEx; WSAIoctl(h, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, @@ -63,9 +65,9 @@ const LPFN_ACCEPTEX lookUpAcceptEx(const qpid::sys::Socket& s) { &dwBytes, NULL, NULL); + closesocket(h); if (fnAcceptEx == 0) throw qpid::Exception(QPID_MSG("Failed to look up AcceptEx")); - return fnAcceptEx; } } @@ -92,15 +94,18 @@ private: AsynchAcceptor::Callback acceptedCallback; const Socket& socket; - const LPFN_ACCEPTEX fnAcceptEx; }; AsynchAcceptor::AsynchAcceptor(const Socket& s, Callback callback) : acceptedCallback(callback), - socket(s), - fnAcceptEx(lookUpAcceptEx(s)) { + socket(s) { s.setNonblocking(); +#if (BOOST_VERSION >= 103500) /* boost 1.35 or later reversed the args */ + boost::call_once(lookUpAcceptExOnce, lookUpAcceptEx); +#else + boost::call_once(lookUpAcceptEx, lookUpAcceptExOnce); +#endif } AsynchAcceptor::~AsynchAcceptor() @@ -109,8 +114,7 @@ AsynchAcceptor::~AsynchAcceptor() } void AsynchAcceptor::start(Poller::shared_ptr poller) { - PollerHandle ph = PollerHandle(socket); - poller->monitorHandle(ph, Poller::INPUT); + poller->monitorHandle(PollerHandle(socket), Poller::INPUT); restart (); } @@ -118,26 +122,25 @@ void AsynchAcceptor::restart(void) { DWORD bytesReceived = 0; // Not used, needed for AcceptEx API AsynchAcceptResult *result = new AsynchAcceptResult(acceptedCallback, this, - socket); + toSocketHandle(socket)); BOOL status; - status = fnAcceptEx(toSocketHandle(socket), - toSocketHandle(*result->newSocket), - result->addressBuffer, - 0, - AsynchAcceptResult::SOCKADDRMAXLEN, - AsynchAcceptResult::SOCKADDRMAXLEN, - &bytesReceived, - result->overlapped()); + status = ::fnAcceptEx(toSocketHandle(socket), + toSocketHandle(*result->newSocket), + result->addressBuffer, + 0, + AsynchAcceptResult::SOCKADDRMAXLEN, + AsynchAcceptResult::SOCKADDRMAXLEN, + &bytesReceived, + result->overlapped()); QPID_WINDOWS_CHECK_ASYNC_START(status); } AsynchAcceptResult::AsynchAcceptResult(AsynchAcceptor::Callback cb, AsynchAcceptor *acceptor, - const Socket& listener) - : callback(cb), acceptor(acceptor), - listener(toSocketHandle(listener)), - newSocket(listener.createSameTypeSocket()) { + SOCKET listener) + : callback(cb), acceptor(acceptor), listener(listener) { + newSocket.reset (new Socket()); } void AsynchAcceptResult::success(size_t /*bytesTransferred*/) { @@ -151,7 +154,7 @@ void AsynchAcceptResult::success(size_t /*bytesTransferred*/) { delete this; } -void AsynchAcceptResult::failure(int /*status*/) { +void AsynchAcceptResult::failure(int status) { //if (status != WSA_OPERATION_ABORTED) // Can there be anything else? ; delete this; @@ -170,20 +173,20 @@ private: FailedCallback failCallback; const Socket& socket; const std::string hostname; - const std::string port; + const uint16_t port; public: AsynchConnector(const Socket& socket, - const std::string& hostname, - const std::string& port, + std::string hostname, + uint16_t port, ConnectedCallback connCb, FailedCallback failCb = 0); void start(Poller::shared_ptr poller); }; AsynchConnector::AsynchConnector(const Socket& sock, - const std::string& hname, - const std::string& p, + std::string hname, + uint16_t p, ConnectedCallback connCb, FailedCallback failCb) : connCallback(connCb), failCallback(failCb), socket(sock), @@ -213,8 +216,8 @@ AsynchAcceptor* AsynchAcceptor::create(const Socket& s, } AsynchConnector* qpid::sys::AsynchConnector::create(const Socket& s, - const std::string& hostname, - const std::string& port, + std::string hostname, + uint16_t port, ConnectedCallback connCb, FailedCallback failCb) { @@ -407,9 +410,8 @@ void AsynchIO::queueForDeletion() { } void AsynchIO::start(Poller::shared_ptr poller0) { - PollerHandle ph = PollerHandle(socket); poller = poller0; - poller->monitorHandle(ph, Poller::INPUT); + poller->monitorHandle(PollerHandle(socket), Poller::INPUT); if (writeQueue.size() > 0) // Already have data queued for write notifyPendingWrite(); startReading(); @@ -582,6 +584,7 @@ void AsynchIO::notifyIdle(void) { void AsynchIO::startWrite(AsynchIO::BufferBase* buff) { writeInProgress = true; InterlockedIncrement(&opsInProgress); + int writeCount = buff->byteCount-buff->dataCount; AsynchWriteResult *result = new AsynchWriteResult(boost::bind(&AsynchIO::completion, this, _1), buff, diff --git a/cpp/src/qpid/sys/windows/AsynchIoResult.h b/cpp/src/qpid/sys/windows/AsynchIoResult.h index 27e4c22138..66c89efc11 100755 --- a/cpp/src/qpid/sys/windows/AsynchIoResult.h +++ b/cpp/src/qpid/sys/windows/AsynchIoResult.h @@ -83,22 +83,22 @@ class AsynchAcceptResult : public AsynchResult { public: AsynchAcceptResult(qpid::sys::AsynchAcceptor::Callback cb, AsynchAcceptor *acceptor, - const qpid::sys::Socket& listener); + SOCKET listener); virtual void success (size_t bytesTransferred); virtual void failure (int error); private: virtual void complete(void) {} // No-op for this class. + std::auto_ptr<qpid::sys::Socket> newSocket; qpid::sys::AsynchAcceptor::Callback callback; AsynchAcceptor *acceptor; SOCKET listener; - std::auto_ptr<qpid::sys::Socket> newSocket; // AcceptEx needs a place to write the local and remote addresses // when accepting the connection. Place those here; get enough for // IPv6 addresses, even if the socket is IPv4. - enum { SOCKADDRMAXLEN = sizeof(sockaddr_in6) + 16, + enum { SOCKADDRMAXLEN = sizeof sockaddr_in6 + 16, SOCKADDRBUFLEN = 2 * SOCKADDRMAXLEN }; char addressBuffer[SOCKADDRBUFLEN]; }; diff --git a/cpp/src/qpid/sys/windows/IocpPoller.cpp b/cpp/src/qpid/sys/windows/IocpPoller.cpp index 1805dd2cd8..d326ab02ac 100755 --- a/cpp/src/qpid/sys/windows/IocpPoller.cpp +++ b/cpp/src/qpid/sys/windows/IocpPoller.cpp @@ -152,9 +152,9 @@ void Poller::monitorHandle(PollerHandle& handle, Direction dir) { } // All no-ops... -void Poller::unmonitorHandle(PollerHandle& /*handle*/, Direction /*dir*/) {} -void Poller::registerHandle(PollerHandle& /*handle*/) {} -void Poller::unregisterHandle(PollerHandle& /*handle*/) {} +void Poller::unmonitorHandle(PollerHandle& handle, Direction dir) {} +void Poller::registerHandle(PollerHandle& handle) {} +void Poller::unregisterHandle(PollerHandle& handle) {} Poller::Event Poller::wait(Duration timeout) { DWORD timeoutMs = 0; diff --git a/cpp/src/qpid/sys/windows/SCM.cpp b/cpp/src/qpid/sys/windows/SCM.cpp deleted file mode 100644 index 4d2c74d4b9..0000000000 --- a/cpp/src/qpid/sys/windows/SCM.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -#include "qpid/log/Statement.h" -#include "qpid/sys/windows/check.h" -#include "SCM.h" - -#pragma comment(lib, "advapi32.lib") - -namespace { - -// Container that will close a SC_HANDLE upon destruction. -class AutoServiceHandle { -public: - AutoServiceHandle(SC_HANDLE h_ = NULL) : h(h_) {} - ~AutoServiceHandle() { if (h != NULL) ::CloseServiceHandle(h); } - void release() { h = NULL; } - void reset(SC_HANDLE newHandle) - { - if (h != NULL) - ::CloseServiceHandle(h); - h = newHandle; - } - operator SC_HANDLE() const { return h; } - -private: - SC_HANDLE h; -}; - -} - -namespace qpid { -namespace windows { - -SCM::SCM() : scmHandle(NULL) -{ -} - -SCM::~SCM() -{ - if (NULL != scmHandle) - ::CloseServiceHandle(scmHandle); -} - -/** - * Install this executable as a service - */ -void SCM::install(const string& serviceName, - const string& serviceDesc, - const string& args, - DWORD startType, - const string& account, - const string& password, - const string& depends) -{ - // Handle dependent service name list; Windows wants a set of nul-separated - // names ending with a double nul. - string depends2 = depends; - if (!depends2.empty()) { - // CDL to null delimiter w/ trailing double null - size_t p = 0; - while ((p = depends2.find_first_of( ',', p)) != string::npos) - depends2.replace(p, 1, 1, '\0'); - depends2.push_back('\0'); - depends2.push_back('\0'); - } - -#if 0 - // I'm nervous about adding a user/password check here. Is this a - // potential attack vector, letting users check passwords without - // control? -Steve Huston, Feb 24, 2011 - - // Validate account, password - HANDLE hToken = NULL; - bool logStatus = false; - if (!account.empty() && !password.empty() && - !(logStatus = ::LogonUserA(account.c_str(), - "", - password.c_str(), - LOGON32_LOGON_NETWORK, - LOGON32_PROVIDER_DEFAULT, - &hToken ) != 0)) - std::cout << "warning: supplied account & password failed with LogonUser." << std::endl; - if (logStatus) - ::CloseHandle(hToken); -#endif - - // Get fully qualified .exe name - char myPath[MAX_PATH]; - DWORD myPathLength = ::GetModuleFileName(NULL, myPath, MAX_PATH); - QPID_WINDOWS_CHECK_NOT(myPathLength, 0); - string imagePath(myPath, myPathLength); - if (!args.empty()) - imagePath += " " + args; - - // Ensure there's a handle to the SCM database. - openSvcManager(); - - // Create the service - SC_HANDLE svcHandle; - svcHandle = ::CreateService(scmHandle, // SCM database - serviceName.c_str(), // name of service - serviceDesc.c_str(), // name to display - SERVICE_ALL_ACCESS, // desired access - SERVICE_WIN32_OWN_PROCESS, // service type - startType, // start type - SERVICE_ERROR_NORMAL, // error cntrl type - imagePath.c_str(), // path to service's binary w/ optional arguments - NULL, // no load ordering group - NULL, // no tag identifier - depends2.empty() ? NULL : depends2.c_str(), - account.empty() ? NULL : account.c_str(), // account name, or NULL for LocalSystem - password.empty() ? NULL : password.c_str()); // password, or NULL for none - QPID_WINDOWS_CHECK_NULL(svcHandle); - ::CloseServiceHandle(svcHandle); - QPID_LOG(info, "Service installed successfully"); -} - -/** - * - */ -void SCM::uninstall(const string& serviceName) -{ - // Ensure there's a handle to the SCM database. - openSvcManager(); - AutoServiceHandle svc(::OpenService(scmHandle, - serviceName.c_str(), - DELETE)); - QPID_WINDOWS_CHECK_NULL((SC_HANDLE)svc); - QPID_WINDOWS_CHECK_NOT(::DeleteService(svc), 0); - QPID_LOG(info, "Service deleted successfully."); -} - -/** - * Attempt to start the service. - */ -void SCM::start(const string& serviceName) -{ - // Ensure we have a handle to the SCM database. - openSvcManager(); - - // Get a handle to the service. - AutoServiceHandle svc(::OpenService(scmHandle, - serviceName.c_str(), - SERVICE_ALL_ACCESS)); - QPID_WINDOWS_CHECK_NULL(svc); - - // Check the status in case the service is not stopped. - DWORD state = waitForStateChangeFrom(svc, SERVICE_STOP_PENDING); - if (state == SERVICE_STOP_PENDING) - throw qpid::Exception("Timed out waiting for running service to stop."); - - // Attempt to start the service. - QPID_WINDOWS_CHECK_NOT(::StartService(svc, 0, NULL), 0); - - QPID_LOG(info, "Service start pending..."); - - // Check the status until the service is no longer start pending. - state = waitForStateChangeFrom(svc, SERVICE_START_PENDING); - // Determine whether the service is running. - if (state == SERVICE_RUNNING) { - QPID_LOG(info, "Service started successfully"); - } - else { - throw qpid::Exception(QPID_MSG("Service not yet running; state now " << state)); - } -} - -/** - * - */ -void SCM::stop(const string& serviceName) -{ - // Ensure a handle to the SCM database. - openSvcManager(); - - // Get a handle to the service. - AutoServiceHandle svc(::OpenService(scmHandle, - serviceName.c_str(), - SERVICE_STOP | SERVICE_QUERY_STATUS | - SERVICE_ENUMERATE_DEPENDENTS)); - QPID_WINDOWS_CHECK_NULL(svc); - - // Make sure the service is not already stopped; if it's stop-pending, - // wait for it to finalize. - DWORD state = waitForStateChangeFrom(svc, SERVICE_STOP_PENDING); - if (state == SERVICE_STOPPED) { - QPID_LOG(info, "Service is already stopped"); - return; - } - - // If the service is running, dependencies must be stopped first. - std::auto_ptr<ENUM_SERVICE_STATUS> deps; - DWORD numDeps = getDependentServices(svc, deps); - for (DWORD i = 0; i < numDeps; i++) - stop(deps.get()[i].lpServiceName); - - // Dependents stopped; send a stop code to the service. - SERVICE_STATUS_PROCESS ssp; - if (!::ControlService(svc, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&ssp)) - throw qpid::Exception(QPID_MSG("Stopping " << serviceName << ": " << - qpid::sys::strError(::GetLastError()))); - - // Wait for the service to stop. - state = waitForStateChangeFrom(svc, SERVICE_STOP_PENDING); - if (state == SERVICE_STOPPED) - QPID_LOG(info, QPID_MSG("Service " << serviceName << - " stopped successfully.")); -} - -/** - * - */ -void SCM::openSvcManager() -{ - if (NULL != scmHandle) - return; - - scmHandle = ::OpenSCManager(NULL, // local computer - NULL, // ServicesActive database - SC_MANAGER_ALL_ACCESS); // Rights - QPID_WINDOWS_CHECK_NULL(scmHandle); -} - -DWORD SCM::waitForStateChangeFrom(SC_HANDLE svc, DWORD originalState) -{ - SERVICE_STATUS_PROCESS ssStatus; - DWORD bytesNeeded; - DWORD waitTime; - if (!::QueryServiceStatusEx(svc, // handle to service - SC_STATUS_PROCESS_INFO, // information level - (LPBYTE)&ssStatus, // address of structure - sizeof(ssStatus), // size of structure - &bytesNeeded)) // size needed if buffer is too small - throw QPID_WINDOWS_ERROR(::GetLastError()); - - // Save the tick count and initial checkpoint. - DWORD startTickCount = ::GetTickCount(); - DWORD oldCheckPoint = ssStatus.dwCheckPoint; - - // Wait for the service to change out of the noted state. - while (ssStatus.dwCurrentState == originalState) { - // Do not wait longer than the wait hint. A good interval is - // one-tenth of the wait hint but not less than 1 second - // and not more than 10 seconds. - waitTime = ssStatus.dwWaitHint / 10; - if (waitTime < 1000) - waitTime = 1000; - else if (waitTime > 10000) - waitTime = 10000; - - ::Sleep(waitTime); - - // Check the status until the service is no longer stop pending. - if (!::QueryServiceStatusEx(svc, - SC_STATUS_PROCESS_INFO, - (LPBYTE) &ssStatus, - sizeof(ssStatus), - &bytesNeeded)) - throw QPID_WINDOWS_ERROR(::GetLastError()); - - if (ssStatus.dwCheckPoint > oldCheckPoint) { - // Continue to wait and check. - startTickCount = ::GetTickCount(); - oldCheckPoint = ssStatus.dwCheckPoint; - } else { - if ((::GetTickCount() - startTickCount) > ssStatus.dwWaitHint) - break; - } - } - return ssStatus.dwCurrentState; -} - -/** - * Get the services that depend on @arg svc. All dependent service info - * is returned in an array of ENUM_SERVICE_STATUS structures via @arg deps. - * - * @retval The number of dependent services. - */ -DWORD SCM::getDependentServices(SC_HANDLE svc, - std::auto_ptr<ENUM_SERVICE_STATUS>& deps) -{ - DWORD bytesNeeded; - DWORD numEntries; - - // Pass a zero-length buffer to get the required buffer size. - if (::EnumDependentServices(svc, - SERVICE_ACTIVE, - 0, - 0, - &bytesNeeded, - &numEntries)) { - // If the Enum call succeeds, then there are no dependent - // services, so do nothing. - return 0; - } - - if (::GetLastError() != ERROR_MORE_DATA) - throw QPID_WINDOWS_ERROR((::GetLastError())); - - // Allocate a buffer for the dependencies. - deps.reset((LPENUM_SERVICE_STATUS)(new char[bytesNeeded])); - // Enumerate the dependencies. - if (!::EnumDependentServices(svc, - SERVICE_ACTIVE, - deps.get(), - bytesNeeded, - &bytesNeeded, - &numEntries)) - throw QPID_WINDOWS_ERROR((::GetLastError())); - return numEntries; -} - -} } // namespace qpid::windows diff --git a/cpp/src/qpid/sys/windows/SCM.h b/cpp/src/qpid/sys/windows/SCM.h deleted file mode 100644 index 8e94ef83c7..0000000000 --- a/cpp/src/qpid/sys/windows/SCM.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef WINDOWS_SCM_H -#define WINDOWS_SCM_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 <memory> -#include <string> -using std::string; - -#ifdef UNICODE -#undef UNICODE -#endif - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#include <windows.h> - -#include "qpid/CommonImportExport.h" - -namespace qpid { -namespace windows { - -/** - * @class SCM - * - * Access the Windows Service Control Manager. - */ -class SCM -{ -public: - QPID_COMMON_EXTERN SCM(); - QPID_COMMON_EXTERN ~SCM(); - - /** - * Install this executable as a service - * - * @param serviceName The name of the service - * @param serviceDesc Description of the service's purpose - * @param args The argument list to pass into the service - * @param startType The start type: SERVICE_DEMAND_START, - * SERVICE_AUTO_START, SERVICE_DISABLED - * @param account If not empty, the account name to install this - * service under - * @param password If not empty, the account password to install this - * service with - * @param depends If not empty, a comma delimited list of services - * that must start before this one - */ - QPID_COMMON_EXTERN void install(const string& serviceName, - const string& serviceDesc, - const string& args, - DWORD startType = SERVICE_DEMAND_START, - const string& account = "NT AUTHORITY\\LocalSystem", - const string& password = "", - const string& depends = ""); - - /** - * Uninstall this executable as a service - * - * @param serviceName the name of the service - */ - QPID_COMMON_EXTERN void uninstall(const string& serviceName); - - /** - * Start the specified service - * - * @param serviceName the name of the service - */ - QPID_COMMON_EXTERN void start(const string& serviceName); - - /** - * Stop the specified service - * - * @param serviceName the name of the service - */ - QPID_COMMON_EXTERN void stop(const string &serviceName); - -private: - SC_HANDLE scmHandle; - - void openSvcManager(); - DWORD waitForStateChangeFrom(SC_HANDLE svc, DWORD originalState); - DWORD getDependentServices(SC_HANDLE svc, - std::auto_ptr<ENUM_SERVICE_STATUS>& deps); - -}; - -}} // namespace qpid::windows - -#endif /* #ifndef WINDOWS_SCM_H */ diff --git a/cpp/src/qpid/sys/windows/Shlib.cpp b/cpp/src/qpid/sys/windows/Shlib.cpp index ba18747eb4..38027de93f 100644 --- a/cpp/src/qpid/sys/windows/Shlib.cpp +++ b/cpp/src/qpid/sys/windows/Shlib.cpp @@ -44,8 +44,7 @@ void Shlib::unload() { } void* Shlib::getSymbol(const char* name) { - // Double cast avoids warning about casting function pointer to object - void *sym = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(GetProcAddress(static_cast<HMODULE>(handle), name))); + void* sym = GetProcAddress(static_cast<HMODULE>(handle), name); if (sym == NULL) throw QPID_WINDOWS_ERROR(GetLastError()); return sym; diff --git a/cpp/src/qpid/sys/windows/Socket.cpp b/cpp/src/qpid/sys/windows/Socket.cpp index 1fa4768329..11fb8b4133 100644..100755 --- a/cpp/src/qpid/sys/windows/Socket.cpp +++ b/cpp/src/qpid/sys/windows/Socket.cpp @@ -20,18 +20,19 @@ */ #include "qpid/sys/Socket.h" - #include "qpid/sys/SocketAddress.h" -#include "qpid/sys/windows/check.h" #include "qpid/sys/windows/IoHandlePrivate.h" +#include "qpid/sys/windows/check.h" +#include "qpid/sys/Time.h" -// Ensure we get all of winsock2.h -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif +#include <cstdlib> +#include <string.h> #include <winsock2.h> +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp> + // Need to initialize WinSock. Ideally, this would be a singleton or embedded // in some one-time initialization function. I tried boost singleton and could // not get it to compile (and others located in google had the same problem). @@ -83,30 +84,53 @@ namespace sys { namespace { -std::string getName(SOCKET fd, bool local) +std::string getName(SOCKET fd, bool local, bool includeService = false) { - ::sockaddr_storage name_s; // big enough for any socket address - ::sockaddr* name = (::sockaddr*)&name_s; - ::socklen_t namelen = sizeof(name_s); - + sockaddr_in name; // big enough for any socket address + socklen_t namelen = sizeof(name); if (local) { - QPID_WINSOCK_CHECK(::getsockname(fd, name, &namelen)); + QPID_WINSOCK_CHECK(::getsockname(fd, (sockaddr*)&name, &namelen)); } else { - QPID_WINSOCK_CHECK(::getpeername(fd, name, &namelen)); + QPID_WINSOCK_CHECK(::getpeername(fd, (sockaddr*)&name, &namelen)); } - return SocketAddress::asString(name, namelen); + char servName[NI_MAXSERV]; + char dispName[NI_MAXHOST]; + if (includeService) { + if (int rc = ::getnameinfo((sockaddr*)&name, namelen, + dispName, sizeof(dispName), + servName, sizeof(servName), + NI_NUMERICHOST | NI_NUMERICSERV) != 0) + throw qpid::Exception(QPID_MSG(gai_strerror(rc))); + return std::string(dispName) + ":" + std::string(servName); + } else { + if (int rc = ::getnameinfo((sockaddr*)&name, namelen, + dispName, sizeof(dispName), + 0, 0, + NI_NUMERICHOST) != 0) + throw qpid::Exception(QPID_MSG(gai_strerror(rc))); + return dispName; + } } -uint16_t getLocalPort(int fd) +std::string getService(SOCKET fd, bool local) { - ::sockaddr_storage name_s; // big enough for any socket address - ::sockaddr* name = (::sockaddr*)&name_s; - ::socklen_t namelen = sizeof(name_s); - - QPID_WINSOCK_CHECK(::getsockname(fd, name, &namelen)); + sockaddr_in name; // big enough for any socket address + socklen_t namelen = sizeof(name); + + if (local) { + QPID_WINSOCK_CHECK(::getsockname(fd, (sockaddr*)&name, &namelen)); + } else { + QPID_WINSOCK_CHECK(::getpeername(fd, (sockaddr*)&name, &namelen)); + } - return SocketAddress::getPort(name); + char servName[NI_MAXSERV]; + if (int rc = ::getnameinfo((sockaddr*)&name, namelen, + 0, 0, + servName, sizeof(servName), + NI_NUMERICHOST | NI_NUMERICSERV) != 0) + throw qpid::Exception(QPID_MSG(gai_strerror(rc))); + return servName; } } // namespace @@ -114,7 +138,13 @@ Socket::Socket() : IOHandle(new IOHandlePrivate), nonblocking(false), nodelay(false) -{} +{ + SOCKET& socket = impl->fd; + if (socket != INVALID_SOCKET) Socket::close(); + SOCKET s = ::socket (PF_INET, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) throw QPID_WINDOWS_ERROR(WSAGetLastError()); + socket = s; +} Socket::Socket(IOHandlePrivate* h) : IOHandle(h), @@ -122,7 +152,8 @@ Socket::Socket(IOHandlePrivate* h) : nodelay(false) {} -void Socket::createSocket(const SocketAddress& sa) const +void +Socket::createSocket(const SocketAddress& sa) const { SOCKET& socket = impl->fd; if (socket != INVALID_SOCKET) Socket::close(); @@ -137,24 +168,24 @@ void Socket::createSocket(const SocketAddress& sa) const if (nonblocking) setNonblocking(); if (nodelay) setTcpNoDelay(); } catch (std::exception&) { - ::closesocket(s); + closesocket(s); socket = INVALID_SOCKET; throw; } } -Socket* Socket::createSameTypeSocket() const { - SOCKET& socket = impl->fd; - // Socket currently has no actual socket attached - if (socket == INVALID_SOCKET) - return new Socket; - - ::sockaddr_storage sa; - ::socklen_t salen = sizeof(sa); - QPID_WINSOCK_CHECK(::getsockname(socket, (::sockaddr*)&sa, &salen)); - SOCKET s = ::socket(sa.ss_family, SOCK_STREAM, 0); // Currently only work with SOCK_STREAM - if (s == INVALID_SOCKET) throw QPID_WINDOWS_ERROR(WSAGetLastError()); - return new Socket(new IOHandlePrivate(s)); +void Socket::setTimeout(const Duration& interval) const +{ + const SOCKET& socket = impl->fd; + int64_t nanosecs = interval; + nanosecs /= (1000 * 1000); // nsecs -> usec -> msec + int msec = 0; + if (nanosecs > std::numeric_limits<int>::max()) + msec = std::numeric_limits<int>::max(); + else + msec = static_cast<int>(nanosecs); + setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&msec, sizeof(msec)); + setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&msec, sizeof(msec)); } void Socket::setNonblocking() const { @@ -162,25 +193,30 @@ void Socket::setNonblocking() const { QPID_WINSOCK_CHECK(ioctlsocket(impl->fd, FIONBIO, &nonblock)); } -void Socket::connect(const std::string& host, const std::string& port) const +void Socket::connect(const std::string& host, uint16_t port) const { - SocketAddress sa(host, port); + SocketAddress sa(host, boost::lexical_cast<std::string>(port)); connect(sa); } void Socket::connect(const SocketAddress& addr) const { - peername = addr.asString(false); - - createSocket(addr); - const SOCKET& socket = impl->fd; - int err; + const addrinfo *addrs = &(getAddrInfo(addr)); + int error = 0; WSASetLastError(0); - if ((::connect(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) != 0) && - ((err = ::WSAGetLastError()) != WSAEWOULDBLOCK)) - throw qpid::Exception(QPID_MSG(strError(err) << ": " << peername)); + while (addrs != 0) { + if ((::connect(socket, addrs->ai_addr, addrs->ai_addrlen) == 0) || + (WSAGetLastError() == WSAEWOULDBLOCK)) + break; + // Error... save this error code and see if there are other address + // to try before throwing the exception. + error = WSAGetLastError(); + addrs = addrs->ai_next; + } + if (error) + throw qpid::Exception(QPID_MSG(strError(error) << ": " << connectname)); } void @@ -211,26 +247,24 @@ int Socket::read(void *buf, size_t count) const return received; } -int Socket::listen(const std::string& host, const std::string& port, int backlog) const -{ - SocketAddress sa(host, port); - return listen(sa, backlog); -} - -int Socket::listen(const SocketAddress& addr, int backlog) const +int Socket::listen(uint16_t port, int backlog) const { - createSocket(addr); - const SOCKET& socket = impl->fd; BOOL yes=1; QPID_WINSOCK_CHECK(setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes))); - - if (::bind(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) == SOCKET_ERROR) - throw Exception(QPID_MSG("Can't bind to " << addr.asString() << ": " << strError(WSAGetLastError()))); + struct sockaddr_in name; + memset(&name, 0, sizeof(name)); + name.sin_family = AF_INET; + name.sin_port = htons(port); + name.sin_addr.s_addr = 0; + if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) == SOCKET_ERROR) + throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(WSAGetLastError()))); if (::listen(socket, backlog) == SOCKET_ERROR) - throw Exception(QPID_MSG("Can't listen on " <<addr.asString() << ": " << strError(WSAGetLastError()))); - - return getLocalPort(socket); + throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(WSAGetLastError()))); + + socklen_t namelen = sizeof(name); + QPID_WINSOCK_CHECK(::getsockname(socket, (struct sockaddr*)&name, &namelen)); + return ntohs(name.sin_port); } Socket* Socket::accept() const @@ -243,20 +277,36 @@ Socket* Socket::accept() const else throw QPID_WINDOWS_ERROR(WSAGetLastError()); } +std::string Socket::getSockname() const +{ + return getName(impl->fd, true); +} + +std::string Socket::getPeername() const +{ + return getName(impl->fd, false); +} + std::string Socket::getPeerAddress() const { - if (peername.empty()) { - peername = getName(impl->fd, false); - } - return peername; + if (!connectname.empty()) + return std::string (connectname); + return getName(impl->fd, false, true); } std::string Socket::getLocalAddress() const { - if (localname.empty()) { - localname = getName(impl->fd, true); - } - return localname; + return getName(impl->fd, true, true); +} + +uint16_t Socket::getLocalPort() const +{ + return atoi(getService(impl->fd, true).c_str()); +} + +uint16_t Socket::getRemotePort() const +{ + return atoi(getService(impl->fd, true).c_str()); } int Socket::getError() const diff --git a/cpp/src/qpid/sys/windows/SocketAddress.cpp b/cpp/src/qpid/sys/windows/SocketAddress.cpp index 77bbf85810..501cff1297 100644 --- a/cpp/src/qpid/sys/windows/SocketAddress.cpp +++ b/cpp/src/qpid/sys/windows/SocketAddress.cpp @@ -21,13 +21,7 @@ #include "qpid/sys/SocketAddress.h" -#include "qpid/Exception.h" -#include "qpid/Msg.h" - -// Ensure we get all of winsock2.h -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif +#include "qpid/sys/windows/check.h" #include <winsock2.h> #include <ws2tcpip.h> @@ -41,111 +35,37 @@ SocketAddress::SocketAddress(const std::string& host0, const std::string& port0) port(port0), addrInfo(0) { -} - -SocketAddress::SocketAddress(const SocketAddress& sa) : - host(sa.host), - port(sa.port), - addrInfo(0) -{ -} - -SocketAddress& SocketAddress::operator=(const SocketAddress& sa) -{ - SocketAddress temp(sa); - - std::swap(temp, *this); - return *this; -} - -SocketAddress::~SocketAddress() -{ - if (addrInfo) { - ::freeaddrinfo(addrInfo); + ::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; + + const char* node = 0; + if (host.empty()) { + hints.ai_flags |= AI_PASSIVE; + } else { + node = host.c_str(); } -} + const char* service = port.empty() ? "0" : port.c_str(); -std::string SocketAddress::asString(::sockaddr const * const addr, size_t addrlen) -{ - char servName[NI_MAXSERV]; - char dispName[NI_MAXHOST]; - if (int rc=::getnameinfo(addr, addrlen, - dispName, sizeof(dispName), - servName, sizeof(servName), - NI_NUMERICHOST | NI_NUMERICSERV) != 0) - throw qpid::Exception(QPID_MSG(gai_strerror(rc))); - std::string s; - switch (addr->sa_family) { - case AF_INET: s += dispName; break; - case AF_INET6: s += "["; s += dispName; s+= "]"; break; - default: throw Exception(QPID_MSG("Unexpected socket type")); - } - s += ":"; - s += servName; - return s; + int n = ::getaddrinfo(node, service, &hints, &addrInfo); + if (n != 0) + throw Exception(QPID_MSG("Cannot resolve " << host << ": " << ::gai_strerror(n))); } -uint16_t SocketAddress::getPort(::sockaddr const * const addr) +SocketAddress::~SocketAddress() { - switch (addr->sa_family) { - case AF_INET: return ntohs(((::sockaddr_in*)addr)->sin_port); - case AF_INET6: return ntohs(((::sockaddr_in6*)addr)->sin6_port); - default:throw Exception(QPID_MSG("Unexpected socket type")); - } + ::freeaddrinfo(addrInfo); } -std::string SocketAddress::asString(bool numeric) const +std::string SocketAddress::asString() const { - if (!numeric) - return host + ":" + port; - // Canonicalise into numeric id - const ::addrinfo& ai = getAddrInfo(*this); - - return asString(ai.ai_addr, ai.ai_addrlen); -} - -bool SocketAddress::nextAddress() { - bool r = currentAddrInfo->ai_next != 0; - if (r) - currentAddrInfo = currentAddrInfo->ai_next; - return r; -} - -void SocketAddress::setAddrInfoPort(uint16_t port) { - if (!currentAddrInfo) return; - - ::addrinfo& ai = *currentAddrInfo; - switch (ai.ai_family) { - case AF_INET: ((::sockaddr_in*)ai.ai_addr)->sin_port = htons(port); return; - case AF_INET6:((::sockaddr_in6*)ai.ai_addr)->sin6_port = htons(port); return; - default: throw Exception(QPID_MSG("Unexpected socket type")); - } + return host + ":" + port; } const ::addrinfo& getAddrInfo(const SocketAddress& sa) { - if (!sa.addrInfo) { - ::addrinfo hints; - ::memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_ADDRCONFIG; // Only use protocols that we have configured interfaces for - hints.ai_family = AF_UNSPEC; // Allow both IPv4 and IPv6 - hints.ai_socktype = SOCK_STREAM; - - const char* node = 0; - if (sa.host.empty()) { - hints.ai_flags |= AI_PASSIVE; - } else { - node = sa.host.c_str(); - } - const char* service = sa.port.empty() ? "0" : sa.port.c_str(); - - int n = ::getaddrinfo(node, service, &hints, &sa.addrInfo); - if (n != 0) - throw Exception(QPID_MSG("Cannot resolve " << sa.asString(false) << ": " << ::gai_strerror(n))); - sa.currentAddrInfo = sa.addrInfo; - } - - return *sa.currentAddrInfo; + return *sa.addrInfo; } }} diff --git a/cpp/src/qpid/sys/windows/SslAsynchIO.h b/cpp/src/qpid/sys/windows/SslAsynchIO.h index edec081ced..3cdf2c8f08 100644 --- a/cpp/src/qpid/sys/windows/SslAsynchIO.h +++ b/cpp/src/qpid/sys/windows/SslAsynchIO.h @@ -39,6 +39,9 @@ namespace qpid { namespace sys { namespace windows { +class Socket; +class Poller; + /* * SSL/Schannel shim between the frame-handling and AsynchIO layers. * SslAsynchIO creates a regular AsynchIO object to handle I/O and this class diff --git a/cpp/src/qpid/sys/windows/StrError.cpp b/cpp/src/qpid/sys/windows/StrError.cpp index 546d399d16..9c1bfcd79c 100755 --- a/cpp/src/qpid/sys/windows/StrError.cpp +++ b/cpp/src/qpid/sys/windows/StrError.cpp @@ -30,7 +30,6 @@ namespace sys { std::string strError(int err) { const size_t bufsize = 512; char buf[bufsize]; - buf[0] = 0; if (0 == FormatMessage (FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM, 0, @@ -40,11 +39,7 @@ std::string strError(int err) { bufsize, 0)) { -#ifdef _MSC_VER - strerror_s(buf, bufsize, err); -#else - return std::string(strerror(err)); -#endif + strerror_s (buf, bufsize, err); } return std::string(buf); } diff --git a/cpp/src/qpid/sys/windows/Thread.cpp b/cpp/src/qpid/sys/windows/Thread.cpp index 23b0033be4..583a9613a3 100755 --- a/cpp/src/qpid/sys/windows/Thread.cpp +++ b/cpp/src/qpid/sys/windows/Thread.cpp @@ -19,11 +19,6 @@ * */ -// Ensure definition of OpenThread in mingw -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif - #include "qpid/sys/Thread.h" #include "qpid/sys/Runnable.h" #include "qpid/sys/windows/check.h" @@ -31,204 +26,50 @@ #include <process.h> #include <windows.h> -/* - * This implementation distinguishes between two types of thread: Qpid - * threads (based on qpid::sys::Runnable) and the rest. It provides a - * join() that will not deadlock against the Windows loader lock for - * Qpid threads. - * - * System thread identifiers are unique per Windows thread; thread - * handles are not. Thread identifiers can be recycled, but keeping a - * handle open against the thread prevents recycling as long as - * shared_ptr references to a ThreadPrivate structure remain. - * - * There is a 1-1 relationship between Qpid threads and their - * ThreadPrivate structure. Non-Qpid threads do not need to find the - * qpidThreadDone handle, so there may be a 1-many relationship for - * them. - * - * TLS storage is used for a lockless solution for static library - * builds. The special case of LoadLibrary/FreeLibrary requires - * additional synchronization variables and resource cleanup in - * DllMain. _DLL marks the dynamic case. - */ +namespace { +unsigned __stdcall runRunnable(void* p) +{ + static_cast<qpid::sys::Runnable*>(p)->run(); + _endthreadex(0); + return 0; +} +} namespace qpid { namespace sys { class ThreadPrivate { -public: friend class Thread; - friend unsigned __stdcall runThreadPrivate(void*); - typedef boost::shared_ptr<ThreadPrivate> shared_ptr; - ~ThreadPrivate(); -private: - unsigned threadId; HANDLE threadHandle; - HANDLE initCompleted; - HANDLE qpidThreadDone; - Runnable* runnable; - shared_ptr keepAlive; - - ThreadPrivate() : threadId(GetCurrentThreadId()), initCompleted(NULL), - qpidThreadDone(NULL), runnable(NULL) { - threadHandle = OpenThread (SYNCHRONIZE, FALSE, threadId); - QPID_WINDOWS_CHECK_CRT_NZ(threadHandle); - } - - ThreadPrivate(Runnable* r) : threadHandle(NULL), initCompleted(NULL), - qpidThreadDone(NULL), runnable(r) {} - - void start(shared_ptr& p); - static shared_ptr createThread(Runnable* r); -}; - -}} // namespace qpid::sys - - -namespace { -using namespace qpid::sys; - -#ifdef _DLL -class ScopedCriticalSection -{ - public: - ScopedCriticalSection(CRITICAL_SECTION& cs) : criticalSection(cs) { EnterCriticalSection(&criticalSection); } - ~ScopedCriticalSection() { LeaveCriticalSection(&criticalSection); } - private: - CRITICAL_SECTION& criticalSection; -}; - -CRITICAL_SECTION threadLock; -long runningThreads = 0; -HANDLE threadsDone; -bool terminating = false; -#endif - - -DWORD volatile tlsIndex = TLS_OUT_OF_INDEXES; - -DWORD getTlsIndex() { - if (tlsIndex != TLS_OUT_OF_INDEXES) - return tlsIndex; // already set - - DWORD trialIndex = TlsAlloc(); - QPID_WINDOWS_CHECK_NOT(trialIndex, TLS_OUT_OF_INDEXES); // No OS resource + unsigned threadId; - // only one thread gets to set the value - DWORD actualIndex = (DWORD) InterlockedCompareExchange((LONG volatile *) &tlsIndex, (LONG) trialIndex, (LONG) TLS_OUT_OF_INDEXES); - if (actualIndex == TLS_OUT_OF_INDEXES) - return trialIndex; // we won the race - else { - TlsFree(trialIndex); - return actualIndex; + ThreadPrivate(Runnable* runnable) { + uintptr_t h = _beginthreadex(0, + 0, + runRunnable, + runnable, + 0, + &threadId); + QPID_WINDOWS_CHECK_CRT_NZ(h); + threadHandle = reinterpret_cast<HANDLE>(h); } -} - -} // namespace - -namespace qpid { -namespace sys { - -unsigned __stdcall runThreadPrivate(void* p) -{ - ThreadPrivate* threadPrivate = static_cast<ThreadPrivate*>(p); - TlsSetValue(getTlsIndex(), threadPrivate); - - WaitForSingleObject (threadPrivate->initCompleted, INFINITE); - CloseHandle (threadPrivate->initCompleted); - threadPrivate->initCompleted = NULL; - - try { - threadPrivate->runnable->run(); - } catch (...) { - // not our concern - } - - SetEvent (threadPrivate->qpidThreadDone); // allow join() - threadPrivate->keepAlive.reset(); // may run ThreadPrivate destructor - -#ifdef _DLL - { - ScopedCriticalSection l(threadLock); - if (--runningThreads == 0) - SetEvent(threadsDone); - } -#endif - return 0; -} - - -ThreadPrivate::shared_ptr ThreadPrivate::createThread(Runnable* runnable) { - ThreadPrivate::shared_ptr tp(new ThreadPrivate(runnable)); - tp->start(tp); - return tp; -} - -void ThreadPrivate::start(ThreadPrivate::shared_ptr& tp) { - getTlsIndex(); // fail here if OS problem, not in new thread - - initCompleted = CreateEvent (NULL, TRUE, FALSE, NULL); - QPID_WINDOWS_CHECK_CRT_NZ(initCompleted); - qpidThreadDone = CreateEvent (NULL, TRUE, FALSE, NULL); - QPID_WINDOWS_CHECK_CRT_NZ(qpidThreadDone); - -#ifdef _DLL - { - ScopedCriticalSection l(threadLock); - if (terminating) - throw qpid::Exception(QPID_MSG("creating thread after exit/FreeLibrary")); - runningThreads++; - } -#endif - - uintptr_t h = _beginthreadex(0, - 0, - runThreadPrivate, - (void *)this, - 0, - &threadId); - -#ifdef _DLL - if (h == NULL) { - ScopedCriticalSection l(threadLock); - if (--runningThreads == 0) - SetEvent(threadsDone); - } -#endif - - QPID_WINDOWS_CHECK_CRT_NZ(h); - - // Success - keepAlive = tp; - threadHandle = reinterpret_cast<HANDLE>(h); - SetEvent (initCompleted); -} - -ThreadPrivate::~ThreadPrivate() { - if (threadHandle) - CloseHandle (threadHandle); - if (initCompleted) - CloseHandle (initCompleted); - if (qpidThreadDone) - CloseHandle (qpidThreadDone); -} - + + ThreadPrivate() + : threadHandle(GetCurrentThread()), threadId(GetCurrentThreadId()) {} +}; Thread::Thread() {} -Thread::Thread(Runnable* runnable) : impl(ThreadPrivate::createThread(runnable)) {} +Thread::Thread(Runnable* runnable) : impl(new ThreadPrivate(runnable)) {} -Thread::Thread(Runnable& runnable) : impl(ThreadPrivate::createThread(&runnable)) {} +Thread::Thread(Runnable& runnable) : impl(new ThreadPrivate(&runnable)) {} Thread::operator bool() { return impl; } bool Thread::operator==(const Thread& t) const { - if (!impl || !t.impl) - return false; return impl->threadId == t.impl->threadId; } @@ -238,17 +79,10 @@ bool Thread::operator!=(const Thread& t) const { void Thread::join() { if (impl) { - DWORD status; - if (impl->runnable) { - HANDLE handles[2] = {impl->qpidThreadDone, impl->threadHandle}; - // wait for either. threadHandle not signalled if loader - // lock held (FreeLibrary). qpidThreadDone not signalled - // if thread terminated by exit(). - status = WaitForMultipleObjects (2, handles, false, INFINITE); - } - else - status = WaitForSingleObject (impl->threadHandle, INFINITE); + DWORD status = WaitForSingleObject (impl->threadHandle, INFINITE); QPID_WINDOWS_CHECK_NOT(status, WAIT_FAILED); + CloseHandle (impl->threadHandle); + impl->threadHandle = 0; } } @@ -258,70 +92,9 @@ unsigned long Thread::logId() { /* static */ Thread Thread::current() { - ThreadPrivate* tlsValue = (ThreadPrivate *) TlsGetValue(getTlsIndex()); Thread t; - if (tlsValue != NULL) { - // called from within Runnable->run(), so keepAlive has positive use count - t.impl = tlsValue->keepAlive; - } - else - t.impl.reset(new ThreadPrivate()); + t.impl.reset(new ThreadPrivate()); return t; } -}} // namespace qpid::sys - - -#ifdef _DLL - -// DllMain: called possibly many times in a process lifetime if dll -// loaded and freed repeatedly . Be mindful of Windows loader lock -// and other DllMain restrictions. - -BOOL APIENTRY DllMain(HMODULE hm, DWORD reason, LPVOID reserved) { - switch (reason) { - case DLL_PROCESS_ATTACH: - InitializeCriticalSection(&threadLock); - threadsDone = CreateEvent(NULL, TRUE, FALSE, NULL); - break; - - case DLL_PROCESS_DETACH: - terminating = true; - if (reserved != NULL) { - // process exit(): threads are stopped arbitrarily and - // possibly in an inconsistent state. Not even threadLock - // can be trusted. All static destructors have been - // called at this point and any resources this unit knows - // about will be released as part of process tear down by - // the OS. Accordingly, do nothing. - return TRUE; - } - else { - // FreeLibrary(): threads are still running and we are - // encouraged to clean up to avoid leaks. Mostly we just - // want any straggler threads to finish and notify - // threadsDone as the last thing they do. - while (1) { - { - ScopedCriticalSection l(threadLock); - if (runningThreads == 0) - break; - ResetEvent(threadsDone); - } - WaitForSingleObject(threadsDone, INFINITE); - } - if (tlsIndex != TLS_OUT_OF_INDEXES) - TlsFree(getTlsIndex()); - CloseHandle(threadsDone); - DeleteCriticalSection(&threadLock); - } - break; - - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return TRUE; -} - -#endif +}} /* qpid::sys */ diff --git a/cpp/src/qpid/sys/windows/Time.cpp b/cpp/src/qpid/sys/windows/Time.cpp index 25c50819cd..16d09fcdc0 100644 --- a/cpp/src/qpid/sys/windows/Time.cpp +++ b/cpp/src/qpid/sys/windows/Time.cpp @@ -27,17 +27,6 @@ using namespace boost::posix_time; -namespace { - -// High-res timing support. This will display times since program start, -// more or less. Keep track of the start value and the conversion factor to -// seconds. -bool timeInitialized = false; -LARGE_INTEGER start; -double freq = 1.0; - -} - namespace qpid { namespace sys { @@ -102,35 +91,10 @@ void outputFormattedNow(std::ostream& o) { char time_string[100]; ::time( &rawtime ); -#ifdef _MSC_VER ::localtime_s(&timeinfo, &rawtime); -#else - timeinfo = *(::localtime(&rawtime)); -#endif ::strftime(time_string, 100, "%Y-%m-%d %H:%M:%S", &timeinfo); o << time_string << " "; } - -void outputHiresNow(std::ostream& o) { - if (!timeInitialized) { - start.QuadPart = 0; - LARGE_INTEGER iFreq; - iFreq.QuadPart = 1; - QueryPerformanceCounter(&start); - QueryPerformanceFrequency(&iFreq); - freq = static_cast<double>(iFreq.QuadPart); - timeInitialized = true; - } - LARGE_INTEGER iNow; - iNow.QuadPart = 0; - QueryPerformanceCounter(&iNow); - iNow.QuadPart -= start.QuadPart; - if (iNow.QuadPart < 0) - iNow.QuadPart = 0; - double now = static_cast<double>(iNow.QuadPart); - now /= freq; // now is seconds after this - o << std::fixed << std::setprecision(8) << std::setw(16) << std::setfill('0') << now << "s "; -} }} diff --git a/cpp/src/qpid/sys/windows/uuid.cpp b/cpp/src/qpid/sys/windows/uuid.cpp index 3316ecbc00..b5360622dc 100644 --- a/cpp/src/qpid/sys/windows/uuid.cpp +++ b/cpp/src/qpid/sys/windows/uuid.cpp @@ -19,7 +19,7 @@ * */ -#include <rpc.h> +#include <Rpc.h> #ifdef uuid_t /* Done in rpcdce.h */ # undef uuid_t #endif @@ -52,11 +52,7 @@ int uuid_parse (const char *in, uuid_t uu) { void uuid_unparse (const uuid_t uu, char *out) { unsigned char *formatted; if (UuidToString((UUID*)uu, &formatted) == RPC_S_OK) { -#ifdef _MSC_VER strncpy_s (out, 36+1, (char*)formatted, _TRUNCATE); -#else - strncpy (out, (char*)formatted, 36+1); -#endif RpcStringFree(&formatted); } } diff --git a/cpp/src/qpid/types/Uuid.cpp b/cpp/src/qpid/types/Uuid.cpp index 9862fa8946..9face4e5d2 100644 --- a/cpp/src/qpid/types/Uuid.cpp +++ b/cpp/src/qpid/types/Uuid.cpp @@ -20,7 +20,6 @@ */ #include "qpid/types/Uuid.h" #include "qpid/sys/uuid.h" -#include "qpid/sys/IntegerTypes.h" #include <sstream> #include <iostream> #include <string.h> @@ -72,8 +71,7 @@ void Uuid::clear() // Force int 0/!0 to false/true; avoids compile warnings. bool Uuid::isNull() const { - // This const cast is for Solaris which has non const arguments - return !!uuid_is_null(const_cast<uint8_t*>(bytes)); + return !!uuid_is_null(bytes); } Uuid::operator bool() const { return !isNull(); } @@ -88,8 +86,7 @@ const unsigned char* Uuid::data() const bool operator==(const Uuid& a, const Uuid& b) { - // This const cast is for Solaris which has non const arguments - return uuid_compare(const_cast<uint8_t*>(a.bytes), const_cast<uint8_t*>(b.bytes)) == 0; + return uuid_compare(a.bytes, b.bytes) == 0; } bool operator!=(const Uuid& a, const Uuid& b) @@ -99,26 +96,22 @@ bool operator!=(const Uuid& a, const Uuid& b) bool operator<(const Uuid& a, const Uuid& b) { - // This const cast is for Solaris which has non const arguments - return uuid_compare(const_cast<uint8_t*>(a.bytes), const_cast<uint8_t*>(b.bytes)) < 0; + return uuid_compare(a.bytes, b.bytes) < 0; } bool operator>(const Uuid& a, const Uuid& b) { - // This const cast is for Solaris which has non const arguments - return uuid_compare(const_cast<uint8_t*>(a.bytes), const_cast<uint8_t*>(b.bytes)) > 0; + return uuid_compare(a.bytes, b.bytes) > 0; } bool operator<=(const Uuid& a, const Uuid& b) { - // This const cast is for Solaris which has non const arguments - return uuid_compare(const_cast<uint8_t*>(a.bytes), const_cast<uint8_t*>(b.bytes)) <= 0; + return uuid_compare(a.bytes, b.bytes) <= 0; } bool operator>=(const Uuid& a, const Uuid& b) { - // This const cast is for Solaris which has non const arguments - return uuid_compare(const_cast<uint8_t*>(a.bytes), const_cast<uint8_t*>(b.bytes)) >= 0; + return uuid_compare(a.bytes, b.bytes) >= 0; } ostream& operator<<(ostream& out, Uuid uuid) diff --git a/cpp/src/qpid/types/Variant.cpp b/cpp/src/qpid/types/Variant.cpp index f563d5de5b..5d8878bdac 100644 --- a/cpp/src/qpid/types/Variant.cpp +++ b/cpp/src/qpid/types/Variant.cpp @@ -19,6 +19,7 @@ * */ #include "qpid/types/Variant.h" +#include "qpid/Msg.h" #include "qpid/log/Statement.h" #include <boost/format.hpp> #include <boost/lexical_cast.hpp> @@ -107,27 +108,15 @@ class VariantImpl } value; std::string encoding;//optional encoding for variable length data + std::string getTypeName(VariantType type) const; template<class T> T convertFromString() const { std::string* s = reinterpret_cast<std::string*>(value.v); - if (std::numeric_limits<T>::is_signed || s->find('-') != 0) { - //lexical_cast won't fail if string is a negative number and T is unsigned - try { - return boost::lexical_cast<T>(*s); - } catch(const boost::bad_lexical_cast&) { - //don't return, throw exception below - } - } else { - //T is unsigned and number starts with '-' - try { - //handle special case of negative zero - if (boost::lexical_cast<int>(*s) == 0) return 0; - //else its a non-zero negative number so throw exception at end of function - } catch(const boost::bad_lexical_cast&) { - //wasn't a valid int, therefore not a valid uint - } + try { + return boost::lexical_cast<T>(*s); + } catch(const boost::bad_lexical_cast&) { + throw InvalidConversion(QPID_MSG("Cannot convert " << *s)); } - throw InvalidConversion(QPID_MSG("Cannot convert " << *s)); } }; @@ -381,11 +370,11 @@ int8_t VariantImpl::asInt8() const return int8_t(value.ui16); break; case VAR_UINT32: - if (value.ui32 <= (uint32_t) std::numeric_limits<int8_t>::max()) + if (value.ui32 <= (uint) std::numeric_limits<int8_t>::max()) return int8_t(value.ui32); break; case VAR_UINT64: - if (value.ui64 <= (uint64_t) std::numeric_limits<int8_t>::max()) + if (value.ui64 <= (uint) std::numeric_limits<int8_t>::max()) return int8_t(value.ui64); break; case VAR_STRING: return convertFromString<int8_t>(); @@ -412,11 +401,11 @@ int16_t VariantImpl::asInt16() const return int16_t(value.ui16); break; case VAR_UINT32: - if (value.ui32 <= (uint32_t) std::numeric_limits<int16_t>::max()) + if (value.ui32 <= (uint) std::numeric_limits<int16_t>::max()) return int16_t(value.ui32); break; case VAR_UINT64: - if (value.ui64 <= (uint64_t) std::numeric_limits<int16_t>::max()) + if (value.ui64 <= (uint) std::numeric_limits<int16_t>::max()) return int16_t(value.ui64); break; case VAR_STRING: return convertFromString<int16_t>(); @@ -441,7 +430,7 @@ int32_t VariantImpl::asInt32() const return int32_t(value.ui32); break; case VAR_UINT64: - if (value.ui64 <= (uint64_t) std::numeric_limits<int32_t>::max()) + if (value.ui64 <= (uint32_t) std::numeric_limits<int32_t>::max()) return int32_t(value.ui64); break; case VAR_STRING: return convertFromString<int32_t>(); @@ -593,7 +582,7 @@ const std::string& VariantImpl::getString() const void VariantImpl::setEncoding(const std::string& s) { encoding = s; } const std::string& VariantImpl::getEncoding() const { return encoding; } -std::string getTypeName(VariantType type) +std::string VariantImpl::getTypeName(VariantType type) const { switch (type) { case VAR_VOID: return "void"; |